The Battle for Wesnoth  1.15.0-dev
widget.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "gui/widgets/grid.hpp"
18 #include "gui/widgets/settings.hpp"
19 #include "gui/widgets/window.hpp"
21 #include "gui/core/log.hpp"
23 #include "sdl/rect.hpp"
24 #include "video.hpp"
25 
26 namespace gui2
27 {
28 
29 /***** ***** ***** Constructor and destructor. ***** ***** *****/
30 
32  : id_("")
33  , parent_(nullptr)
34  , x_(-1)
35  , y_(-1)
36  , width_(0)
37  , height_(0)
38  , layout_size_()
39 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
40  , last_best_size_()
41 #endif
42  , linked_group_()
43  , visible_(visibility::visible)
44  , redraw_action_(redraw_action::full)
45  , clipping_rectangle_()
46  , debug_border_mode_(0)
47  , debug_border_color_(0,0,0,0)
48 {
49  DBG_GUI_LF << "widget create: " << static_cast<void*>(this) << "\n";
50 }
51 
53  : id_(builder.id)
54  , parent_(nullptr)
55  , x_(-1)
56  , y_(-1)
57  , width_(0)
58  , height_(0)
59  , layout_size_()
60 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
61  , last_best_size_()
62 #endif
63  , linked_group_(builder.linked_group)
64  , visible_(visibility::visible)
67  , debug_border_mode_(builder.debug_border_mode)
68  , debug_border_color_(builder.debug_border_color)
69 {
70  DBG_GUI_LF << "widget create: " << static_cast<void*>(this) << "\n";
71 }
72 
74 {
76  << "widget destroy: " << static_cast<void*>(this) << " (id: " << id_
77  << ")\n";
78 
79  widget* p = parent();
80  while(p) {
81  fire(event::NOTIFY_REMOVAL, *p, nullptr);
82  p = p->parent();
83  }
84 
85  if(!linked_group_.empty()) {
86  if(window* window = get_window()) {
88  }
89  }
90 }
91 
92 /***** ***** ***** ***** ID functions. ***** ***** ***** *****/
93 
94 void widget::set_id(const std::string& id)
95 {
96  styled_widget* this_ctrl = dynamic_cast<styled_widget*>(this);
97 
99  << "set id of " << static_cast<void*>(this) << " to '" << id << "' "
100  << "(was '" << id_ << "'). Widget type: "
101  << (this_ctrl ? this_ctrl->get_control_type() : typeid(widget).name()) << "\n";
102 
103  id_ = id;
104 }
105 
106 const std::string& widget::id() const
107 {
108  return id_;
109 }
110 
111 /***** ***** ***** ***** Parent functions ***** ***** ***** *****/
112 
114 {
115  // Go up into the parent tree until we find the top level
116  // parent, we can also be the toplevel so start with
117  // ourselves instead of our parent.
118  widget* result = this;
119  while(result->parent_) {
120  result = result->parent_;
121  }
122 
123  // on error dynamic_cast returns nullptr which is what we want.
124  return dynamic_cast<window*>(result);
125 }
126 
128 {
129  // Go up into the parent tree until we find the top level
130  // parent, we can also be the toplevel so start with
131  // ourselves instead of our parent.
132  const widget* result = this;
133  while(result->parent_) {
134  result = result->parent_;
135  }
136 
137  // on error dynamic_cast returns nullptr which is what we want.
138  return dynamic_cast<const window*>(result);
139 }
140 
142 {
143  widget* result = parent_;
144  while(result && dynamic_cast<grid*>(result) == nullptr) {
145  result = result->parent_;
146  }
147 
148  return result ? dynamic_cast<grid*>(result) : nullptr;
149 }
150 
152 {
153  parent_ = parent;
154 }
155 
157 {
158  return parent_;
159 }
160 
161 /***** ***** ***** ***** Size and layout functions. ***** ***** ***** *****/
162 
163 void widget::layout_initialize(const bool /*full_initialization*/)
164 {
165  assert(visible_ != visibility::invisible);
166  assert(get_window());
167 
168  layout_size_ = point();
169  if(!linked_group_.empty()) {
171  }
172 }
173 
174 void widget::demand_reduce_width(const unsigned /*maximum_width*/)
175 {
176  /* DO NOTHING */
177 }
178 
179 void widget::request_reduce_height(const unsigned /*maximum_height*/)
180 {
181  /* DO NOTHING */
182 }
183 
184 void widget::demand_reduce_height(const unsigned /*maximum_height*/)
185 {
186  /* DO NOTHING */
187 }
188 
190 {
191  assert(visible_ != visibility::invisible);
192 
193  point result = layout_size_;
194  if(result == point()) {
195  result = calculate_best_size();
196  //Adjust to linked widget size if linked widget size was already calculated.
197  if(!get_window()->get_need_layout() && !linked_group_.empty())
198  {
199  point linked_size = get_window()->get_linked_size(linked_group_);
200  result.x = std::max(result.x, linked_size.x);
201  result.y = std::max(result.y, linked_size.y);
202  }
203  }
204 
205 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
206  last_best_size_ = result;
207 #endif
208 
209  return result;
210 }
211 
212 bool widget::can_wrap() const
213 {
214  return false;
215 }
216 
217 void widget::set_origin(const point& origin)
218 {
219  x_ = origin.x;
220  y_ = origin.y;
221 }
222 
224 {
225  assert(size.x >= 0);
226  assert(size.y >= 0);
227 
228  width_ = size.x;
229  height_ = size.y;
230 }
231 
232 void widget::place(const point& origin, const point& size)
233 {
234  assert(size.x >= 0);
235  assert(size.y >= 0);
236 
237  x_ = origin.x;
238  y_ = origin.y;
239  width_ = size.x;
240  height_ = size.y;
241 
242 #if 0
243  std::cerr
244  << "Id " << id()
245  << " rect " << get_rectangle()
246  << " parent "
247  << (parent ? parent->get_x() : 0)
248  << ','
249  << (parent ? parent->get_y() : 0)
250  << " screen origin " << x_ << ',' << y_
251  << ".\n";
252 #endif
253 }
254 
255 void widget::move(const int x_offset, const int y_offset)
256 {
257  x_ += x_offset;
258  y_ += y_offset;
259 }
260 
261 void widget::set_horizontal_alignment(const std::string& alignment)
262 {
263  grid* parent_grid = get_parent_grid();
264  if(!parent_grid) {
265  return;
266  }
267 
269 
270  // TODO: evaluate necessity
271  //get_window()->invalidate_layout();
272 }
273 
274 void widget::set_vertical_alignment(const std::string& alignment)
275 {
276  grid* parent_grid = get_parent_grid();
277  if(!parent_grid) {
278  return;
279  }
280 
282 
283  // TODO: evaluate necessity
284  //get_window()->invalidate_layout();
285 }
286 
288 {
289  /* DO NOTHING */
290 }
291 
293 {
294  return point(x_, y_);
295 }
296 
298 {
299  return point(width_, height_);
300 }
301 
302 SDL_Rect widget::get_rectangle() const
303 {
304  return create_rect(get_origin(), get_size());
305 }
306 
307 int widget::get_x() const
308 {
309  return x_;
310 }
311 
312 int widget::get_y() const
313 {
314  return y_;
315 }
316 
317 unsigned widget::get_width() const
318 {
319  return width_;
320 }
321 
322 unsigned widget::get_height() const
323 {
324  return height_;
325 }
326 
328 {
329  layout_size_ = size;
330 }
331 
333 {
334  return layout_size_;
335 }
336 
337 void widget::set_linked_group(const std::string& linked_group)
338 {
339  linked_group_ = linked_group;
340 }
341 
342 /***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/
343 
345 {
346  return get_rectangle();
347 }
348 
350 {
351  return clipping_rectangle_;
352 }
353 
354 namespace
355 {
356 /**
357  * Small RAII helper class to set the renderer viewport and clip rect for the drawing routines.
358  */
359 class viewport_and_clip_rect_setter
360 {
361 public:
362  explicit viewport_and_clip_rect_setter(const widget& widget)
363  : renderer_(CVideo::get_singleton().get_renderer())
364  {
365  // Set viewport.
366  const SDL_Rect dst_rect = widget.calculate_blitting_rectangle();
367  SDL_RenderSetViewport(renderer_, &dst_rect);
368 
369  // Set clip rect, if appropriate.
371  return;
372  }
373 
374  SDL_Rect clip_rect = widget.calculate_clipping_rectangle();
375 
376  // Adjust clip rect origin to match the viewport origin. Currently, the both rects are mapped to
377  // absolute screen coordinates. However, setting the viewport essentially moves the screen origin,
378  // meaning if both the viewport rect and clip rect have x = 100, then clipping will actually
379  // happen at x = 200.
380  clip_rect.x -= dst_rect.x;
381  clip_rect.y -= dst_rect.y;
382 
383  SDL_RenderSetClipRect(renderer_, &clip_rect);
384  }
385 
386  ~viewport_and_clip_rect_setter()
387  {
388  SDL_RenderSetClipRect(renderer_, nullptr);
389  SDL_RenderSetViewport(renderer_, nullptr);
390  }
391 
392 private:
393  SDL_Renderer* renderer_;
394 };
395 
396 } // anon namespace
397 
399 {
400  assert(visible_ == visibility::visible);
401 
402  viewport_and_clip_rect_setter setter(*this);
403 
406 }
407 
409 {
410  assert(visible_ == visibility::visible);
411 
412  viewport_and_clip_rect_setter setter(*this);
413 
415 }
416 
418 {
419  assert(visible_ == visibility::visible);
420 
421  viewport_and_clip_rect_setter setter(*this);
422 
424 }
425 
427 {
430 }
431 
432 void widget::set_visible_rectangle(const SDL_Rect& rectangle)
433 {
435 
438  } else if(clipping_rectangle_ == sdl::empty_rect) {
440  } else {
442  }
443 }
444 
445 void widget::set_visible(const visibility visible)
446 {
447  if(visible == visible_) {
448  return;
449  }
450 
451  // Switching to or from invisible should invalidate the layout
452  // if the widget has already been laid out.
453  const bool need_resize = visible_ == visibility::invisible
454  || (visible == visibility::invisible && get_size() != point());
455  visible_ = visible;
456 
457  if(need_resize) {
458  if(visible == visibility::visible && new_widgets) {
460  fire(event::REQUEST_PLACEMENT, *this, message);
461  } else {
462  window* window = get_window();
463  if(window) {
464  window->invalidate_layout();
465  }
466  }
467  }
468 }
469 
471 {
472  return visible_;
473 }
474 
476 {
477  return (width_ == 0 || height_ == 0) ? redraw_action::none
478  : redraw_action_;
479 }
480 
481 void widget::set_debug_border_mode(const unsigned debug_border_mode)
482 {
483  debug_border_mode_ = debug_border_mode;
484 }
485 
486 void widget::set_debug_border_color(const color_t debug_border_color)
487 {
488  debug_border_color_ = debug_border_color;
489 }
490 
492 {
493  SDL_Rect r = redraw_action_ == redraw_action::partly
496 
497  switch(debug_border_mode_) {
498  case 0:
499  /* DO NOTHING */
500  break;
501 
502  case 1:
504  break;
505 
506  case 2:
508  break;
509 
510  default:
511  assert(false);
512  }
513 }
514 
515 /***** ***** ***** ***** Query functions ***** ***** ***** *****/
516 
517 widget* widget::find_at(const point& coordinate, const bool must_be_active)
518 {
519  return is_at(coordinate, must_be_active) ? this : nullptr;
520 }
521 
523  const bool must_be_active) const
524 {
525  return is_at(coordinate, must_be_active) ? this : nullptr;
526 }
527 
528 widget* widget::find(const std::string& id, const bool /*must_be_active*/)
529 {
530  return id_ == id ? this : nullptr;
531 }
532 
533 const widget* widget::find(const std::string& id,
534  const bool /*must_be_active*/) const
535 {
536  return id_ == id ? this : nullptr;
537 }
538 
539 bool widget::has_widget(const widget& widget) const
540 {
541  return &widget == this;
542 }
543 
544 bool widget::is_at(const point& coordinate) const
545 {
546  return is_at(coordinate, true);
547 }
548 
549 bool widget::recursive_is_visible(const widget* widget, const bool must_be_active) const
550 {
551  while(widget) {
552  if(widget->visible_ == visibility::invisible
553  || (widget->visible_ == visibility::hidden && must_be_active)) {
554  return false;
555  }
556 
557  widget = widget->parent_;
558  }
559 
560  return true;
561 }
562 
563 bool widget::is_at(const point& coordinate, const bool must_be_active) const
564 {
565  if(!recursive_is_visible(this, must_be_active)) {
566  return false;
567  }
568 
569  return sdl::point_in_rect(coordinate, get_rectangle());
570 }
571 
572 } // namespace gui2
Define the common log macros for the gui toolkit.
#define DBG_GUI_LF
Definition: log.hpp:64
Contains the info needed to instantiate a widget.
virtual void impl_draw_background()
See draw_background.
Definition: widget.hpp:558
bool new_widgets
Do we wish to use the new library or not.
Definition: settings.cpp:21
grid * get_parent_grid()
Get the parent grid.
Definition: widget.cpp:141
int get_x() const
Definition: widget.cpp:307
SDL_Rect create_rect(const point &origin, const point &size)
Creates a rectangle.
Definition: helper.cpp:32
void set_parent(widget *parent)
Definition: widget.cpp:151
virtual bool is_at(const point &coordinate) const override
See event::dispatcher::is_at.
Definition: widget.cpp:544
void set_debug_border_mode(const unsigned debug_border_mode)
Definition: widget.cpp:481
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:163
void set_layout_size(const point &size)
Definition: widget.cpp:327
redraw_action
Visibility set by the engine.
Definition: widget.hpp:96
virtual widget * find(const std::string &id, const bool must_be_active)
Returns a widget with the wanted id.
Definition: widget.cpp:528
SDL_Renderer * renderer_
Definition: widget.cpp:393
visibility get_visible() const
Definition: widget.cpp:470
Main class to show messages to the user.
Definition: message.hpp:34
unsigned debug_border_mode_
Mode for drawing the debug border.
Definition: widget.hpp:627
widget * parent_
The parent widget.
Definition: widget.hpp:201
const std::string & id() const
Definition: widget.cpp:106
This file contains the window object, this object is a top level container which has the event manage...
unsigned height_
The height of the widget.
Definition: widget.hpp:464
redraw_action get_drawing_action() const
Definition: widget.cpp:475
SDL_Rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:302
Base class for all widgets.
Definition: widget.hpp:48
virtual void set_visible_rectangle(const SDL_Rect &rectangle)
Sets the visible rectangle for a widget.
Definition: widget.cpp:432
unsigned get_height() const
Definition: widget.cpp:322
virtual void impl_draw_foreground()
See draw_foreground.
Definition: widget.hpp:568
static CVideo & get_singleton()
Definition: video.hpp:48
redraw_action redraw_action_
Field for the action to do on a drawing request.
Definition: widget.hpp:611
SDL_Rect intersect_rects(const SDL_Rect &rect1, const SDL_Rect &rect2)
Calculates the intersection of two rectangles.
Definition: rect.cpp:39
static const unsigned HORIZONTAL_MASK
Definition: grid.hpp:59
virtual void request_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:179
virtual ~widget() override
Definition: widget.cpp:73
void draw_debug_border()
Definition: widget.cpp:491
-file util.hpp
virtual void demand_reduce_width(const unsigned maximum_width)
Tries to reduce the width of a widget.
Definition: widget.cpp:174
std::string id_
The id is the unique name of the widget in a certain context.
Definition: widget.hpp:162
void draw_foreground()
Draws the foreground of the widget.
Definition: widget.cpp:417
unsigned get_width() const
Definition: widget.cpp:317
visibility visible_
Field for the status of the visibility.
Definition: widget.hpp:608
virtual void set_horizontal_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:261
int x
x coordinate.
Definition: point.hpp:44
Generic file dialog.
Definition: field-fwd.hpp:22
point get_linked_size(const std::string &linked_group_id) const
Definition: window.hpp:377
The message callbacks hold a reference to a message.
Definition: message.hpp:46
Base container class.
Definition: grid.hpp:30
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
Request to place the widget.
Definition: handler.hpp:94
SDL_Rect get_dirty_rectangle() const
Gets the dirty rectangle of the widget.
Definition: widget.cpp:426
SDL_Rect calculate_clipping_rectangle() const
Calculates the clipping rectangle of the widget.
Definition: widget.cpp:349
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:189
virtual void demand_reduce_height(const unsigned maximum_height)
Tries to reduce the height of a widget.
Definition: widget.cpp:184
const t_string name
This file contains the settings handling of the widget library.
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:232
The widget is fully visible.
void set_visible(const visibility visible)
Definition: widget.cpp:445
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:217
virtual void impl_draw_children()
See draw_children.
Definition: widget.hpp:563
Sent by a widget to notify others it&#39;s being destroyed.
Definition: handler.hpp:87
void draw_rectangle(const SDL_Rect &rect, const color_t &color)
Draw a rectangle outline.
Definition: rect.cpp:57
widget * parent()
Definition: widget.cpp:156
The widget is not visible.
virtual point calculate_best_size() const =0
Calculates the best size.
virtual bool has_widget(const widget &widget) const
Does the widget contain the widget.
Definition: widget.cpp:539
This file contains the definitions for the gui2::event::message class.
point layout_size_
The best size for the widget.
Definition: widget.hpp:476
std::string linked_group_
The linked group the widget belongs to.
Definition: widget.hpp:500
int y_
The y-coordinate of the widget on the screen.
Definition: widget.hpp:458
int get_y() const
Definition: widget.cpp:312
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:22
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
Definition: window.cpp:655
mock_party p
The user set the widget invisible, that means:
color_t debug_border_color_
The color for the debug border.
Definition: widget.hpp:630
window * get_window()
Get the parent window.
Definition: widget.cpp:113
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:408
visibility
Visibility settings done by the user.
Definition: widget.hpp:58
Holds a 2D point.
Definition: point.hpp:23
static const unsigned VERTICAL_MASK
Definition: grid.hpp:52
virtual void layout_children()
Allows a widget to update its children.
Definition: widget.cpp:287
Base class for all visible items.
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:549
unsigned get_v_align(const std::string &v_align)
Returns the vertical alignment.
Definition: helper.cpp:37
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:297
SDL_Rect clipping_rectangle_
The clipping rectangle if a widget is partly visible.
Definition: widget.hpp:614
unsigned width_
The width of the widget.
Definition: widget.hpp:461
Contains the SDL_Rect helper code.
The user sets the widget visible, that means:
The user sets the widget hidden, that means:
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:929
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:31
virtual void move(const int x_offset, const int y_offset)
Moves a widget.
Definition: widget.cpp:255
void set_id(const std::string &id)
Definition: widget.cpp:94
void set_debug_border_color(const color_t debug_border_color)
Definition: widget.cpp:486
void fill_rectangle(const SDL_Rect &rect, const color_t &color)
Draws a filled rectangle.
Definition: rect.cpp:65
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:66
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:223
const point & layout_size() const
Definition: widget.cpp:332
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:612
virtual void set_vertical_alignment(const std::string &alignment)
Sets the horizontal alignment of the widget within its parent grid.
Definition: widget.cpp:274
void draw_background()
Draws the background of a widget.
Definition: widget.cpp:398
virtual const std::string & get_control_type() const =0
Returns the type of this styled_widget.
virtual widget * find_at(const point &coordinate, const bool must_be_active)
Returns the widget at the wanted coordinates.
Definition: widget.cpp:517
void remove_linked_widget(const std::string &id, const widget *widget)
Removes a widget from a linked size group.
Definition: window.cpp:669
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
virtual bool can_wrap() const
Can the widget wrap.
Definition: widget.cpp:212
unsigned get_h_align(const std::string &h_align)
Returns the horizontal alignment.
Definition: helper.cpp:52
The widget is partly visible.
int y
y coordinate.
Definition: point.hpp:47
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
int x_
The x-coordinate of the widget on the screen.
Definition: widget.hpp:455
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:292
void set_linked_group(const std::string &linked_group)
Definition: widget.cpp:337
SDL_Rect calculate_blitting_rectangle() const
Calculates the blitting rectangle of the widget.
Definition: widget.cpp:344