The Battle for Wesnoth  1.19.0-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  parent_ = parent;
158 }
159 
161 {
162  return parent_;
163 }
164 
165 /***** ***** ***** ***** Size and layout functions. ***** ***** ***** *****/
166 
167 void widget::layout_initialize(const bool /*full_initialization*/)
168 {
169  assert(visible_ != visibility::invisible);
170  assert(get_window());
171 
172  layout_size_ = point();
173  if(!linked_group_.empty()) {
175  }
176 }
177 
178 void widget::demand_reduce_width(const unsigned /*maximum_width*/)
179 {
180  /* DO NOTHING */
181 }
182 
183 void widget::request_reduce_height(const unsigned /*maximum_height*/)
184 {
185  /* DO NOTHING */
186 }
187 
188 void widget::demand_reduce_height(const unsigned /*maximum_height*/)
189 {
190  /* DO NOTHING */
191 }
192 
194 {
195  assert(visible_ != visibility::invisible);
196 
197  point result = layout_size_;
198  if(result == point()) {
199  result = calculate_best_size();
200  //Adjust to linked widget size if linked widget size was already calculated.
201  if(!get_window()->get_need_layout() && !linked_group_.empty())
202  {
203  point linked_size = get_window()->get_linked_size(linked_group_);
204  result.x = std::max(result.x, linked_size.x);
205  result.y = std::max(result.y, linked_size.y);
206  }
207  }
208 
209 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
210  last_best_size_ = result;
211 #endif
212 
213  return result;
214 }
215 
216 bool widget::can_wrap() const
217 {
218  return false;
219 }
220 
221 void widget::set_origin(const point& origin)
222 {
223  x_ = origin.x;
224  y_ = origin.y;
225 }
226 
228 {
229  assert(size.x >= 0);
230  assert(size.y >= 0);
231 
232  queue_redraw();
233  width_ = size.x;
234  height_ = size.y;
235 
236  queue_redraw();
237 }
238 
239 void widget::place(const point& origin, const point& size)
240 {
241  assert(size.x >= 0);
242  assert(size.y >= 0);
243 
244  queue_redraw();
245  x_ = origin.x;
246  y_ = origin.y;
247  width_ = size.x;
248  height_ = size.y;
249 
250 #if 0
251  PLAIN_LOG
252  << "Id " << id()
253  << " rect " << get_rectangle()
254  << " parent "
255  << (parent ? parent->get_x() : 0)
256  << ','
257  << (parent ? parent->get_y() : 0)
258  << " screen origin " << x_ << ',' << y_
259  << ".\n";
260 #endif
261 
262  queue_redraw();
263 }
264 
265 void widget::move(const int x_offset, const int y_offset)
266 {
267  x_ += x_offset;
268  y_ += y_offset;
269 }
270 
271 void widget::set_horizontal_alignment(const std::string& alignment)
272 {
273  grid* parent_grid = get_parent_grid();
274  if(!parent_grid) {
275  return;
276  }
277 
279 
280  // TODO: evaluate necessity
281  //get_window()->invalidate_layout();
282 }
283 
284 void widget::set_vertical_alignment(const std::string& alignment)
285 {
286  grid* parent_grid = get_parent_grid();
287  if(!parent_grid) {
288  return;
289  }
290 
292 
293  // TODO: evaluate necessity
294  //get_window()->invalidate_layout();
295 }
296 
298 {
299  /* DO NOTHING */
300 }
301 
303 {
304  return point(x_, y_);
305 }
306 
308 {
309  return point(width_, height_);
310 }
311 
313 {
314  return {get_origin(), get_size()};
315 }
316 
317 int widget::get_x() const
318 {
319  return x_;
320 }
321 
322 int widget::get_y() const
323 {
324  return y_;
325 }
326 
327 unsigned widget::get_width() const
328 {
329  return width_;
330 }
331 
332 unsigned widget::get_height() const
333 {
334  return height_;
335 }
336 
338 {
339  layout_size_ = size;
340 }
341 
343 {
344  return layout_size_;
345 }
346 
347 void widget::set_linked_group(const std::string& linked_group)
348 {
349  linked_group_ = linked_group;
350 }
351 
352 /***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/
353 
355 {
356  return get_rectangle();
357 }
358 
360 {
361  switch(get_drawing_action()) {
362  case redraw_action::none:
363  return sdl::empty_rect;
365  return clipping_rectangle_;
366  case redraw_action::full:
367  default:
368  return get_rectangle();
369  }
370 }
371 
373 {
374  assert(visible_ == visibility::visible);
375 
377  return true;
378  }
379 
380  // Set viewport and clip so we can draw in local coordinates.
383  // Presumably we are drawing to our window's render buffer.
384  point window_origin = get_window()->get_origin();
385  dest.shift(-window_origin);
386  auto view_setter = draw::set_viewport(dest);
387  clip.shift(-get_origin());
388  auto clip_setter = draw::reduce_clip(clip);
389 
391  return impl_draw_background();
392 }
393 
395 {
396  assert(visible_ == visibility::visible);
397 
399  return;
400  }
401 
402  // Set viewport and clip so we can draw in local coordinates.
405  // Presumably we are drawing to our window's render buffer.
406  point window_origin = get_window()->get_origin();
407  dest.shift(-window_origin);
408  auto view_setter = draw::set_viewport(dest);
409  clip.shift(-get_origin());
410  auto clip_setter = draw::reduce_clip(clip);
411 
413 }
414 
416 {
417  assert(visible_ == visibility::visible);
418 
420  return true;
421  }
422 
423  // Set viewport and clip so we can draw in local coordinates.
426  // Presumably we are drawing to our window's render buffer.
427  point window_origin = get_window()->get_origin();
428  dest.shift(-window_origin);
429  auto view_setter = draw::set_viewport(dest);
430  clip.shift(-get_origin());
431  auto clip_setter = draw::reduce_clip(clip);
432 
433  return impl_draw_foreground();
434 }
435 
437 {
440 }
441 
442 void widget::set_visible_rectangle(const SDL_Rect& rectangle)
443 {
445 
448  } else if(clipping_rectangle_.empty()) {
450  } else {
452  }
453 }
454 
456 {
457  if (!width_ && !height_) {
458  // Do nothing if the widget hasn't yet been placed.
459  return;
460  }
462 }
463 
464 void widget::queue_redraw(const rect& region)
465 {
466  get_window()->queue_rerender(region);
468 }
469 
470 void widget::set_visible(const visibility visible)
471 {
472  if(visible == visible_) {
473  return;
474  }
475 
476  // Switching to or from invisible should invalidate the layout
477  // if the widget has already been laid out.
478  const bool need_resize = visible_ == visibility::invisible
479  || (visible == visibility::invisible && get_size() != point());
480  visible_ = visible;
481 
482  if(need_resize) {
483  if(visible == visibility::visible && new_widgets) {
486  } else {
487  window* window = get_window();
488  if(window) {
490  }
491  }
492  } else {
493  queue_redraw();
494  }
495 }
496 
498 {
499  return visible_;
500 }
501 
503 {
504  return (width_ == 0 || height_ == 0) ? redraw_action::none
505  : redraw_action_;
506 }
507 
508 void widget::set_debug_border_mode(const debug_border debug_border_mode)
509 {
510  debug_border_mode_ = debug_border_mode;
511 }
512 
513 void widget::set_debug_border_color(const color_t debug_border_color)
514 {
515  debug_border_color_ = debug_border_color;
516 }
517 
519 {
520  SDL_Rect r = redraw_action_ == redraw_action::partly
523 
524  switch(debug_border_mode_) {
525  case debug_border::none:
526  /* DO NOTHING */
527  break;
528 
531  break;
532 
533  case debug_border::fill:
535  break;
536 
537  default:
538  assert(false);
539  }
540 }
541 
542 /***** ***** ***** ***** Query functions ***** ***** ***** *****/
543 
544 widget* widget::find_at(const point& coordinate, const bool must_be_active)
545 {
546  return is_at(coordinate, must_be_active) ? this : nullptr;
547 }
548 
550  const bool must_be_active) const
551 {
552  return is_at(coordinate, must_be_active) ? this : nullptr;
553 }
554 
555 widget* widget::find(const std::string& id, const bool /*must_be_active*/)
556 {
557  return id_ == id ? this : nullptr;
558 }
559 
560 const widget* widget::find(const std::string& id,
561  const bool /*must_be_active*/) const
562 {
563  return id_ == id ? this : nullptr;
564 }
565 
566 bool widget::has_widget(const widget& widget) const
567 {
568  return &widget == this;
569 }
570 
571 bool widget::is_at(const point& coordinate) const
572 {
573  return is_at(coordinate, true);
574 }
575 
576 bool widget::recursive_is_visible(const widget* widget, const bool must_be_active) const
577 {
578  while(widget) {
580  || (widget->visible_ == visibility::hidden && must_be_active)) {
581  return false;
582  }
583 
584  widget = widget->parent_;
585  }
586 
587  return true;
588 }
589 
590 bool widget::is_at(const point& coordinate, const bool must_be_active) const
591 {
592  if(!recursive_is_visible(this, must_be_active)) {
593  return false;
594  }
595 
597 }
598 
599 } // 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
Base class for all visible items.
virtual const std::string & get_control_type() const =0
Returns the type of this styled_widget.
Base class for all widgets.
Definition: widget.hpp:53
const point & layout_size() const
Definition: widget.cpp:342
virtual void demand_reduce_width(const unsigned maximum_width)
Tries to reduce the width of a widget.
Definition: widget.cpp:178
void set_layout_size(const point &size)
Definition: widget.cpp:337
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:641
bool draw_foreground()
Draws the foreground of the widget.
Definition: widget.cpp:415
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:193
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:239
debug_border debug_border_mode_
Mode for drawing the debug border.
Definition: widget.hpp:652
void set_visible(const visibility visible)
Definition: widget.cpp:470
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:465
virtual void demand_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:188
virtual void layout_children()
Allows a widget to update its children.
Definition: widget.cpp:297
visibility visible_
Field for the status of the visibility.
Definition: widget.hpp:638
virtual ~widget() override
Definition: widget.cpp:77
rect clipping_rectangle_
The clipping rectangle if a widget is partly visible.
Definition: widget.hpp:644
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:167
SDL_Rect get_dirty_rectangle() const
Gets the dirty rectangle of the widget.
Definition: widget.cpp:436
void set_linked_group(const std::string &linked_group)
Definition: widget.cpp:347
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:455
widget * parent_
The parent widget.
Definition: widget.hpp:214
visibility get_visible() const
Definition: widget.cpp:497
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:302
color_t debug_border_color_
The color for the debug border.
Definition: widget.hpp:655
int get_x() const
Definition: widget.cpp:317
virtual bool impl_draw_foreground()
See draw_foreground.
Definition: widget.hpp:581
virtual widget * find(const std::string &id, const bool must_be_active)
Returns a widget with the wanted id.
Definition: widget.cpp:555
unsigned width_
The width of the widget.
Definition: widget.hpp:471
unsigned get_width() const
Definition: widget.cpp:327
int get_y() const
Definition: widget.cpp:322
void set_parent(widget *parent)
Definition: widget.cpp:155
virtual point calculate_best_size() const =0
Calculates the best size.
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:307
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:394
virtual void move(const int x_offset, const int y_offset)
Moves a widget.
Definition: widget.cpp:265
bool draw_background()
Draws the background of a widget.
Definition: widget.cpp:372
virtual bool has_widget(const widget &widget) const
Does the widget contain the widget.
Definition: widget.cpp:566
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:221
unsigned get_height() const
Definition: widget.cpp:332
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:576
virtual bool impl_draw_background()
See draw_background.
Definition: widget.hpp:570
int y_
The y-coordinate of the widget on the screen.
Definition: widget.hpp:468
virtual void set_horizontal_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:271
std::string id_
The id is the unique name of the widget in a certain context.
Definition: widget.hpp:175
visibility
Visibility settings done by the user.
Definition: widget.hpp:63
@ 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:354
SDL_Rect calculate_clipping_rectangle() const
Calculates the clipping rectangle of the widget.
Definition: widget.cpp:359
std::string linked_group_
The linked group the widget belongs to.
Definition: widget.hpp:510
void set_debug_border_mode(const debug_border debug_border_mode)
Definition: widget.cpp:508
redraw_action get_drawing_action() const
Definition: widget.cpp:502
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:312
virtual void impl_draw_children()
See draw_children.
Definition: widget.hpp:576
void draw_debug_border()
Definition: widget.cpp:518
point layout_size_
The best size for the widget.
Definition: widget.hpp:486
@ 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:544
void set_debug_border_color(const color_t debug_border_color)
Definition: widget.cpp:513
unsigned height_
The height of the widget.
Definition: widget.hpp:474
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:227
virtual void request_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:183
virtual bool can_wrap() const
Can the widget wrap.
Definition: widget.cpp:216
virtual bool is_at(const point &coordinate) const override
See event::dispatcher::is_at.
Definition: widget.cpp:571
redraw_action
Visibility set by the engine.
Definition: widget.hpp:101
@ 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:442
widget * parent()
Definition: widget.cpp:160
virtual void set_vertical_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:284
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:63
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:767
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
Definition: window.cpp:810
point get_linked_size(const std::string &linked_group_id) const
Definition: window.hpp:431
void remove_linked_widget(const std::string &id, const widget *widget)
Removes a widget from a linked size group.
Definition: window.cpp:824
void queue_rerender(const rect &region)
Queue a rerender of the internal render buffer.
Definition: window.cpp:688
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:207
This file contains the window object, this object is a top level container which has the event manage...
#define PLAIN_LOG
Definition: log.hpp:295
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:551
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:457
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:47
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
Definition: rect.cpp:52
void shift(const point &p)
Shift the rectangle by the given relative position.
Definition: rect.cpp:104
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:90
mock_party p