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