The Battle for Wesnoth  1.19.2+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_window()->get_need_layout() && !linked_group_.empty()) {
202  point linked_size = get_window()->get_linked_size(linked_group_);
203  result.x = std::max(result.x, linked_size.x);
204  result.y = std::max(result.y, linked_size.y);
205  }
206  }
207 
208 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
209  last_best_size_ = result;
210 #endif
211 
212  return result;
213 }
214 
215 bool widget::can_wrap() const
216 {
217  return false;
218 }
219 
220 void widget::set_origin(const point& origin)
221 {
222  x_ = origin.x;
223  y_ = origin.y;
224 }
225 
227 {
228  assert(size.x >= 0);
229  assert(size.y >= 0);
230 
231  queue_redraw();
232  width_ = size.x;
233  height_ = size.y;
234 
235  queue_redraw();
236 }
237 
238 void widget::place(const point& origin, const point& size)
239 {
240  assert(size.x >= 0);
241  assert(size.y >= 0);
242 
243  queue_redraw();
244  x_ = origin.x;
245  y_ = origin.y;
246  width_ = size.x;
247  height_ = size.y;
248 
249 #if 0
250  PLAIN_LOG
251  << "Id " << id()
252  << " rect " << get_rectangle()
253  << " parent "
254  << (parent ? parent->get_x() : 0)
255  << ','
256  << (parent ? parent->get_y() : 0)
257  << " screen origin " << x_ << ',' << y_
258  << ".\n";
259 #endif
260 
261  queue_redraw();
262 }
263 
264 void widget::move(const int x_offset, const int y_offset)
265 {
266  x_ += x_offset;
267  y_ += y_offset;
268 }
269 
270 void widget::set_horizontal_alignment(const std::string& alignment)
271 {
272  grid* parent_grid = get_parent_grid();
273  if(!parent_grid) {
274  return;
275  }
276 
278 
279  // TODO: evaluate necessity
280  //get_window()->invalidate_layout();
281 }
282 
283 void widget::set_vertical_alignment(const std::string& alignment)
284 {
285  grid* parent_grid = get_parent_grid();
286  if(!parent_grid) {
287  return;
288  }
289 
291 
292  // TODO: evaluate necessity
293  //get_window()->invalidate_layout();
294 }
295 
297 {
298  /* DO NOTHING */
299 }
300 
302 {
303  return point(x_, y_);
304 }
305 
307 {
308  return point(width_, height_);
309 }
310 
312 {
313  return {get_origin(), get_size()};
314 }
315 
316 int widget::get_x() const
317 {
318  return x_;
319 }
320 
321 int widget::get_y() const
322 {
323  return y_;
324 }
325 
326 unsigned widget::get_width() const
327 {
328  return width_;
329 }
330 
331 unsigned widget::get_height() const
332 {
333  return height_;
334 }
335 
337 {
338  layout_size_ = size;
339 }
340 
342 {
343  return layout_size_;
344 }
345 
346 void widget::set_linked_group(const std::string& linked_group)
347 {
348  linked_group_ = linked_group;
349 }
350 
351 /***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/
352 
354 {
355  return get_rectangle();
356 }
357 
359 {
360  switch(get_drawing_action()) {
361  case redraw_action::none:
362  return sdl::empty_rect;
364  return clipping_rectangle_;
365  case redraw_action::full:
366  default:
367  return get_rectangle();
368  }
369 }
370 
372 {
373  assert(visible_ == visibility::visible);
374 
376  return true;
377  }
378 
379  // Set viewport and clip so we can draw in local coordinates.
382  // Presumably we are drawing to our window's render buffer.
383  point window_origin = get_window()->get_origin();
384  dest.shift(-window_origin);
385  auto view_setter = draw::set_viewport(dest);
386  clip.shift(-get_origin());
387  auto clip_setter = draw::reduce_clip(clip);
388 
389  return impl_draw_background();
390 }
391 
393 {
394  assert(visible_ == visibility::visible);
395 
397  return;
398  }
399 
400  // Set viewport and clip so we can draw in local coordinates.
403  // Presumably we are drawing to our window's render buffer.
404  point window_origin = get_window()->get_origin();
405  dest.shift(-window_origin);
406  auto view_setter = draw::set_viewport(dest);
407  clip.shift(-get_origin());
408  auto clip_setter = draw::reduce_clip(clip);
409 
411 }
412 
414 {
415  assert(visible_ == visibility::visible);
416 
418  return true;
419  }
420 
421  // Set viewport and clip so we can draw in local coordinates.
424  // Presumably we are drawing to our window's render buffer.
425  point window_origin = get_window()->get_origin();
426  dest.shift(-window_origin);
427  auto view_setter = draw::set_viewport(dest);
428  clip.shift(-get_origin());
429  auto clip_setter = draw::reduce_clip(clip);
430 
432  return impl_draw_foreground();
433 }
434 
436 {
439 }
440 
441 void widget::set_visible_rectangle(const SDL_Rect& rectangle)
442 {
444 
447  } else if(clipping_rectangle_.empty()) {
449  } else {
451  }
452 }
453 
455 {
456  if (!width_ && !height_) {
457  // Do nothing if the widget hasn't yet been placed.
458  return;
459  }
461 }
462 
463 void widget::queue_redraw(const rect& region)
464 {
465  get_window()->queue_rerender(region);
467 }
468 
469 void widget::set_visible(const visibility visible)
470 {
471  if(visible == visible_) {
472  return;
473  }
474 
475  // Switching to or from invisible should invalidate the layout
476  // if the widget has already been laid out.
477  const bool need_resize = visible_ == visibility::invisible
478  || (visible == visibility::invisible && get_size() != point());
479  visible_ = visible;
480 
481  if(need_resize) {
482  if(visible == visibility::visible && new_widgets) {
485  } else {
486  window* window = get_window();
487  if(window) {
489  }
490  }
491  } else {
492  queue_redraw();
493  }
494 }
495 
497 {
498  return visible_;
499 }
500 
502 {
503  return (width_ == 0 || height_ == 0) ? redraw_action::none
504  : redraw_action_;
505 }
506 
507 void widget::set_debug_border_mode(const debug_border debug_border_mode)
508 {
509  debug_border_mode_ = debug_border_mode;
510 }
511 
512 void widget::set_debug_border_color(const color_t debug_border_color)
513 {
514  debug_border_color_ = debug_border_color;
515 }
516 
518 {
519  switch(debug_border_mode_) {
520  case debug_border::none:
521  /* DO NOTHING */
522  break;
523 
526  break;
527 
528  case debug_border::fill:
530  break;
531 
532  default:
533  assert(false);
534  }
535 }
536 
537 /***** ***** ***** ***** Query functions ***** ***** ***** *****/
538 
539 widget* widget::find_at(const point& coordinate, const bool must_be_active)
540 {
541  return is_at(coordinate, must_be_active) ? this : nullptr;
542 }
543 
545  const bool must_be_active) const
546 {
547  return is_at(coordinate, must_be_active) ? this : nullptr;
548 }
549 
550 widget* widget::find(const std::string& id, const bool /*must_be_active*/)
551 {
552  return id_ == id ? this : nullptr;
553 }
554 
555 const widget* widget::find(const std::string& id,
556  const bool /*must_be_active*/) const
557 {
558  return id_ == id ? this : nullptr;
559 }
560 
561 bool widget::has_widget(const widget& widget) const
562 {
563  return &widget == this;
564 }
565 
566 bool widget::is_at(const point& coordinate) const
567 {
568  return is_at(coordinate, true);
569 }
570 
571 bool widget::recursive_is_visible(const widget* widget, const bool must_be_active) const
572 {
573  while(widget) {
575  || (widget->visible_ == visibility::hidden && must_be_active)) {
576  return false;
577  }
578 
579  widget = widget->parent_;
580  }
581 
582  return true;
583 }
584 
585 bool widget::is_at(const point& coordinate, const bool must_be_active) const
586 {
587  if(!recursive_is_visible(this, must_be_active)) {
588  return false;
589  }
590 
592 }
593 
594 } // 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:53
const point & layout_size() const
Definition: widget.cpp:341
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:336
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:413
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:238
debug_border debug_border_mode_
Mode for drawing the debug border.
Definition: widget.hpp:652
void set_visible(const visibility visible)
Definition: widget.cpp:469
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:296
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:435
void set_linked_group(const std::string &linked_group)
Definition: widget.cpp:346
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:454
widget * parent_
The parent widget.
Definition: widget.hpp:214
visibility get_visible() const
Definition: widget.cpp:496
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:301
color_t debug_border_color_
The color for the debug border.
Definition: widget.hpp:655
int get_x() const
Definition: widget.cpp:316
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:550
unsigned width_
The width of the widget.
Definition: widget.hpp:471
unsigned get_width() const
Definition: widget.cpp:326
int get_y() const
Definition: widget.cpp:321
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:306
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:392
virtual void move(const int x_offset, const int y_offset)
Moves a widget.
Definition: widget.cpp:264
bool draw_background()
Draws the background of a widget.
Definition: widget.cpp:371
virtual bool has_widget(const widget &widget) const
Does the widget contain the widget.
Definition: widget.cpp:561
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:220
unsigned get_height() const
Definition: widget.cpp:331
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:571
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:270
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:353
SDL_Rect calculate_clipping_rectangle() const
Calculates the clipping rectangle of the widget.
Definition: widget.cpp:358
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:507
redraw_action get_drawing_action() const
Definition: widget.cpp:501
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:311
virtual void impl_draw_children()
See draw_children.
Definition: widget.hpp:576
void draw_debug_border()
Definition: widget.cpp:517
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:539
void set_debug_border_color(const color_t debug_border_color)
Definition: widget.cpp:512
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:226
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:215
virtual bool is_at(const point &coordinate) const override
See event::dispatcher::is_at.
Definition: widget.cpp:566
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:441
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:283
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:773
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
Definition: window.cpp:816
point get_linked_size(const std::string &linked_group_id) const
Definition: window.hpp:429
void remove_linked_widget(const std::string &id, const widget *widget)
Removes a widget from a linked size group.
Definition: window.cpp:830
void queue_rerender(const rect &region)
Queue a rerender of the internal render buffer.
Definition: window.cpp:694
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:205
This file contains the window object, this object is a top level container which has the event manage...
#define PLAIN_LOG
Definition: log.hpp:298
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: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