The Battle for Wesnoth  1.15.0-dev
grid.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 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 
18 
21 #include "gui/core/log.hpp"
24 #include "gui/widgets/window.hpp"
25 
26 #include <numeric>
27 
28 #define LOG_SCOPE_HEADER "grid [" + id() + "] " + __func__
29 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
30 #define LOG_IMPL_HEADER "grid [" + grid.id() + "] " + __func__ + ':'
31 
32 #define LOG_CHILD_SCOPE_HEADER \
33  "grid::child [" + (widget_ ? widget_->id() : "-") + "] " + __func__
34 #define LOG_CHILD_HEADER LOG_CHILD_SCOPE_HEADER + ':'
35 
36 namespace gui2
37 {
38 
39 grid::grid(const unsigned rows, const unsigned cols)
40  : rows_(rows)
41  , cols_(cols)
42  , row_height_()
43  , col_width_()
44  , row_grow_factor_(rows)
45  , col_grow_factor_(cols)
46  , children_(rows * cols)
47 {
48  connect_signal<event::REQUEST_PLACEMENT>(
49  std::bind(&grid::request_placement, this,
50  std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
52 }
53 
55 {
56 }
57 
58 unsigned grid::add_row(const unsigned count)
59 {
60  assert(count);
61 
62  // FIXME the warning in set_rows_cols should be killed.
63 
64  unsigned result = rows_;
65  set_rows_cols(rows_ + count, cols_);
66  return result;
67 }
68 
70  const unsigned row,
71  const unsigned col,
72  const unsigned flags,
73  const unsigned border_size)
74 {
75  assert(row < rows_ && col < cols_);
76  assert(flags & VERTICAL_MASK);
77  assert(flags & HORIZONTAL_MASK);
78 
79  child& cell = get_child(row, col);
80 
81  // clear old child if any
82  if(cell.get_widget()) {
83  // free a child when overwriting it
84  WRN_GUI_G << LOG_HEADER << " child '" << cell.id() << "' at cell '"
85  << row << ',' << col << "' will be replaced.\n";
86  }
87 
88  // copy data
89  cell.set_flags(flags);
90  cell.set_border_size(border_size);
91  cell.set_widget(widget);
92 
93  // make sure the new child is valid before deferring
94  if(gui2::widget* w = cell.get_widget()) {
95  w->set_parent(this);
96  }
97 }
98 
99 widget_ptr grid::swap_child(const std::string& id,
100  widget_ptr w,
101  const bool recurse,
102  widget* new_parent)
103 {
104  assert(w);
105 
106  for(auto & child : children_)
107  {
108  if(child.id() != id) {
109 
110  if(recurse) {
111  // decent in the nested grids.
112  grid* g = dynamic_cast<grid*>(child.get_widget());
113  if(g) {
114 
115  widget_ptr old = g->swap_child(id, w, true);
116  if(old) {
117  return old;
118  }
119  }
120  }
121 
122  continue;
123  }
124 
125  // Free widget from cell and validate.
126  widget_ptr old = child.free_widget();
127  assert(old);
128 
129  old->set_parent(new_parent);
130 
131  w->set_parent(this);
132  w->set_visible(old->get_visible());
133 
134  child.set_widget(w);
135  return old;
136  }
137 
138  return nullptr;
139 }
140 
141 void grid::remove_child(const unsigned row, const unsigned col)
142 {
143  assert(row < rows_ && col < cols_);
144 
145  child& cell = get_child(row, col);
146  cell.set_widget(nullptr);
147 }
148 
149 void grid::remove_child(const std::string& id, const bool find_all)
150 {
151  for(auto & child : children_)
152  {
153  if(child.id() == id) {
154  child.set_widget(nullptr);
155 
156  if(!find_all) {
157  break;
158  }
159  }
160  }
161 }
162 
163 void grid::set_active(const bool active)
164 {
165  for(auto & child : children_)
166  {
167 
169  if(!widget) {
170  continue;
171  }
172 
173  grid* g = dynamic_cast<grid*>(widget);
174  if(g) {
175  g->set_active(active);
176  continue;
177  }
178 
179  styled_widget* control = dynamic_cast<styled_widget*>(widget);
180  if(control) {
181  control->set_active(active);
182  }
183  }
184 }
185 
186 void grid::layout_initialize(const bool full_initialization)
187 {
188  // Inherited.
189  widget::layout_initialize(full_initialization);
190 
191  // Clear child caches.
192  for(auto & child : children_)
193  {
194 
195  child.layout_initialize(full_initialization);
196  }
197 }
198 
199 void grid::reduce_width(const unsigned maximum_width)
200 {
201  /***** ***** ***** ***** INIT ***** ***** ***** *****/
203  DBG_GUI_L << LOG_HEADER << " maximum width " << maximum_width << ".\n";
204 
206  if(size.x <= static_cast<int>(maximum_width)) {
207  DBG_GUI_L << LOG_HEADER << " Already fits.\n";
208  return;
209  }
210 
211  /***** ***** ***** ***** Request resize ***** ***** ***** *****/
212 
213  request_reduce_width(maximum_width);
214 
215  size = get_best_size();
216  if(size.x <= static_cast<int>(maximum_width)) {
217  DBG_GUI_L << LOG_HEADER << " Resize request honored.\n";
218  return;
219  }
220 
221  /***** ***** ***** ***** Demand resize ***** ***** ***** *****/
222 
223  /** @todo Implement. */
224 
225  /***** ***** ***** ***** Acknowledge failure ***** ***** ***** *****/
226 
227  DBG_GUI_L << LOG_HEADER << " Resizing failed.\n";
228 
230 }
231 
232 void grid::request_reduce_width(const unsigned maximum_width)
233 {
235  if(size.x <= static_cast<int>(maximum_width)) {
236  /** @todo this point shouldn't be reached, find out why it does. */
237  return;
238  }
239 
240  const unsigned too_wide = size.x - maximum_width;
241  unsigned reduced = 0;
242  for(std::size_t col = 0; col < cols_; ++col) {
243  if(too_wide - reduced >= col_width_[col]) {
244  DBG_GUI_L << LOG_HEADER << " column " << col
245  << " is too small to be reduced.\n";
246  continue;
247  }
248 
249  const unsigned wanted_width = col_width_[col] - (too_wide - reduced);
250  const unsigned width
252  *this, col, wanted_width);
253 
254  if(width < col_width_[col]) {
255  unsigned reduction = col_width_[col] - width;
256 
257  DBG_GUI_L << LOG_HEADER << " reduced " << reduction
258  << " pixels for column " << col << ".\n";
259 
260  size.x -= reduction;
261  reduced += reduction;
262  }
263 
264  if(size.x <= static_cast<int>(maximum_width)) {
265  break;
266  }
267  }
268 
270 }
271 
272 void grid::demand_reduce_width(const unsigned /*maximum_width*/)
273 {
274  /** @todo Implement. */
275 }
276 
277 void grid::reduce_height(const unsigned maximum_height)
278 {
279  /***** ***** ***** ***** INIT ***** ***** ***** *****/
281  DBG_GUI_L << LOG_HEADER << " maximum height " << maximum_height << ".\n";
282 
284  if(size.y <= static_cast<int>(maximum_height)) {
285  DBG_GUI_L << LOG_HEADER << " Already fits.\n";
286  return;
287  }
288 
289  /***** ***** ***** ***** Request resize ***** ***** ***** *****/
290 
291  request_reduce_height(maximum_height);
292 
293  size = get_best_size();
294  if(size.y <= static_cast<int>(maximum_height)) {
295  DBG_GUI_L << LOG_HEADER << " Resize request honored.\n";
296  return;
297  }
298 
299  /***** ***** ***** ***** Demand resize ***** ***** ***** *****/
300 
301  /** @todo Implement. */
302 
303  /***** ***** ***** ***** Acknowledge failure ***** ***** ***** *****/
304 
305  DBG_GUI_L << LOG_HEADER << " Resizing failed.\n";
306 
308 }
309 
310 void grid::request_reduce_height(const unsigned maximum_height)
311 {
313  if(size.y <= static_cast<int>(maximum_height)) {
314  /** @todo this point shouldn't be reached, find out why it does. */
315  return;
316  }
317 
318  const unsigned too_high = size.y - maximum_height;
319  unsigned reduced = 0;
320  for(std::size_t row = 0; row < rows_; ++row) {
321  unsigned wanted_height = row_height_[row] - (too_high - reduced);
322  /**
323  * @todo Improve this code.
324  *
325  * Now we try every item to be reduced, maybe items need a flag whether
326  * or not to try to reduce and also evaluate whether the force
327  * reduction is still needed.
328  */
329  if(too_high - reduced >= row_height_[row]) {
330  DBG_GUI_L << LOG_HEADER << " row " << row << " height "
331  << row_height_[row] << " want to reduce " << too_high
332  << " is too small to be reduced fully try 1 pixel.\n";
333 
334  wanted_height = 1;
335  }
336 
337  /* Reducing the height of a widget causes the widget to save its new size
338  in widget::layout_size_. After that, get_best_size() will return that
339  size and not the originally calculated optimal size.
340  Thus, it's perfectly correct that grid::calculate_best_size() that we
341  call later calls get_best_size() for child widgets as if size reduction
342  had never happened. */
343  const unsigned height = grid_implementation::row_request_reduce_height(
344  *this, row, wanted_height);
345 
346  if(height < row_height_[row]) {
347  unsigned reduction = row_height_[row] - height;
348 
349  DBG_GUI_L << LOG_HEADER << " row " << row << " height "
350  << row_height_[row] << " want to reduce " << too_high
351  << " reduced " << reduction << " pixels.\n";
352 
353  size.y -= reduction;
354  reduced += reduction;
355  }
356 
357  if(size.y <= static_cast<int>(maximum_height)) {
358  break;
359  }
360  }
361 
362  size = calculate_best_size();
363 
364  DBG_GUI_L << LOG_HEADER << " Requested maximum " << maximum_height
365  << " resulting height " << size.y << ".\n";
366 
367  set_layout_size(size);
368 }
369 
370 void grid::demand_reduce_height(const unsigned /*maximum_height*/)
371 {
372  /** @todo Implement. */
373 }
374 
375 void grid::request_placement(dispatcher&, const event::ui_event, bool& handled, bool&)
376 {
377  if (get_window()->invalidate_layout_blocked()) {
378  handled = true;
379  return;
380  }
381 
382  point size = get_size();
383  point best_size = calculate_best_size();
384  if(size.x >= best_size.x && size.y >= best_size.y) {
385  place(get_origin(), size);
386  handled = true;
387  return;
388  }
389 
391 
392  if(size.y >= best_size.y) {
393  // We have enough space in the Y direction, but not in the X direction.
394  // Try wrapping the content.
395  request_reduce_width(size.x);
396  best_size = get_best_size();
397 
398  if(size.x >= best_size.x && size.y >= best_size.y) {
399  // Wrapping succeeded, we still fit vertically.
400  place(get_origin(), size);
401  handled = true;
402  return;
403  } else {
404  // Wrapping failed, we no longer fit.
405  // Reset the sizes of child widgets.
406  layout_initialize(true);
407  }
408  }
409 
410  /*
411  Not enough space.
412  Let the event flow higher up.
413  This is a pre-event handler, so the event flows upwards. */
414 }
415 
417 {
418  point best_size = calculate_best_size();
419  set_layout_size(best_size);
420  return best_size;
421 }
422 
424 {
426 
427  // Reset the cached values.
428  row_height_.clear();
429  row_height_.resize(rows_, 0);
430  col_width_.clear();
431  col_width_.resize(cols_, 0);
432 
433  // First get the sizes for all items.
434  for(unsigned row = 0; row < rows_; ++row) {
435  for(unsigned col = 0; col < cols_; ++col) {
436 
437  const point size = get_child(row, col).get_best_size();
438 
439  if(size.x > static_cast<int>(col_width_[col])) {
440  col_width_[col] = size.x;
441  }
442 
443  if(size.y > static_cast<int>(row_height_[row])) {
444  row_height_[row] = size.y;
445  }
446  }
447  }
448 
449  for(unsigned row = 0; row < rows_; ++row) {
450  DBG_GUI_L << LOG_HEADER << " the row_height_ for row " << row
451  << " will be " << row_height_[row] << ".\n";
452  }
453 
454  for(unsigned col = 0; col < cols_; ++col) {
455  DBG_GUI_L << LOG_HEADER << " the col_width_ for column " << col
456  << " will be " << col_width_[col] << ".\n";
457  }
458 
459  const point result(
460  std::accumulate(col_width_.begin(), col_width_.end(), 0),
461  std::accumulate(row_height_.begin(), row_height_.end(), 0));
462 
463  DBG_GUI_L << LOG_HEADER << " returning " << result << ".\n";
464  return result;
465 }
466 
467 bool grid::can_wrap() const
468 {
469  for(const auto & child : children_)
470  {
471  if(child.can_wrap()) {
472  return true;
473  }
474  }
475 
476  // Inherited.
477  return widget::can_wrap();
478 }
479 
480 void grid::place(const point& origin, const point& size)
481 {
483 
484  /***** INIT *****/
485 
486  widget::place(origin, size);
487 
488  if(!rows_ || !cols_) {
489  return;
490  }
491 
492  // call the calculate so the size cache gets updated.
493  const point best_size = calculate_best_size();
494 
495  assert(row_height_.size() == rows_);
496  assert(col_width_.size() == cols_);
497  assert(row_grow_factor_.size() == rows_);
498  assert(col_grow_factor_.size() == cols_);
499 
500  DBG_GUI_L << LOG_HEADER << " best size " << best_size << " available size "
501  << size << ".\n";
502 
503  /***** BEST_SIZE *****/
504 
505  if(best_size == size) {
506  layout(origin);
507  return;
508  }
509 
510  if(best_size.x > size.x || best_size.y > size.y) {
511  // The assertion below fails quite often so try to give as much information as possible.
512  std::stringstream out;
513  out << " Failed to place a grid, we have " << size << " space but we need " << best_size << " space.";
514  out << " This happened at a grid with the id '" << id() << "'";
515  widget* pw = parent();
516  while(pw != nullptr) {
517  out << " in a '" << typeid(*pw).name() << "' with the id '" << pw->id() << "'";
518  pw = pw->parent();
519  }
520  ERR_GUI_L << LOG_HEADER << out.str() << ".\n";
521 
522  return;
523  }
524 
525  /***** GROW *****/
526 
527  // expand it.
528  if(size.x > best_size.x) {
529  const unsigned w = size.x - best_size.x;
530  unsigned w_size = std::accumulate(
531  col_grow_factor_.begin(), col_grow_factor_.end(), 0);
532 
533  DBG_GUI_L << LOG_HEADER << " extra width " << w
534  << " will be divided amount " << w_size << " units in "
535  << cols_ << " columns.\n";
536 
537  if(w_size == 0) {
538  // If all sizes are 0 reset them to 1
539  for(auto & val : col_grow_factor_)
540  {
541  val = 1;
542  }
543  w_size = cols_;
544  }
545  // We might have a bit 'extra' if the division doesn't fix exactly
546  // but we ignore that part for now.
547  const unsigned w_normal = w / w_size;
548  for(unsigned i = 0; i < cols_; ++i) {
549  col_width_[i] += w_normal * col_grow_factor_[i];
550  DBG_GUI_L << LOG_HEADER << " column " << i
551  << " with grow factor " << col_grow_factor_[i]
552  << " set width to " << col_width_[i] << ".\n";
553  }
554  }
555 
556  if(size.y > best_size.y) {
557  const unsigned h = size.y - best_size.y;
558  unsigned h_size = std::accumulate(
559  row_grow_factor_.begin(), row_grow_factor_.end(), 0);
560  DBG_GUI_L << LOG_HEADER << " extra height " << h
561  << " will be divided amount " << h_size << " units in "
562  << rows_ << " rows.\n";
563 
564  if(h_size == 0) {
565  // If all sizes are 0 reset them to 1
566  for(auto & val : row_grow_factor_)
567  {
568  val = 1;
569  }
570  h_size = rows_;
571  }
572  // We might have a bit 'extra' if the division doesn't fix exactly
573  // but we ignore that part for now.
574  const unsigned h_normal = h / h_size;
575  for(unsigned i = 0; i < rows_; ++i) {
576  row_height_[i] += h_normal * row_grow_factor_[i];
577  DBG_GUI_L << LOG_HEADER << " row " << i << " with grow factor "
578  << row_grow_factor_[i] << " set height to "
579  << row_height_[i] << ".\n";
580  }
581  }
582 
583  layout(origin);
584  return;
585 }
586 
587 void grid::set_origin(const point& origin)
588 {
589  const point movement {origin.x - get_x(), origin.y - get_y()};
590 
591  // Inherited.
592  widget::set_origin(origin);
593 
594  for(auto & child : children_)
595  {
596 
598  assert(widget);
599 
600  widget->set_origin(point(widget->get_x() + movement.x, widget->get_y() + movement.y));
601  }
602 }
603 
604 void grid::set_visible_rectangle(const SDL_Rect& rectangle)
605 {
606  // Inherited.
608 
609  for(auto & child : children_)
610  {
611 
613  assert(widget);
614 
615  widget->set_visible_rectangle(rectangle);
616  }
617 }
618 
620 {
621  for(auto & child : children_)
622  {
623  assert(child.get_widget());
625  }
626 }
627 
628 widget* grid::find_at(const point& coordinate, const bool must_be_active)
629 {
630  return grid_implementation::find_at<widget>(
631  *this, coordinate, must_be_active);
632 }
633 
635  const bool must_be_active) const
636 {
637  return grid_implementation::find_at<const widget>(
638  *this, coordinate, must_be_active);
639 }
640 
641 widget* grid::find(const std::string& id, const bool must_be_active)
642 {
643  return grid_implementation::find<widget>(*this, id, must_be_active);
644 }
645 
646 const widget* grid::find(const std::string& id, const bool must_be_active)
647  const
648 {
649  return grid_implementation::find<const widget>(*this, id, must_be_active);
650 }
651 
652 bool grid::has_widget(const widget& widget) const
653 {
654  if(widget::has_widget(widget)) {
655  return true;
656  }
657 
658  for(const auto & child : children_)
659  {
660  if(child.get_widget()->has_widget(widget)) {
661  return true;
662  }
663  }
664  return false;
665 }
666 
668 {
670  return false;
671  }
672 
673  for(const auto & child : children_)
674  {
675  const widget* widget = child.get_widget();
676  assert(widget);
677 
678  if(widget->disable_click_dismiss()) {
679  return true;
680  }
681  }
682  return false;
683 }
684 
686 {
687  return std::make_unique<gui2::iteration::grid>(*this);
688 }
689 
690 void grid::set_rows(const unsigned rows)
691 {
692  if(rows == rows_) {
693  return;
694  }
695 
696  set_rows_cols(rows, cols_);
697 }
698 
699 void grid::set_cols(const unsigned cols)
700 {
701  if(cols == cols_) {
702  return;
703  }
704 
705  set_rows_cols(rows_, cols);
706 }
707 
708 void grid::set_rows_cols(const unsigned rows, const unsigned cols)
709 {
710  if(rows == rows_ && cols == cols_) {
711  return;
712  }
713 
714  if(!children_.empty()) {
715  WRN_GUI_G << LOG_HEADER << " resizing a non-empty grid "
716  << " may give unexpected problems.\n";
717  }
718 
719  rows_ = rows;
720  cols_ = cols;
721  row_grow_factor_.resize(rows);
722  col_grow_factor_.resize(cols);
723  children_.resize(rows_ * cols_);
724 }
725 
727 {
729 
730  if(!widget_) {
731  DBG_GUI_L << LOG_CHILD_HEADER << " has widget " << false
732  << " returning " << border_space() << ".\n";
733  return border_space();
734  }
735 
736  if(widget_->get_visible() == widget::visibility::invisible) {
737  DBG_GUI_L << LOG_CHILD_HEADER << " has widget " << true
738  << " widget visible " << false << " returning 0,0"
739  << ".\n";
740  return point();
741  }
742 
743  const point best_size = widget_->get_best_size() + border_space();
744 
745  DBG_GUI_L << LOG_CHILD_HEADER << " has widget " << true
746  << " widget visible " << true << " returning " << best_size
747  << ".\n";
748  return best_size;
749 }
750 
752 {
753  assert(get_widget());
755  return;
756  }
757 
758  if(border_size_) {
759  if(flags_ & BORDER_TOP) {
760  origin.y += border_size_;
761  size.y -= border_size_;
762  }
763  if(flags_ & BORDER_BOTTOM) {
764  size.y -= border_size_;
765  }
766 
767  if(flags_ & BORDER_LEFT) {
768  origin.x += border_size_;
769  size.x -= border_size_;
770  }
771  if(flags_ & BORDER_RIGHT) {
772  size.x -= border_size_;
773  }
774  }
775 
776  // If size smaller or equal to best size set that size.
777  // No need to check > min size since this is what we got.
778  const point best_size = get_widget()->get_best_size();
779  if(size <= best_size) {
781  << " in best size range setting widget to " << origin << " x "
782  << size << ".\n";
783 
784  get_widget()->place(origin, size);
785  return;
786  }
787 
788  const styled_widget* control = dynamic_cast<const styled_widget*>(get_widget());
789  const point maximum_size = control ? control->get_config_maximum_size()
790  : point();
791 
792  if((flags_ & (HORIZONTAL_MASK | VERTICAL_MASK))
794 
795  if(maximum_size == point() || size <= maximum_size) {
796 
798  << " in maximum size range setting widget to " << origin
799  << " x " << size << ".\n";
800 
801  get_widget()->place(origin, size);
802  return;
803  }
804  }
805 
806  point widget_size = point(std::min(size.x, best_size.x), std::min(size.y, best_size.y));
807  point widget_orig = origin;
808 
809  const unsigned v_flag = flags_ & VERTICAL_MASK;
810 
811  if(v_flag == VERTICAL_GROW_SEND_TO_CLIENT) {
812  if(maximum_size.y) {
813  widget_size.y = std::min(size.y, maximum_size.y);
814  } else {
815  widget_size.y = size.y;
816  }
817  DBG_GUI_L << LOG_CHILD_HEADER << " vertical growing from "
818  << best_size.y << " to " << widget_size.y << ".\n";
819 
820  } else if(v_flag == VERTICAL_ALIGN_TOP) {
821  // Do nothing.
822 
823  DBG_GUI_L << LOG_CHILD_HEADER << " vertically aligned at the top.\n";
824 
825  } else if(v_flag == VERTICAL_ALIGN_CENTER) {
826 
827  widget_orig.y += (size.y - widget_size.y) / 2;
828  DBG_GUI_L << LOG_CHILD_HEADER << " vertically centered.\n";
829 
830  } else if(v_flag == VERTICAL_ALIGN_BOTTOM) {
831 
832  widget_orig.y += (size.y - widget_size.y);
833  DBG_GUI_L << LOG_CHILD_HEADER << " vertically aligned at the bottom.\n";
834 
835  } else {
836  ERR_GUI_L << LOG_CHILD_HEADER << " Invalid vertical alignment '"
837  << v_flag << "' specified.\n";
838  assert(false);
839  }
840 
841  const unsigned h_flag = flags_ & HORIZONTAL_MASK;
842 
843  if(h_flag == HORIZONTAL_GROW_SEND_TO_CLIENT) {
844  if(maximum_size.x) {
845  widget_size.x = std::min(size.x, maximum_size.x);
846  } else {
847  widget_size.x = size.x;
848  }
849  DBG_GUI_L << LOG_CHILD_HEADER << " horizontal growing from "
850  << best_size.x << " to " << widget_size.x << ".\n";
851 
852  } else if(h_flag == HORIZONTAL_ALIGN_LEFT) {
853  // Do nothing.
854  DBG_GUI_L << LOG_CHILD_HEADER << " horizontally aligned at the left.\n";
855 
856  } else if(h_flag == HORIZONTAL_ALIGN_CENTER) {
857 
858  widget_orig.x += (size.x - widget_size.x) / 2;
859  DBG_GUI_L << LOG_CHILD_HEADER << " horizontally centered.\n";
860 
861  } else if(h_flag == HORIZONTAL_ALIGN_RIGHT) {
862 
863  widget_orig.x += (size.x - widget_size.x);
865  << " horizontally aligned at the right.\n";
866 
867  } else {
868  ERR_GUI_L << LOG_CHILD_HEADER << " No horizontal alignment '" << h_flag
869  << "' specified.\n";
870  assert(false);
871  }
872 
873  DBG_GUI_L << LOG_CHILD_HEADER << " resize widget to " << widget_orig
874  << " x " << widget_size << ".\n";
875 
876  get_widget()->place(widget_orig, widget_size);
877 }
878 
879 void grid::child::layout_initialize(const bool full_initialization)
880 {
881  assert(widget_);
882 
883  if(widget_->get_visible() != widget::visibility::invisible) {
884  widget_->layout_initialize(full_initialization);
885  }
886 }
887 
888 const std::string& grid::child::id() const
889 {
890  assert(widget_);
891  return widget_->id();
892 }
893 
895 {
896  point result(0, 0);
897 
898  if(border_size_) {
899 
900  if(flags_ & BORDER_TOP)
901  result.y += border_size_;
902  if(flags_ & BORDER_BOTTOM)
903  result.y += border_size_;
904 
905  if(flags_ & BORDER_LEFT)
906  result.x += border_size_;
907  if(flags_ & BORDER_RIGHT)
908  result.x += border_size_;
909  }
910 
911  return result;
912 }
913 
915 {
916  if(!w) {
917  return nullptr;
918  }
919 
920  for(auto& child : children_) {
921  if(w == child.get_widget()) {
922  return &child;
923  }
924  }
925 
926  return nullptr;
927 }
928 
929 void grid::set_child_alignment(widget* widget, unsigned set_flag, unsigned mode_mask)
930 {
931  grid::child* cell = get_child(widget);
932  if(!cell) {
933  return;
934  }
935 
936  unsigned flags = cell->get_flags();
937 
938  if((flags & mode_mask) == HORIZONTAL_GROW_SEND_TO_CLIENT) {
939  ERR_GUI_G << "Cannot set horizontal alignment (grid cell specifies dynamic growth)" << std::endl;
940  return;
941  }
942 
943  if((flags & mode_mask) == VERTICAL_GROW_SEND_TO_CLIENT) {
944  ERR_GUI_G << "Cannot set vertical alignment (grid cell specifies dynamic growth)" << std::endl;
945  return;
946  }
947 
948  flags &= ~mode_mask;
949  flags |= set_flag;
950 
951  cell->set_flags(flags);
952 
954  fire(event::REQUEST_PLACEMENT, *this, message);
955 }
956 
957 void grid::layout(const point& origin)
958 {
959  point orig = origin;
960  for(unsigned row = 0; row < rows_; ++row) {
961  for(unsigned col = 0; col < cols_; ++col) {
962 
963  const point size(col_width_[col], row_height_[row]);
964  DBG_GUI_L << LOG_HEADER << " set widget at " << row << ',' << col
965  << " at origin " << orig << " with size " << size
966  << ".\n";
967 
968  if(get_child(row, col).get_widget()) {
969  get_child(row, col).place(orig, size);
970  }
971 
972  orig.x += col_width_[col];
973  }
974  orig.y += row_height_[row];
975  orig.x = origin.x;
976  }
977 }
978 
980 {
981  /*
982  * The call to SDL_PumpEvents seems a bit like black magic.
983  * With the call the resizing doesn't seem to lose resize events.
984  * But when added the queue still only contains one resize event and the
985  * internal SDL queue doesn't seem to overflow (rarely more than 50 pending
986  * events).
987  * Without the call when resizing larger a black area of remains, this is
988  * the area not used for resizing the screen, this call `fixes' that.
989  */
990 
992 
993  for(auto & child : children_)
994  {
995 
997  assert(widget);
998 
999  if(widget->get_visible() != widget::visibility::visible) {
1000  continue;
1001  }
1002 
1004  continue;
1005  }
1006 
1007  widget->draw_background();
1008  widget->draw_children();
1009  widget->draw_foreground();
1010  }
1011 }
1012 
1014  grid& grid, const unsigned row, const unsigned maximum_height)
1015 {
1016  // The minimum height required.
1017  unsigned required_height = 0;
1018 
1019  for(std::size_t x = 0; x < grid.cols_; ++x) {
1020  grid::child& cell = grid.get_child(row, x);
1021  cell_request_reduce_height(cell, maximum_height);
1022 
1023  const point size(cell.get_best_size());
1024 
1025  if(required_height == 0 || static_cast<std::size_t>(size.y)
1026  > required_height) {
1027 
1028  required_height = size.y;
1029  }
1030  }
1031 
1032  DBG_GUI_L << LOG_IMPL_HEADER << " maximum row height " << maximum_height
1033  << " returning " << required_height << ".\n";
1034 
1035  return required_height;
1036 }
1037 
1039  grid& grid, const unsigned column, const unsigned maximum_width)
1040 {
1041  // The minimum width required.
1042  unsigned required_width = 0;
1043 
1044  for(std::size_t y = 0; y < grid.rows_; ++y) {
1045  grid::child& cell = grid.get_child(y, column);
1046  cell_request_reduce_width(cell, maximum_width);
1047 
1048  const point size(cell.get_best_size());
1049 
1050  if(required_width == 0 || static_cast<std::size_t>(size.x)
1051  > required_width) {
1052 
1053  required_width = size.x;
1054  }
1055  }
1056 
1057  DBG_GUI_L << LOG_IMPL_HEADER << " maximum column width " << maximum_width
1058  << " returning " << required_width << ".\n";
1059 
1060  return required_width;
1061 }
1062 
1063 void
1065  const unsigned maximum_height)
1066 {
1067  assert(child.widget_);
1068 
1069  if(child.widget_->get_visible() == widget::visibility::invisible) {
1070  return;
1071  }
1072 
1073  child.widget_->request_reduce_height(maximum_height
1074  - child.border_space().y);
1075 }
1076 
1077 void
1079  const unsigned maximum_width)
1080 {
1081  assert(child.widget_);
1082 
1083  if(child.widget_->get_visible() == widget::visibility::invisible) {
1084  return;
1085  }
1086 
1087  child.widget_->request_reduce_width(maximum_width - child.border_space().x);
1088 }
1089 
1091 {
1092  grid.set_rows_cols(1, 1);
1093  grid.set_child(widget,
1094  0,
1095  0,
1098  0);
1099 }
1100 
1101 } // namespace gui2
1102 
1103 
1104 /*WIKI
1105  * @page = GUILayout
1106  *
1107  * {{Autogenerated}}
1108  *
1109  * = Abstract =
1110  *
1111  * In the widget library the placement and sizes of elements is determined by
1112  * a grid. Therefore most widgets have no fixed size.
1113  *
1114  *
1115  * = Theory =
1116  *
1117  * We have two examples for the addon dialog, the first example the lower
1118  * buttons are in one grid, that means if the remove button gets wider
1119  * (due to translations) the connect button (4.1 - 2.2) will be aligned
1120  * to the left of the remove button. In the second example the connect
1121  * button will be partial underneath the remove button.
1122  *
1123  * A grid exists of x rows and y columns for all rows the number of columns
1124  * needs to be the same, there is no column (nor row) span. If spanning is
1125  * required place a nested grid to do so. In the examples every row has 1 column
1126  * but rows 3, 4 (and in the second 5) have a nested grid to add more elements
1127  * per row.
1128  *
1129  * In the grid every cell needs to have a widget, if no widget is wanted place
1130  * the special widget ''spacer''. This is a non-visible item which normally
1131  * shouldn't have a size. It is possible to give a spacer a size as well but
1132  * that is discussed elsewhere.
1133  *
1134  * Every row and column has a ''grow_factor'', since all columns in a grid are
1135  * aligned only the columns in the first row need to define their grow factor.
1136  * The grow factor is used to determine with the extra size available in a
1137  * dialog. The algorithm determines the extra size work like this:
1138  *
1139  * * determine the extra size
1140  * * determine the sum of the grow factors
1141  * * if this sum is 0 set the grow factor for every item to 1 and sum to sum of items.
1142  * * divide the extra size with the sum of grow factors
1143  * * for every item multiply the grow factor with the division value
1144  *
1145  * eg
1146  * extra size 100
1147  * grow factors 1, 1, 2, 1
1148  * sum 5
1149  * division 100 / 5 = 20
1150  * extra sizes 20, 20, 40, 20
1151  *
1152  * Since we force the factors to 1 if all zero it's not possible to have non
1153  * growing cells. This can be solved by adding an extra cell with a spacer and a
1154  * grow factor of 1. This is used for the buttons in the examples.
1155  *
1156  * Every cell has a ''border_size'' and ''border'' the ''border_size'' is the
1157  * number of pixels in the cell which aren't available for the widget. This is
1158  * used to make sure the items in different cells aren't put side to side. With
1159  * ''border'' it can be determined which sides get the border. So a border is
1160  * either 0 or ''border_size''.
1161  *
1162  * If the widget doesn't grow when there's more space available the alignment
1163  * determines where in the cell the widget is placed.
1164  *
1165  * == Examples ==
1166  *
1167  * |---------------------------------------|
1168  * | 1.1 |
1169  * |---------------------------------------|
1170  * | 2.1 |
1171  * |---------------------------------------|
1172  * | |-----------------------------------| |
1173  * | | 3.1 - 1.1 | 3.1 - 1.2 | |
1174  * | |-----------------------------------| |
1175  * |---------------------------------------|
1176  * | |-----------------------------------| |
1177  * | | 4.1 - 1.1 | 4.1 - 1.2 | 4.1 - 1.3 | |
1178  * | |-----------------------------------| |
1179  * | | 4.1 - 2.1 | 4.1 - 2.2 | 4.1 - 2.3 | |
1180  * | |-----------------------------------| |
1181  * |---------------------------------------|
1182  *
1183  *
1184  * 1.1 label : title
1185  * 2.1 label : description
1186  * 3.1 - 1.1 label : server
1187  * 3.1 - 1.2 text box : server to connect to
1188  * 4.1 - 1.1 spacer
1189  * 4.1 - 1.2 spacer
1190  * 4.1 - 1.3 button : remove addon
1191  * 4.1 - 2.1 spacer
1192  * 4.1 - 2.2 button : connect
1193  * 4.1 - 2.3 button : cancel
1194  *
1195  *
1196  * |---------------------------------------|
1197  * | 1.1 |
1198  * |---------------------------------------|
1199  * | 2.1 |
1200  * |---------------------------------------|
1201  * | |-----------------------------------| |
1202  * | | 3.1 - 1.1 | 3.1 - 1.2 | |
1203  * | |-----------------------------------| |
1204  * |---------------------------------------|
1205  * | |-----------------------------------| |
1206  * | | 4.1 - 1.1 | 4.1 - 1.2 | |
1207  * | |-----------------------------------| |
1208  * |---------------------------------------|
1209  * | |-----------------------------------| |
1210  * | | 5.1 - 1.1 | 5.1 - 1.2 | 5.1 - 2.3 | |
1211  * | |-----------------------------------| |
1212  * |---------------------------------------|
1213  *
1214  *
1215  * 1.1 label : title
1216  * 2.1 label : description
1217  * 3.1 - 1.1 label : server
1218  * 3.1 - 1.2 text box : server to connect to
1219  * 4.1 - 1.1 spacer
1220  * 4.1 - 1.2 button : remove addon
1221  * 5.1 - 1.1 spacer
1222  * 5.1 - 1.2 button : connect
1223  * 5.1 - 1.3 button : cancel
1224  *
1225  * = Praxis =
1226  *
1227  * This is the code needed to create the skeleton for the structure the extra
1228  * flags are omitted.
1229  *
1230  * [grid]
1231  * [row]
1232  * [column]
1233  * [label]
1234  * # 1.1
1235  * [/label]
1236  * [/column]
1237  * [/row]
1238  * [row]
1239  * [column]
1240  * [label]
1241  * # 2.1
1242  * [/label]
1243  * [/column]
1244  * [/row]
1245  * [row]
1246  * [column]
1247  * [grid]
1248  * [row]
1249  * [column]
1250  * [label]
1251  * # 3.1 - 1.1
1252  * [/label]
1253  * [/column]
1254  * [column]
1255  * [text_box]
1256  * # 3.1 - 1.2
1257  * [/text_box]
1258  * [/column]
1259  * [/row]
1260  * [/grid]
1261  * [/column]
1262  * [/row]
1263  * [row]
1264  * [column]
1265  * [grid]
1266  * [row]
1267  * [column]
1268  * [spacer]
1269  * # 4.1 - 1.1
1270  * [/spacer]
1271  * [/column]
1272  * [column]
1273  * [spacer]
1274  * # 4.1 - 1.2
1275  * [/spacer]
1276  * [/column]
1277  * [column]
1278  * [button]
1279  * # 4.1 - 1.3
1280  * [/button]
1281  * [/column]
1282  * [/row]
1283  * [row]
1284  * [column]
1285  * [spacer]
1286  * # 4.1 - 2.1
1287  * [/spacer]
1288  * [/column]
1289  * [column]
1290  * [button]
1291  * # 4.1 - 2.2
1292  * [/button]
1293  * [/column]
1294  * [column]
1295  * [button]
1296  * # 4.1 - 2.3
1297  * [/button]
1298  * [/column]
1299  * [/row]
1300  * [/grid]
1301  * [/column]
1302  * [/row]
1303  * [/grid]
1304  *
1305  *
1306  * [[Category: WML Reference]]
1307  * [[Category: GUI WML Reference]]
1308  */
Define the common log macros for the gui toolkit.
unsigned get_flags() const
Definition: grid.hpp:364
Defines the exception classes for the layout algorithm.
static const unsigned BORDER_TOP
Definition: grid.hpp:61
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override
See widget::set_visible_rectangle.
Definition: grid.cpp:604
int get_x() const
Definition: widget.cpp:307
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:38
#define DBG_GUI_L
Definition: log.hpp:57
void set_single_child(grid &grid, widget_ptr widget)
Sets the single child in a grid.
Definition: grid.cpp:1090
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
std::vector< unsigned > row_grow_factor_
The grow factor for all rows.
Definition: grid.hpp:501
virtual void demand_reduce_width(const unsigned maximum_width) override
See widget::demand_reduce_width.
Definition: grid.cpp:272
virtual bool can_wrap() const override
See widget::can_wrap.
Definition: grid.cpp:467
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: grid.cpp:667
visibility get_visible() const
Definition: widget.cpp:470
Main class to show messages to the user.
Definition: message.hpp:34
void set_widget(widget_ptr widget)
Acquires an owning reference to the given widget.
Definition: grid.hpp:395
unsigned cols_
The number of grid columns.
Definition: grid.hpp:490
Child item of the grid.
Definition: grid.hpp:321
const std::string & id() const
Definition: widget.cpp:106
virtual bool has_widget(const widget &widget) const override
See widget::has_widget.
Definition: grid.cpp:652
Exception thrown when the height resizing has failed.
This file contains the window object, this object is a top level container which has the event manage...
redraw_action get_drawing_action() const
Definition: widget.cpp:475
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
#define ERR_GUI_G
Definition: log.hpp:43
#define LOG_IMPL_HEADER
Definition: grid.cpp:30
lg::log_domain log_gui_layout("gui/layout")
Definition: log.hpp:56
#define h
static const unsigned HORIZONTAL_MASK
Definition: grid.hpp:59
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
Definition: grid.cpp:232
widget_ptr swap_child(const std::string &id, widget_ptr w, const bool recurse, widget *new_parent=nullptr)
Exchanges a child in the grid.
Definition: grid.cpp:99
point recalculate_best_size()
Recalculates the best size.
Definition: grid.cpp:416
void draw_foreground()
Draws the foreground of the widget.
Definition: widget.cpp:417
int x
x coordinate.
Definition: point.hpp:44
Generic file dialog.
Definition: field-fwd.hpp:22
unsigned rows_
The number of grid rows.
Definition: grid.hpp:487
The message callbacks hold a reference to a message.
Definition: message.hpp:46
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: grid.cpp:186
#define ERR_GUI_L
Definition: log.hpp:60
static void cell_request_reduce_height(grid::child &child, const unsigned maximum_height)
Helper function to do the resizing of a widget.
Definition: grid.cpp:1064
Base container class.
Definition: grid.hpp:30
const grid::child & get_child(const unsigned row, const unsigned col) const
Gets the grid child in the specified cell.
Definition: grid.hpp:522
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
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:189
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:232
#define LOG_CHILD_SCOPE_HEADER
Definition: grid.cpp:32
void set_child(widget_ptr widget, const unsigned row, const unsigned col, const unsigned flags, const unsigned border_size)
Sets a child in the grid.
Definition: grid.cpp:69
std::shared_ptr< widget > widget_ptr
Definition: widget.hpp:732
void set_flags(const unsigned flags)
Definition: grid.hpp:369
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: grid.cpp:423
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:217
widget * parent()
Definition: widget.cpp:156
The widget is not visible.
static const unsigned HORIZONTAL_ALIGN_RIGHT
Definition: grid.hpp:58
static const unsigned BORDER_BOTTOM
Definition: grid.hpp:62
const std::string & id() const
Returns the id of the widget/.
Definition: grid.cpp:888
std::vector< unsigned > col_grow_factor_
The grow factor for all columns.
Definition: grid.hpp:504
virtual ~grid()
Definition: grid.cpp:54
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.
std::vector< unsigned > row_height_
The row heights in the grid.
Definition: grid.hpp:495
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:641
Exception thrown when the width resizing has failed.
#define log_scope2(domain, description)
Definition: log.hpp:187
void layout(const point &origin)
Layouts the children in the grid.
Definition: grid.cpp:957
int get_y() const
Definition: widget.cpp:312
void request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled, bool &halt)
Attempts to lay out the grid without laying out the entire window.
Definition: grid.cpp:375
void place(point origin, point size)
Places the widget in the cell.
Definition: grid.cpp:751
std::vector< child > children_
The child items.
Definition: grid.hpp:512
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: grid.cpp:480
static const unsigned VERTICAL_ALIGN_TOP
Definition: grid.hpp:49
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
Definition: grid.cpp:685
std::size_t i
Definition: function.cpp:933
#define WRN_GUI_G
Definition: log.hpp:42
static const unsigned BORDER_RIGHT
Definition: grid.hpp:64
unsigned add_row(const unsigned count=1)
Adds a row to end of the grid.
Definition: grid.cpp:58
The user set the widget invisible, that means:
#define LOG_SCOPE_HEADER
Definition: grid.cpp:28
window * get_window()
Get the parent window.
Definition: widget.cpp:113
void reduce_width(const unsigned maximum_width)
Tries to reduce the width of a container.
Definition: grid.cpp:199
double g
Definition: astarsearch.cpp:63
widget_ptr widget_
Pointer to the widget.
Definition: grid.hpp:425
void layout_initialize(const bool full_initialization)
Forwards grid::layout_initialize to the cell.
Definition: grid.cpp:879
static unsigned row_request_reduce_height(grid &grid, const unsigned row, const unsigned maximum_height)
Helper function to do the resizing of a row.
Definition: grid.cpp:1013
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:408
static const unsigned VERTICAL_ALIGN_CENTER
Definition: grid.hpp:50
bool can_wrap() const
Returns the can_wrap for the cell.
Definition: grid.hpp:356
static const unsigned HORIZONTAL_ALIGN_CENTER
Definition: grid.hpp:57
std::vector< unsigned > col_width_
The column widths in the grid.
Definition: grid.hpp:498
Holds a 2D point.
Definition: point.hpp:23
static const unsigned VERTICAL_MASK
Definition: grid.hpp:52
void set_active(const bool active)
Activates all children.
Definition: grid.cpp:163
static unsigned column_request_reduce_width(grid &grid, const unsigned column, const unsigned maximum_width)
Helper function to do the resizing of a column.
Definition: grid.cpp:1038
virtual void layout_children()
Allows a widget to update its children.
Definition: widget.cpp:287
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:55
int w
Base class for all visible items.
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:48
virtual void set_origin(const point &origin) override
See widget::set_origin.
Definition: grid.cpp:587
virtual void request_reduce_height(const unsigned maximum_height) override
See widget::request_reduce_height.
Definition: grid.cpp:310
virtual void impl_draw_children() override
See widget::impl_draw_children.
Definition: grid.cpp:979
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:708
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: grid.cpp:628
static const unsigned VERTICAL_ALIGN_BOTTOM
Definition: grid.hpp:51
widget_ptr free_widget()
Releases widget from ownership by this child and returns it in the form of a new shared_ptr.
Definition: grid.hpp:404
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:297
void set_cols(const unsigned cols)
Definition: grid.cpp:699
The user sets the widget visible, that means:
void remove_child(const unsigned row, const unsigned col)
Removes and frees a widget in a cell.
Definition: grid.cpp:141
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
virtual void set_active(const bool active)=0
Sets the styled_widget&#39;s state.
virtual void demand_reduce_height(const unsigned maximum_height) override
See widget::demand_reduce_height.
Definition: grid.cpp:370
virtual void layout_children() override
See widget::layout_children.
Definition: grid.cpp:619
Helper for header for the grid.
#define LOG_CHILD_HEADER
Definition: grid.cpp:34
void set_border_size(const unsigned border_size)
Definition: grid.hpp:379
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:66
void draw_background()
Draws the background of a widget.
Definition: widget.cpp:398
virtual bool disable_click_dismiss() const =0
Does the widget disable easy close?
static const unsigned HORIZONTAL_ALIGN_LEFT
Definition: grid.hpp:56
void set_rows(const unsigned rows)
Definition: grid.cpp:690
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
point border_space() const
Returns the space needed for the border.
Definition: grid.cpp:894
const widget * get_widget(const unsigned row, const unsigned col) const
Returns the widget in the selected cell.
Definition: grid.hpp:178
const widget * get_widget() const
Definition: grid.hpp:384
static const unsigned BORDER_LEFT
Definition: grid.hpp:63
grid(const unsigned rows=0, const unsigned cols=0)
Definition: grid.cpp:39
int y
y coordinate.
Definition: point.hpp:47
point get_best_size() const
Returns the best size for the cell.
Definition: grid.cpp:726
void reduce_height(const unsigned maximum_height)
Tries to reduce the height of a container.
Definition: grid.cpp:277
#define LOG_HEADER
Definition: grid.cpp:29
static void cell_request_reduce_width(grid::child &child, const unsigned maximum_width)
Helper function to do the resizing of a widget.
Definition: grid.cpp:1078
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:292
ui_event
The event send to the dispatcher.
Definition: handler.hpp:47
point get_config_maximum_size() const
Gets the best size as defined in the config.