The Battle for Wesnoth  1.17.23+dev
widget.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 - 2023
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 #include "video.hpp"
28 
29 namespace gui2
30 {
31 
32 /***** ***** ***** Constructor and destructor. ***** ***** *****/
33 
35  : enable_lua_ptr<widget>(this)
36  , id_("")
37  , parent_(nullptr)
38  , x_(-1)
39  , y_(-1)
40  , width_(0)
41  , height_(0)
42  , layout_size_()
43 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
44  , last_best_size_()
45 #endif
46  , linked_group_()
47  , visible_(visibility::visible)
48  , redraw_action_(redraw_action::full)
49  , clipping_rectangle_()
50  , debug_border_mode_(debug_border::none)
51  , debug_border_color_(0,0,0,0)
52 {
53  DBG_GUI_LF << "widget create: " << static_cast<void*>(this);
54 }
55 
57  : enable_lua_ptr<widget>(this)
58  , id_(builder.id)
59  , parent_(nullptr)
60  , x_(-1)
61  , y_(-1)
62  , width_(0)
63  , height_(0)
64  , layout_size_()
65 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
66  , last_best_size_()
67 #endif
68  , linked_group_(builder.linked_group)
69  , visible_(visibility::visible)
70  , redraw_action_(redraw_action::full)
71  , clipping_rectangle_()
72  , debug_border_mode_(builder.debug_border_mode)
73  , debug_border_color_(builder.debug_border_color)
74 {
75  DBG_GUI_LF << "widget create: " << static_cast<void*>(this);
76 }
77 
79 {
81  << "widget destroy: " << static_cast<void*>(this)
82  << " (id: " << id_ << ')';
83 
84  widget* p = parent();
85  while(p) {
86  fire(event::NOTIFY_REMOVAL, *p, nullptr);
87  p = p->parent();
88  }
89 
90  if(!linked_group_.empty()) {
91  if(window* window = get_window()) {
93  }
94  }
95 }
96 
97 /***** ***** ***** ***** ID functions. ***** ***** ***** *****/
98 
99 void widget::set_id(const std::string& id)
100 {
101  styled_widget* this_ctrl = dynamic_cast<styled_widget*>(this);
102 
103  DBG_GUI_LF
104  << "set id of " << static_cast<void*>(this) << " to '" << id << "' "
105  << "(was '" << id_ << "'). Widget type: "
106  << (this_ctrl ? this_ctrl->get_control_type() : typeid(widget).name());
107 
108  id_ = id;
109 }
110 
111 const std::string& widget::id() const
112 {
113  return id_;
114 }
115 
116 /***** ***** ***** ***** Parent functions ***** ***** ***** *****/
117 
119 {
120  // Go up into the parent tree until we find the top level
121  // parent, we can also be the toplevel so start with
122  // ourselves instead of our parent.
123  widget* result = this;
124  while(result->parent_) {
125  result = result->parent_;
126  }
127 
128  // on error dynamic_cast returns nullptr which is what we want.
129  return dynamic_cast<window*>(result);
130 }
131 
133 {
134  // Go up into the parent tree until we find the top level
135  // parent, we can also be the toplevel so start with
136  // ourselves instead of our parent.
137  const widget* result = this;
138  while(result->parent_) {
139  result = result->parent_;
140  }
141 
142  // on error dynamic_cast returns nullptr which is what we want.
143  return dynamic_cast<const window*>(result);
144 }
145 
147 {
148  widget* result = parent_;
149  while(result && dynamic_cast<grid*>(result) == nullptr) {
150  result = result->parent_;
151  }
152 
153  return result ? dynamic_cast<grid*>(result) : nullptr;
154 }
155 
157 {
158  parent_ = parent;
159 }
160 
162 {
163  return parent_;
164 }
165 
166 /***** ***** ***** ***** Size and layout functions. ***** ***** ***** *****/
167 
168 void widget::layout_initialize(const bool /*full_initialization*/)
169 {
170  assert(visible_ != visibility::invisible);
171  assert(get_window());
172 
173  layout_size_ = point();
174  if(!linked_group_.empty()) {
176  }
177 }
178 
179 void widget::demand_reduce_width(const unsigned /*maximum_width*/)
180 {
181  /* DO NOTHING */
182 }
183 
184 void widget::request_reduce_height(const unsigned /*maximum_height*/)
185 {
186  /* DO NOTHING */
187 }
188 
189 void widget::demand_reduce_height(const unsigned /*maximum_height*/)
190 {
191  /* DO NOTHING */
192 }
193 
195 {
196  assert(visible_ != visibility::invisible);
197 
198  point result = layout_size_;
199  if(result == point()) {
200  result = calculate_best_size();
201  //Adjust to linked widget size if linked widget size was already calculated.
202  if(!get_window()->get_need_layout() && !linked_group_.empty())
203  {
204  point linked_size = get_window()->get_linked_size(linked_group_);
205  result.x = std::max(result.x, linked_size.x);
206  result.y = std::max(result.y, linked_size.y);
207  }
208  }
209 
210 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
211  last_best_size_ = result;
212 #endif
213 
214  return result;
215 }
216 
217 bool widget::can_wrap() const
218 {
219  return false;
220 }
221 
222 void widget::set_origin(const point& origin)
223 {
224  x_ = origin.x;
225  y_ = origin.y;
226 }
227 
229 {
230  assert(size.x >= 0);
231  assert(size.y >= 0);
232 
233  queue_redraw();
234  width_ = size.x;
235  height_ = size.y;
236 
237  queue_redraw();
238 }
239 
240 void widget::place(const point& origin, const point& size)
241 {
242  assert(size.x >= 0);
243  assert(size.y >= 0);
244 
245  queue_redraw();
246  x_ = origin.x;
247  y_ = origin.y;
248  width_ = size.x;
249  height_ = size.y;
250 
251 #if 0
252  PLAIN_LOG
253  << "Id " << id()
254  << " rect " << get_rectangle()
255  << " parent "
256  << (parent ? parent->get_x() : 0)
257  << ','
258  << (parent ? parent->get_y() : 0)
259  << " screen origin " << x_ << ',' << y_
260  << ".\n";
261 #endif
262 
263  queue_redraw();
264 }
265 
266 void widget::move(const int x_offset, const int y_offset)
267 {
268  x_ += x_offset;
269  y_ += y_offset;
270 }
271 
272 void widget::set_horizontal_alignment(const std::string& alignment)
273 {
274  grid* parent_grid = get_parent_grid();
275  if(!parent_grid) {
276  return;
277  }
278 
280 
281  // TODO: evaluate necessity
282  //get_window()->invalidate_layout();
283 }
284 
285 void widget::set_vertical_alignment(const std::string& alignment)
286 {
287  grid* parent_grid = get_parent_grid();
288  if(!parent_grid) {
289  return;
290  }
291 
293 
294  // TODO: evaluate necessity
295  //get_window()->invalidate_layout();
296 }
297 
299 {
300  /* DO NOTHING */
301 }
302 
304 {
305  return point(x_, y_);
306 }
307 
309 {
310  return point(width_, height_);
311 }
312 
314 {
315  return {get_origin(), get_size()};
316 }
317 
318 int widget::get_x() const
319 {
320  return x_;
321 }
322 
323 int widget::get_y() const
324 {
325  return y_;
326 }
327 
328 unsigned widget::get_width() const
329 {
330  return width_;
331 }
332 
333 unsigned widget::get_height() const
334 {
335  return height_;
336 }
337 
339 {
340  layout_size_ = size;
341 }
342 
344 {
345  return layout_size_;
346 }
347 
348 void widget::set_linked_group(const std::string& linked_group)
349 {
350  linked_group_ = linked_group;
351 }
352 
353 /***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/
354 
356 {
357  return get_rectangle();
358 }
359 
361 {
362  switch(get_drawing_action()) {
363  case redraw_action::none:
364  return sdl::empty_rect;
366  return clipping_rectangle_;
367  case redraw_action::full:
368  default:
369  return get_rectangle();
370  }
371 }
372 
374 {
375  assert(visible_ == visibility::visible);
376 
378  return true;
379  }
380 
381  // Set viewport and clip so we can draw in local coordinates.
384  // Presumably we are drawing to our window's render buffer.
385  point window_origin = get_window()->get_origin();
386  dest.shift(-window_origin);
387  auto view_setter = draw::set_viewport(dest);
388  clip.shift(-get_origin());
389  auto clip_setter = draw::reduce_clip(clip);
390 
392  return impl_draw_background();
393 }
394 
396 {
397  assert(visible_ == visibility::visible);
398 
400  return;
401  }
402 
403  // Set viewport and clip so we can draw in local coordinates.
406  // Presumably we are drawing to our window's render buffer.
407  point window_origin = get_window()->get_origin();
408  dest.shift(-window_origin);
409  auto view_setter = draw::set_viewport(dest);
410  clip.shift(-get_origin());
411  auto clip_setter = draw::reduce_clip(clip);
412 
414 }
415 
417 {
418  assert(visible_ == visibility::visible);
419 
421  return true;
422  }
423 
424  // Set viewport and clip so we can draw in local coordinates.
427  // Presumably we are drawing to our window's render buffer.
428  point window_origin = get_window()->get_origin();
429  dest.shift(-window_origin);
430  auto view_setter = draw::set_viewport(dest);
431  clip.shift(-get_origin());
432  auto clip_setter = draw::reduce_clip(clip);
433 
434  return impl_draw_foreground();
435 }
436 
438 {
441 }
442 
443 void widget::set_visible_rectangle(const SDL_Rect& rectangle)
444 {
446 
449  } else if(clipping_rectangle_.empty()) {
451  } else {
453  }
454 }
455 
457 {
458  if (!width_ && !height_) {
459  // Do nothing if the widget hasn't yet been placed.
460  return;
461  }
463 }
464 
465 void widget::queue_redraw(const rect& region)
466 {
467  get_window()->queue_rerender(region);
469 }
470 
471 void widget::set_visible(const visibility visible)
472 {
473  if(visible == visible_) {
474  return;
475  }
476 
477  // Switching to or from invisible should invalidate the layout
478  // if the widget has already been laid out.
479  const bool need_resize = visible_ == visibility::invisible
480  || (visible == visibility::invisible && get_size() != point());
481  visible_ = visible;
482 
483  if(need_resize) {
484  if(visible == visibility::visible && new_widgets) {
487  } else {
488  window* window = get_window();
489  if(window) {
491  }
492  }
493  } else {
494  queue_redraw();
495  }
496 }
497 
499 {
500  return visible_;
501 }
502 
504 {
505  return (width_ == 0 || height_ == 0) ? redraw_action::none
506  : redraw_action_;
507 }
508 
509 void widget::set_debug_border_mode(const debug_border debug_border_mode)
510 {
511  debug_border_mode_ = debug_border_mode;
512 }
513 
514 void widget::set_debug_border_color(const color_t debug_border_color)
515 {
516  debug_border_color_ = debug_border_color;
517 }
518 
520 {
521  SDL_Rect r = redraw_action_ == redraw_action::partly
524 
525  switch(debug_border_mode_) {
526  case debug_border::none:
527  /* DO NOTHING */
528  break;
529 
532  break;
533 
534  case debug_border::fill:
536  break;
537 
538  default:
539  assert(false);
540  }
541 }
542 
543 /***** ***** ***** ***** Query functions ***** ***** ***** *****/
544 
545 widget* widget::find_at(const point& coordinate, const bool must_be_active)
546 {
547  return is_at(coordinate, must_be_active) ? this : nullptr;
548 }
549 
551  const bool must_be_active) const
552 {
553  return is_at(coordinate, must_be_active) ? this : nullptr;
554 }
555 
556 widget* widget::find(const std::string& id, const bool /*must_be_active*/)
557 {
558  return id_ == id ? this : nullptr;
559 }
560 
561 const widget* widget::find(const std::string& id,
562  const bool /*must_be_active*/) const
563 {
564  return id_ == id ? this : nullptr;
565 }
566 
567 bool widget::has_widget(const widget& widget) const
568 {
569  return &widget == this;
570 }
571 
572 bool widget::is_at(const point& coordinate) const
573 {
574  return is_at(coordinate, true);
575 }
576 
577 bool widget::recursive_is_visible(const widget* widget, const bool must_be_active) const
578 {
579  while(widget) {
581  || (widget->visible_ == visibility::hidden && must_be_active)) {
582  return false;
583  }
584 
585  widget = widget->parent_;
586  }
587 
588  return true;
589 }
590 
591 bool widget::is_at(const point& coordinate, const bool must_be_active) const
592 {
593  if(!recursive_is_visible(this, must_be_active)) {
594  return false;
595  }
596 
598 }
599 
600 } // 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:76
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:54
const point & layout_size() const
Definition: widget.cpp:343
virtual void demand_reduce_width(const unsigned maximum_width)
Tries to reduce the width of a widget.
Definition: widget.cpp:179
void set_layout_size(const point &size)
Definition: widget.cpp:338
grid * get_parent_grid()
Get the parent grid.
Definition: widget.cpp:146
redraw_action redraw_action_
Field for the action to do on a drawing request.
Definition: widget.hpp:642
bool draw_foreground()
Draws the foreground of the widget.
Definition: widget.cpp:416
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:194
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:240
debug_border debug_border_mode_
Mode for drawing the debug border.
Definition: widget.hpp:653
void set_visible(const visibility visible)
Definition: widget.cpp:471
void set_id(const std::string &id)
Definition: widget.cpp:99
int x_
The x-coordinate of the widget on the screen.
Definition: widget.hpp:466
virtual void demand_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:189
virtual void layout_children()
Allows a widget to update its children.
Definition: widget.cpp:298
visibility visible_
Field for the status of the visibility.
Definition: widget.hpp:639
virtual ~widget() override
Definition: widget.cpp:78
rect clipping_rectangle_
The clipping rectangle if a widget is partly visible.
Definition: widget.hpp:645
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:168
SDL_Rect get_dirty_rectangle() const
Gets the dirty rectangle of the widget.
Definition: widget.cpp:437
void set_linked_group(const std::string &linked_group)
Definition: widget.cpp:348
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:456
widget * parent_
The parent widget.
Definition: widget.hpp:215
visibility get_visible() const
Definition: widget.cpp:498
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:303
color_t debug_border_color_
The color for the debug border.
Definition: widget.hpp:656
int get_x() const
Definition: widget.cpp:318
virtual bool impl_draw_foreground()
See draw_foreground.
Definition: widget.hpp:582
virtual widget * find(const std::string &id, const bool must_be_active)
Returns a widget with the wanted id.
Definition: widget.cpp:556
unsigned width_
The width of the widget.
Definition: widget.hpp:472
unsigned get_width() const
Definition: widget.cpp:328
int get_y() const
Definition: widget.cpp:323
void set_parent(widget *parent)
Definition: widget.cpp:156
virtual point calculate_best_size() const =0
Calculates the best size.
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:308
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:395
virtual void move(const int x_offset, const int y_offset)
Moves a widget.
Definition: widget.cpp:266
bool draw_background()
Draws the background of a widget.
Definition: widget.cpp:373
virtual bool has_widget(const widget &widget) const
Does the widget contain the widget.
Definition: widget.cpp:567
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:222
unsigned get_height() const
Definition: widget.cpp:333
const std::string & id() const
Definition: widget.cpp:111
window * get_window()
Get the parent window.
Definition: widget.cpp:118
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:577
virtual bool impl_draw_background()
See draw_background.
Definition: widget.hpp:571
int y_
The y-coordinate of the widget on the screen.
Definition: widget.hpp:469
virtual void set_horizontal_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:272
std::string id_
The id is the unique name of the widget in a certain context.
Definition: widget.hpp:176
visibility
Visibility settings done by the user.
Definition: widget.hpp:64
@ 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:355
SDL_Rect calculate_clipping_rectangle() const
Calculates the clipping rectangle of the widget.
Definition: widget.cpp:360
std::string linked_group_
The linked group the widget belongs to.
Definition: widget.hpp:511
void set_debug_border_mode(const debug_border debug_border_mode)
Definition: widget.cpp:509
redraw_action get_drawing_action() const
Definition: widget.cpp:503
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:313
virtual void impl_draw_children()
See draw_children.
Definition: widget.hpp:577
void draw_debug_border()
Definition: widget.cpp:519
point layout_size_
The best size for the widget.
Definition: widget.hpp:487
@ 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:545
void set_debug_border_color(const color_t debug_border_color)
Definition: widget.cpp:514
unsigned height_
The height of the widget.
Definition: widget.hpp:475
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:228
virtual void request_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:184
virtual bool can_wrap() const
Can the widget wrap.
Definition: widget.cpp:217
virtual bool is_at(const point &coordinate) const override
See event::dispatcher::is_at.
Definition: widget.cpp:572
redraw_action
Visibility set by the engine.
Definition: widget.hpp:102
@ 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:443
widget * parent()
Definition: widget.cpp:161
virtual void set_vertical_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:285
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:67
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:776
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
Definition: window.cpp:819
point get_linked_size(const std::string &linked_group_id) const
Definition: window.hpp:435
void remove_linked_widget(const std::string &id, const widget *widget)
Removes a widget from a linked size group.
Definition: window.cpp:833
void queue_rerender(const rect &region)
Queue a rerender of the internal render buffer.
Definition: window.cpp:697
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:215
This file contains the window object, this object is a top level container which has the event manage...
#define PLAIN_LOG
Definition: log.hpp:262
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:552
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:458
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:51
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:203
void rect(const SDL_Rect &rect)
Draw a rectangle.
Definition: draw.cpp:151
@ 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:87
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:49
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
Definition: rect.cpp:54
void shift(const point &p)
Shift the rectangle by the given relative position.
Definition: rect.cpp:106
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:92
mock_party p