The Battle for Wesnoth  1.19.5+dev
widget.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 - 2024
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
18 #include "draw.hpp"
19 #include "draw_manager.hpp"
20 #include "gui/widgets/grid.hpp"
21 #include "gui/widgets/settings.hpp"
22 #include "gui/widgets/window.hpp"
24 #include "gui/core/log.hpp"
26 #include "sdl/rect.hpp"
27 
28 namespace gui2
29 {
30 
31 /***** ***** ***** Constructor and destructor. ***** ***** *****/
32 
34  : enable_lua_ptr<widget>(this)
35  , id_("")
36  , parent_(nullptr)
37  , x_(-1)
38  , y_(-1)
39  , width_(0)
40  , height_(0)
41  , layout_size_()
42 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
43  , last_best_size_()
44 #endif
45  , linked_group_()
46  , visible_(visibility::visible)
47  , redraw_action_(redraw_action::full)
48  , clipping_rectangle_()
49  , debug_border_mode_(debug_border::none)
50  , debug_border_color_(0,0,0,0)
51 {
52  DBG_GUI_LF << "widget create: " << static_cast<void*>(this);
53 }
54 
56  : enable_lua_ptr<widget>(this)
57  , id_(builder.id)
58  , parent_(nullptr)
59  , x_(-1)
60  , y_(-1)
61  , width_(0)
62  , height_(0)
63  , layout_size_()
64 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
65  , last_best_size_()
66 #endif
67  , linked_group_(builder.linked_group)
68  , visible_(visibility::visible)
69  , redraw_action_(redraw_action::full)
70  , clipping_rectangle_()
71  , debug_border_mode_(builder.debug_border_mode)
72  , debug_border_color_(builder.debug_border_color)
73 {
74  DBG_GUI_LF << "widget create: " << static_cast<void*>(this);
75 }
76 
78 {
80  << "widget destroy: " << static_cast<void*>(this)
81  << " (id: " << id_ << ')';
82 
83  widget* p = parent();
84  while(p) {
85  fire(event::NOTIFY_REMOVAL, *p, nullptr);
86  p = p->parent();
87  }
88 
89  if(!linked_group_.empty()) {
90  if(window* window = get_window()) {
92  }
93  }
94 }
95 
96 /***** ***** ***** ***** ID functions. ***** ***** ***** *****/
97 
98 void widget::set_id(const std::string& id)
99 {
100  styled_widget* this_ctrl = dynamic_cast<styled_widget*>(this);
101 
102  DBG_GUI_LF
103  << "set id of " << static_cast<void*>(this) << " to '" << id << "' "
104  << "(was '" << id_ << "'). Widget type: "
105  << (this_ctrl ? this_ctrl->get_control_type() : typeid(widget).name());
106 
107  id_ = id;
108 }
109 
110 const std::string& widget::id() const
111 {
112  return id_;
113 }
114 
115 /***** ***** ***** ***** Parent functions ***** ***** ***** *****/
116 
118 {
119  // Go up into the parent tree until we find the top level
120  // parent, we can also be the toplevel so start with
121  // ourselves instead of our parent.
122  widget* result = this;
123  while(result->parent_) {
124  result = result->parent_;
125  }
126 
127  // on error dynamic_cast returns nullptr which is what we want.
128  return dynamic_cast<window*>(result);
129 }
130 
132 {
133  // Go up into the parent tree until we find the top level
134  // parent, we can also be the toplevel so start with
135  // ourselves instead of our parent.
136  const widget* result = this;
137  while(result->parent_) {
138  result = result->parent_;
139  }
140 
141  // on error dynamic_cast returns nullptr which is what we want.
142  return dynamic_cast<const window*>(result);
143 }
144 
146 {
147  widget* result = parent_;
148  while(result && dynamic_cast<grid*>(result) == nullptr) {
149  result = result->parent_;
150  }
151 
152  return result ? dynamic_cast<grid*>(result) : nullptr;
153 }
154 
156 {
157  const widget* result = parent_;
158  while(result && dynamic_cast<const grid*>(result) == nullptr) {
159  result = result->parent_;
160  }
161 
162  return result ? dynamic_cast<const grid*>(result) : nullptr;
163 }
164 
166 {
167  parent_ = parent;
168 }
169 
171 {
172  return parent_;
173 }
174 
175 /***** ***** ***** ***** Size and layout functions. ***** ***** ***** *****/
176 
177 void widget::layout_initialize(const bool /*full_initialization*/)
178 {
179  assert(visible_ != visibility::invisible);
180  assert(get_window());
181 
182  layout_size_ = point();
183  if(!linked_group_.empty()) {
185  }
186 }
187 
188 void widget::demand_reduce_width(const unsigned /*maximum_width*/)
189 {
190  /* DO NOTHING */
191 }
192 
193 void widget::request_reduce_height(const unsigned /*maximum_height*/)
194 {
195  /* DO NOTHING */
196 }
197 
198 void widget::demand_reduce_height(const unsigned /*maximum_height*/)
199 {
200  /* DO NOTHING */
201 }
202 
204 {
205  assert(visible_ != visibility::invisible);
206 
207  point result = layout_size_;
208  if(result == point()) {
209  result = calculate_best_size();
210  //Adjust to linked widget size if linked widget size was already calculated.
211  if (get_window() && !get_window()->get_need_layout() && !linked_group_.empty()) {
212  point linked_size = get_window()->get_linked_size(linked_group_);
213  result.x = std::max(result.x, linked_size.x);
214  result.y = std::max(result.y, linked_size.y);
215  }
216  }
217 
218 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
219  last_best_size_ = result;
220 #endif
221 
222  return result;
223 }
224 
225 bool widget::can_wrap() const
226 {
227  return false;
228 }
229 
230 void widget::set_origin(const point& origin)
231 {
232  x_ = origin.x;
233  y_ = origin.y;
234 }
235 
237 {
238  assert(size.x >= 0);
239  assert(size.y >= 0);
240 
241  queue_redraw();
242  width_ = size.x;
243  height_ = size.y;
244 
245  queue_redraw();
246 }
247 
248 void widget::place(const point& origin, const point& size)
249 {
250  assert(size.x >= 0);
251  assert(size.y >= 0);
252 
253  queue_redraw();
254  x_ = origin.x;
255  y_ = origin.y;
256  width_ = size.x;
257  height_ = size.y;
258 
259 #if 0
260  PLAIN_LOG
261  << "Id " << id()
262  << " rect " << get_rectangle()
263  << " parent "
264  << (parent ? parent->get_x() : 0)
265  << ','
266  << (parent ? parent->get_y() : 0)
267  << " screen origin " << x_ << ',' << y_
268  << ".\n";
269 #endif
270 
271  queue_redraw();
272 }
273 
274 void widget::move(const int x_offset, const int y_offset)
275 {
276  x_ += x_offset;
277  y_ += y_offset;
278 }
279 
280 void widget::set_horizontal_alignment(const std::string& alignment)
281 {
282  grid* parent_grid = get_parent_grid();
283  if(!parent_grid) {
284  return;
285  }
286 
288 
289  // TODO: evaluate necessity
290  //get_window()->invalidate_layout();
291 }
292 
293 void widget::set_vertical_alignment(const std::string& alignment)
294 {
295  grid* parent_grid = get_parent_grid();
296  if(!parent_grid) {
297  return;
298  }
299 
301 
302  // TODO: evaluate necessity
303  //get_window()->invalidate_layout();
304 }
305 
307 {
308  /* DO NOTHING */
309 }
310 
312 {
313  return point(x_, y_);
314 }
315 
317 {
318  return point(width_, height_);
319 }
320 
322 {
323  return {get_origin(), get_size()};
324 }
325 
326 int widget::get_x() const
327 {
328  return x_;
329 }
330 
331 int widget::get_y() const
332 {
333  return y_;
334 }
335 
336 unsigned widget::get_width() const
337 {
338  return width_;
339 }
340 
341 unsigned widget::get_height() const
342 {
343  return height_;
344 }
345 
347 {
348  layout_size_ = size;
349 }
350 
352 {
353  return layout_size_;
354 }
355 
356 void widget::set_linked_group(const std::string& linked_group)
357 {
358  linked_group_ = linked_group;
359 }
360 
361 /***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/
362 
364 {
365  return get_rectangle();
366 }
367 
369 {
370  switch(get_drawing_action()) {
371  case redraw_action::none:
372  return sdl::empty_rect;
374  return clipping_rectangle_;
375  case redraw_action::full:
376  default:
377  return get_rectangle();
378  }
379 }
380 
382 {
383  assert(visible_ == visibility::visible);
384 
386  return true;
387  }
388 
389  // Set viewport and clip so we can draw in local coordinates.
392  // Presumably we are drawing to our window's render buffer.
393  point window_origin = get_window()->get_origin();
394  dest.shift(-window_origin);
395  auto view_setter = draw::set_viewport(dest);
396  clip.shift(-get_origin());
397  auto clip_setter = draw::reduce_clip(clip);
398 
399  return impl_draw_background();
400 }
401 
403 {
404  assert(visible_ == visibility::visible);
405 
407  return;
408  }
409 
410  // Set viewport and clip so we can draw in local coordinates.
413  // Presumably we are drawing to our window's render buffer.
414  point window_origin = get_window()->get_origin();
415  dest.shift(-window_origin);
416  auto view_setter = draw::set_viewport(dest);
417  clip.shift(-get_origin());
418  auto clip_setter = draw::reduce_clip(clip);
419 
421 }
422 
424 {
425  assert(visible_ == visibility::visible);
426 
428  return true;
429  }
430 
431  // Set viewport and clip so we can draw in local coordinates.
434  // Presumably we are drawing to our window's render buffer.
435  point window_origin = get_window()->get_origin();
436  dest.shift(-window_origin);
437  auto view_setter = draw::set_viewport(dest);
438  clip.shift(-get_origin());
439  auto clip_setter = draw::reduce_clip(clip);
440 
442  return impl_draw_foreground();
443 }
444 
446 {
449 }
450 
451 void widget::set_visible_rectangle(const SDL_Rect& rectangle)
452 {
454 
457  } else if(clipping_rectangle_.empty()) {
459  } else {
461  }
462 }
463 
465 {
466  if (!width_ && !height_) {
467  // Do nothing if the widget hasn't yet been placed.
468  return;
469  }
471 }
472 
473 void widget::queue_redraw(const rect& region)
474 {
475  get_window()->queue_rerender(region);
477 }
478 
479 void widget::set_visible(const visibility visible)
480 {
481  if(visible == visible_) {
482  return;
483  }
484 
485  // Switching to or from invisible should invalidate the layout
486  // if the widget has already been laid out.
487  const bool need_resize = visible_ == visibility::invisible
488  || (visible == visibility::invisible && get_size() != point());
489  visible_ = visible;
490 
491  if(need_resize) {
492  if(visible == visibility::visible && new_widgets) {
495  } else {
496  window* window = get_window();
497  if(window) {
499  }
500  }
501  } else {
502  queue_redraw();
503  }
504 }
505 
507 {
508  return visible_;
509 }
510 
512 {
513  return (width_ == 0 || height_ == 0) ? redraw_action::none
514  : redraw_action_;
515 }
516 
517 void widget::set_debug_border_mode(const debug_border debug_border_mode)
518 {
519  debug_border_mode_ = debug_border_mode;
520 }
521 
522 void widget::set_debug_border_color(const color_t debug_border_color)
523 {
524  debug_border_color_ = debug_border_color;
525 }
526 
528 {
529  switch(debug_border_mode_) {
530  case debug_border::none:
531  /* DO NOTHING */
532  break;
533 
536  break;
537 
538  case debug_border::fill:
540  break;
541 
542  default:
543  assert(false);
544  }
545 }
546 
547 /***** ***** ***** ***** Query functions ***** ***** ***** *****/
548 
549 widget* widget::find_at(const point& coordinate, const bool must_be_active)
550 {
551  return is_at(coordinate, must_be_active) ? this : nullptr;
552 }
553 
555  const bool must_be_active) const
556 {
557  return is_at(coordinate, must_be_active) ? this : nullptr;
558 }
559 
560 widget* widget::find(const std::string& id, const bool /*must_be_active*/)
561 {
562  return id_ == id ? this : nullptr;
563 }
564 
565 const widget* widget::find(const std::string& id,
566  const bool /*must_be_active*/) const
567 {
568  return id_ == id ? this : nullptr;
569 }
570 
571 bool widget::has_widget(const widget& widget) const
572 {
573  return &widget == this;
574 }
575 
576 bool widget::is_at(const point& coordinate) const
577 {
578  return is_at(coordinate, true);
579 }
580 
581 bool widget::recursive_is_visible(const widget* widget, const bool must_be_active) const
582 {
583  while(widget) {
585  || (widget->visible_ == visibility::hidden && must_be_active)) {
586  return false;
587  }
588 
589  widget = widget->parent_;
590  }
591 
592  return true;
593 }
594 
595 bool widget::is_at(const point& coordinate, const bool must_be_active) const
596 {
597  if(!recursive_is_visible(this, must_be_active)) {
598  return false;
599  }
600 
602 }
603 
604 } // namespace gui2
Main class to show messages to the user.
Definition: message.hpp:36
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:74
Base container class.
Definition: grid.hpp:32
static const unsigned HORIZONTAL_MASK
Definition: grid.hpp:60
void set_child_alignment(widget *widget, unsigned set_flag, unsigned mode_mask)
Modifies the widget alignment data of a child cell containing a specific widget.
Definition: grid.cpp:932
static const unsigned VERTICAL_MASK
Definition: grid.hpp:53
virtual const std::string & get_control_type() const =0
Returns the type of this styled_widget.
Base class for all widgets.
Definition: widget.hpp:55
const point & layout_size() const
Definition: widget.cpp:351
virtual void demand_reduce_width(const unsigned maximum_width)
Tries to reduce the width of a widget.
Definition: widget.cpp:188
void set_layout_size(const point &size)
Definition: widget.cpp:346
grid * get_parent_grid()
Get the parent grid.
Definition: widget.cpp:145
redraw_action redraw_action_
Field for the action to do on a drawing request.
Definition: widget.hpp:644
bool draw_foreground()
Draws the foreground of the widget.
Definition: widget.cpp:423
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:203
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:248
debug_border debug_border_mode_
Mode for drawing the debug border.
Definition: widget.hpp:655
void set_visible(const visibility visible)
Definition: widget.cpp:479
void set_id(const std::string &id)
Definition: widget.cpp:98
int x_
The x-coordinate of the widget on the screen.
Definition: widget.hpp:468
virtual void demand_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:198
virtual void layout_children()
Allows a widget to update its children.
Definition: widget.cpp:306
visibility visible_
Field for the status of the visibility.
Definition: widget.hpp:641
virtual ~widget() override
Definition: widget.cpp:77
rect clipping_rectangle_
The clipping rectangle if a widget is partly visible.
Definition: widget.hpp:647
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:177
SDL_Rect get_dirty_rectangle() const
Gets the dirty rectangle of the widget.
Definition: widget.cpp:445
void set_linked_group(const std::string &linked_group)
Definition: widget.cpp:356
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:464
widget * parent_
The parent widget.
Definition: widget.hpp:217
visibility get_visible() const
Definition: widget.cpp:506
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:311
color_t debug_border_color_
The color for the debug border.
Definition: widget.hpp:658
int get_x() const
Definition: widget.cpp:326
virtual bool impl_draw_foreground()
See draw_foreground.
Definition: widget.hpp:584
virtual widget * find(const std::string &id, const bool must_be_active)
Returns a widget with the wanted id.
Definition: widget.cpp:560
unsigned width_
The width of the widget.
Definition: widget.hpp:474
unsigned get_width() const
Definition: widget.cpp:336
int get_y() const
Definition: widget.cpp:331
void set_parent(widget *parent)
Definition: widget.cpp:165
virtual point calculate_best_size() const =0
Calculates the best size.
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:316
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:402
virtual void move(const int x_offset, const int y_offset)
Moves a widget.
Definition: widget.cpp:274
bool draw_background()
Draws the background of a widget.
Definition: widget.cpp:381
virtual bool has_widget(const widget &widget) const
Does the widget contain the widget.
Definition: widget.cpp:571
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:230
unsigned get_height() const
Definition: widget.cpp:341
const std::string & id() const
Definition: widget.cpp:110
window * get_window()
Get the parent window.
Definition: widget.cpp:117
bool recursive_is_visible(const widget *widget, const bool must_be_active) const
Is the widget and every single one of its parents visible?
Definition: widget.cpp:581
virtual bool impl_draw_background()
See draw_background.
Definition: widget.hpp:573
int y_
The y-coordinate of the widget on the screen.
Definition: widget.hpp:471
virtual void set_horizontal_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:280
std::string id_
The id is the unique name of the widget in a certain context.
Definition: widget.hpp:177
visibility
Visibility settings done by the user.
Definition: widget.hpp:65
@ visible
The user sets the widget visible, that means:
@ invisible
The user set the widget invisible, that means:
@ hidden
The user sets the widget hidden, that means:
SDL_Rect calculate_blitting_rectangle() const
Calculates the blitting rectangle of the widget.
Definition: widget.cpp:363
SDL_Rect calculate_clipping_rectangle() const
Calculates the clipping rectangle of the widget.
Definition: widget.cpp:368
std::string linked_group_
The linked group the widget belongs to.
Definition: widget.hpp:513
void set_debug_border_mode(const debug_border debug_border_mode)
Definition: widget.cpp:517
redraw_action get_drawing_action() const
Definition: widget.cpp:511
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:321
virtual void impl_draw_children()
See draw_children.
Definition: widget.hpp:579
void draw_debug_border()
Definition: widget.cpp:527
point layout_size_
The best size for the widget.
Definition: widget.hpp:489
@ outline
Single-pixel outline.
@ fill
Flood-filled rectangle.
virtual widget * find_at(const point &coordinate, const bool must_be_active)
Returns the widget at the wanted coordinates.
Definition: widget.cpp:549
void set_debug_border_color(const color_t debug_border_color)
Definition: widget.cpp:522
unsigned height_
The height of the widget.
Definition: widget.hpp:477
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:236
virtual void request_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:193
virtual bool can_wrap() const
Can the widget wrap.
Definition: widget.cpp:225
virtual bool is_at(const point &coordinate) const override
See event::dispatcher::is_at.
Definition: widget.cpp:576
redraw_action
Visibility set by the engine.
Definition: widget.hpp:103
@ none
The widget is not visible.
@ partly
The widget is partly visible.
@ full
The widget is fully visible.
virtual void set_visible_rectangle(const SDL_Rect &rectangle)
Sets the visible rectangle for a widget.
Definition: widget.cpp:451
widget * parent()
Definition: widget.cpp:170
virtual void set_vertical_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:293
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:61
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:761
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
Definition: window.cpp:804
point get_linked_size(const std::string &linked_group_id) const
Definition: window.hpp:427
void remove_linked_widget(const std::string &id, const widget *widget)
Removes a widget from a linked size group.
Definition: window.cpp:818
void queue_rerender(const rect &region)
Queue a rerender of the internal render buffer.
Definition: window.cpp:682
This file contains the definitions for the gui2::event::message class.
Drawing functions, for drawing things on the screen.
Define the common log macros for the gui toolkit.
#define DBG_GUI_LF
Definition: log.hpp:62
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:198
This file contains the window object, this object is a top level container which has the event manage...
#define PLAIN_LOG
Definition: log.hpp:299
void invalidate_region(const rect &region)
Mark a region of the screen as requiring redraw.
viewport_setter set_viewport(const SDL_Rect &viewport)
Set the viewport.
Definition: draw.cpp:596
clip_setter reduce_clip(const SDL_Rect &clip)
Set the clipping area to the intersection of the current clipping area and the given rectangle.
Definition: draw.cpp:502
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:50
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:202
void rect(const SDL_Rect &rect)
Draw a rectangle.
Definition: draw.cpp:150
@ NOTIFY_REMOVAL
Definition: handler.hpp:157
@ REQUEST_PLACEMENT
Definition: handler.hpp:163
unsigned get_v_align(const std::string &v_align)
Returns the vertical alignment.
Definition: helper.cpp:38
unsigned get_h_align(const std::string &h_align)
Returns the horizontal alignment.
Definition: helper.cpp:53
Generic file dialog.
bool new_widgets
Do we wish to use the new library or not.
Definition: settings.cpp:23
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:30
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
Contains the SDL_Rect helper code.
This file contains the settings handling of the widget library.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
Contains the info needed to instantiate a widget.
The message callbacks hold a reference to a message.
Definition: message.hpp:46
Holds a 2D point.
Definition: point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:47
bool empty() const
False if both w and h are > 0, true otherwise.
Definition: rect.cpp:48
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
Definition: rect.cpp:53
void shift(const point &p)
Shift the rectangle by the given relative position.
Definition: rect.cpp:105
rect intersect(const SDL_Rect &r) const
Calculates the intersection of this rectangle and another; that is, the maximal rectangle that is con...
Definition: rect.cpp:91
mock_party p