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  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 
628  const std::vector<widget*>& call_stack)
629 {
630  assert(!call_stack.empty() && call_stack.back() == this);
631 
632  for(auto & child : children_)
633  {
634 
635  assert(child.get_widget());
636 
637  std::vector<widget*> child_call_stack = call_stack;
638  child.get_widget()->populate_dirty_list(caller, child_call_stack);
639  }
640 }
641 
642 widget* grid::find_at(const point& coordinate, const bool must_be_active)
643 {
644  return grid_implementation::find_at<widget>(
645  *this, coordinate, must_be_active);
646 }
647 
649  const bool must_be_active) const
650 {
651  return grid_implementation::find_at<const widget>(
652  *this, coordinate, must_be_active);
653 }
654 
655 widget* grid::find(const std::string& id, const bool must_be_active)
656 {
657  return grid_implementation::find<widget>(*this, id, must_be_active);
658 }
659 
660 const widget* grid::find(const std::string& id, const bool must_be_active)
661  const
662 {
663  return grid_implementation::find<const widget>(*this, id, must_be_active);
664 }
665 
666 bool grid::has_widget(const widget& widget) const
667 {
668  if(widget::has_widget(widget)) {
669  return true;
670  }
671 
672  for(const auto & child : children_)
673  {
674  if(child.get_widget()->has_widget(widget)) {
675  return true;
676  }
677  }
678  return false;
679 }
680 
682 {
684  return false;
685  }
686 
687  for(const auto & child : children_)
688  {
689  const widget* widget = child.get_widget();
690  assert(widget);
691 
692  if(widget->disable_click_dismiss()) {
693  return true;
694  }
695  }
696  return false;
697 }
698 
700 {
701  return new gui2::iteration::grid(*this);
702 }
703 
704 void grid::set_rows(const unsigned rows)
705 {
706  if(rows == rows_) {
707  return;
708  }
709 
710  set_rows_cols(rows, cols_);
711 }
712 
713 void grid::set_cols(const unsigned cols)
714 {
715  if(cols == cols_) {
716  return;
717  }
718 
719  set_rows_cols(rows_, cols);
720 }
721 
722 void grid::set_rows_cols(const unsigned rows, const unsigned cols)
723 {
724  if(rows == rows_ && cols == cols_) {
725  return;
726  }
727 
728  if(!children_.empty()) {
729  WRN_GUI_G << LOG_HEADER << " resizing a non-empty grid "
730  << " may give unexpected problems.\n";
731  }
732 
733  rows_ = rows;
734  cols_ = cols;
735  row_grow_factor_.resize(rows);
736  col_grow_factor_.resize(cols);
737  children_.resize(rows_ * cols_);
738 }
739 
741 {
743 
744  if(!widget_) {
745  DBG_GUI_L << LOG_CHILD_HEADER << " has widget " << false
746  << " returning " << border_space() << ".\n";
747  return border_space();
748  }
749 
750  if(widget_->get_visible() == widget::visibility::invisible) {
751  DBG_GUI_L << LOG_CHILD_HEADER << " has widget " << true
752  << " widget visible " << false << " returning 0,0"
753  << ".\n";
754  return point();
755  }
756 
757  const point best_size = widget_->get_best_size() + border_space();
758 
759  DBG_GUI_L << LOG_CHILD_HEADER << " has widget " << true
760  << " widget visible " << true << " returning " << best_size
761  << ".\n";
762  return best_size;
763 }
764 
766 {
767  assert(get_widget());
769  return;
770  }
771 
772  if(border_size_) {
773  if(flags_ & BORDER_TOP) {
774  origin.y += border_size_;
775  size.y -= border_size_;
776  }
777  if(flags_ & BORDER_BOTTOM) {
778  size.y -= border_size_;
779  }
780 
781  if(flags_ & BORDER_LEFT) {
782  origin.x += border_size_;
783  size.x -= border_size_;
784  }
785  if(flags_ & BORDER_RIGHT) {
786  size.x -= border_size_;
787  }
788  }
789 
790  // If size smaller or equal to best size set that size.
791  // No need to check > min size since this is what we got.
792  const point best_size = get_widget()->get_best_size();
793  if(size <= best_size) {
795  << " in best size range setting widget to " << origin << " x "
796  << size << ".\n";
797 
798  get_widget()->place(origin, size);
799  return;
800  }
801 
802  const styled_widget* control = dynamic_cast<const styled_widget*>(get_widget());
803  const point maximum_size = control ? control->get_config_maximum_size()
804  : point();
805 
806  if((flags_ & (HORIZONTAL_MASK | VERTICAL_MASK))
808 
809  if(maximum_size == point() || size <= maximum_size) {
810 
812  << " in maximum size range setting widget to " << origin
813  << " x " << size << ".\n";
814 
815  get_widget()->place(origin, size);
816  return;
817  }
818  }
819 
820  point widget_size = point(std::min(size.x, best_size.x), std::min(size.y, best_size.y));
821  point widget_orig = origin;
822 
823  const unsigned v_flag = flags_ & VERTICAL_MASK;
824 
825  if(v_flag == VERTICAL_GROW_SEND_TO_CLIENT) {
826  if(maximum_size.y) {
827  widget_size.y = std::min(size.y, maximum_size.y);
828  } else {
829  widget_size.y = size.y;
830  }
831  DBG_GUI_L << LOG_CHILD_HEADER << " vertical growing from "
832  << best_size.y << " to " << widget_size.y << ".\n";
833 
834  } else if(v_flag == VERTICAL_ALIGN_TOP) {
835  // Do nothing.
836 
837  DBG_GUI_L << LOG_CHILD_HEADER << " vertically aligned at the top.\n";
838 
839  } else if(v_flag == VERTICAL_ALIGN_CENTER) {
840 
841  widget_orig.y += (size.y - widget_size.y) / 2;
842  DBG_GUI_L << LOG_CHILD_HEADER << " vertically centered.\n";
843 
844  } else if(v_flag == VERTICAL_ALIGN_BOTTOM) {
845 
846  widget_orig.y += (size.y - widget_size.y);
847  DBG_GUI_L << LOG_CHILD_HEADER << " vertically aligned at the bottom.\n";
848 
849  } else {
850  ERR_GUI_L << LOG_CHILD_HEADER << " Invalid vertical alignment '"
851  << v_flag << "' specified.\n";
852  assert(false);
853  }
854 
855  const unsigned h_flag = flags_ & HORIZONTAL_MASK;
856 
857  if(h_flag == HORIZONTAL_GROW_SEND_TO_CLIENT) {
858  if(maximum_size.x) {
859  widget_size.x = std::min(size.x, maximum_size.x);
860  } else {
861  widget_size.x = size.x;
862  }
863  DBG_GUI_L << LOG_CHILD_HEADER << " horizontal growing from "
864  << best_size.x << " to " << widget_size.x << ".\n";
865 
866  } else if(h_flag == HORIZONTAL_ALIGN_LEFT) {
867  // Do nothing.
868  DBG_GUI_L << LOG_CHILD_HEADER << " horizontally aligned at the left.\n";
869 
870  } else if(h_flag == HORIZONTAL_ALIGN_CENTER) {
871 
872  widget_orig.x += (size.x - widget_size.x) / 2;
873  DBG_GUI_L << LOG_CHILD_HEADER << " horizontally centered.\n";
874 
875  } else if(h_flag == HORIZONTAL_ALIGN_RIGHT) {
876 
877  widget_orig.x += (size.x - widget_size.x);
879  << " horizontally aligned at the right.\n";
880 
881  } else {
882  ERR_GUI_L << LOG_CHILD_HEADER << " No horizontal alignment '" << h_flag
883  << "' specified.\n";
884  assert(false);
885  }
886 
887  DBG_GUI_L << LOG_CHILD_HEADER << " resize widget to " << widget_orig
888  << " x " << widget_size << ".\n";
889 
890  get_widget()->place(widget_orig, widget_size);
891 }
892 
893 void grid::child::layout_initialize(const bool full_initialization)
894 {
895  assert(widget_);
896 
897  if(widget_->get_visible() != widget::visibility::invisible) {
898  widget_->layout_initialize(full_initialization);
899  }
900 }
901 
902 const std::string& grid::child::id() const
903 {
904  assert(widget_);
905  return widget_->id();
906 }
907 
909 {
910  point result(0, 0);
911 
912  if(border_size_) {
913 
914  if(flags_ & BORDER_TOP)
915  result.y += border_size_;
916  if(flags_ & BORDER_BOTTOM)
917  result.y += border_size_;
918 
919  if(flags_ & BORDER_LEFT)
920  result.x += border_size_;
921  if(flags_ & BORDER_RIGHT)
922  result.x += border_size_;
923  }
924 
925  return result;
926 }
927 
929 {
930  if(!w) {
931  return nullptr;
932  }
933 
934  for(auto& child : children_) {
935  if(w == child.get_widget()) {
936  return &child;
937  }
938  }
939 
940  return nullptr;
941 }
942 
943 void grid::set_child_alignment(widget* widget, unsigned set_flag, unsigned mode_mask)
944 {
945  grid::child* cell = get_child(widget);
946  if(!cell) {
947  return;
948  }
949 
950  unsigned flags = cell->get_flags();
951 
952  if((flags & mode_mask) == HORIZONTAL_GROW_SEND_TO_CLIENT) {
953  ERR_GUI_G << "Cannot set horizontal alignment (grid cell specifies dynamic growth)" << std::endl;
954  return;
955  }
956 
957  if((flags & mode_mask) == VERTICAL_GROW_SEND_TO_CLIENT) {
958  ERR_GUI_G << "Cannot set vertical alignment (grid cell specifies dynamic growth)" << std::endl;
959  return;
960  }
961 
962  flags &= ~mode_mask;
963  flags |= set_flag;
964 
965  cell->set_flags(flags);
966 
968  fire(event::REQUEST_PLACEMENT, *this, message);
969 }
970 
971 void grid::layout(const point& origin)
972 {
973  point orig = origin;
974  for(unsigned row = 0; row < rows_; ++row) {
975  for(unsigned col = 0; col < cols_; ++col) {
976 
977  const point size(col_width_[col], row_height_[row]);
978  DBG_GUI_L << LOG_HEADER << " set widget at " << row << ',' << col
979  << " at origin " << orig << " with size " << size
980  << ".\n";
981 
982  if(get_child(row, col).get_widget()) {
983  get_child(row, col).place(orig, size);
984  }
985 
986  orig.x += col_width_[col];
987  }
988  orig.y += row_height_[row];
989  orig.x = origin.x;
990  }
991 }
992 
993 void grid::impl_draw_children(surface& frame_buffer, int x_offset, int y_offset)
994 {
995  /*
996  * The call to SDL_PumpEvents seems a bit like black magic.
997  * With the call the resizing doesn't seem to lose resize events.
998  * But when added the queue still only contains one resize event and the
999  * internal SDL queue doesn't seem to overflow (rarely more than 50 pending
1000  * events).
1001  * Without the call when resizing larger a black area of remains, this is
1002  * the area not used for resizing the screen, this call `fixes' that.
1003  */
1004 
1006  set_is_dirty(false);
1007 
1008  for(auto & child : children_)
1009  {
1010 
1012  assert(widget);
1013 
1014  if(widget->get_visible() != widget::visibility::visible) {
1015  continue;
1016  }
1017 
1019  continue;
1020  }
1021 
1022  widget->draw_background(frame_buffer, x_offset, y_offset);
1023  widget->draw_children(frame_buffer, x_offset, y_offset);
1024  widget->draw_foreground(frame_buffer, x_offset, y_offset);
1025  widget->set_is_dirty(false);
1026  }
1027 }
1028 
1030  grid& grid, const unsigned row, const unsigned maximum_height)
1031 {
1032  // The minimum height required.
1033  unsigned required_height = 0;
1034 
1035  for(std::size_t x = 0; x < grid.cols_; ++x) {
1036  grid::child& cell = grid.get_child(row, x);
1037  cell_request_reduce_height(cell, maximum_height);
1038 
1039  const point size(cell.get_best_size());
1040 
1041  if(required_height == 0 || static_cast<std::size_t>(size.y)
1042  > required_height) {
1043 
1044  required_height = size.y;
1045  }
1046  }
1047 
1048  DBG_GUI_L << LOG_IMPL_HEADER << " maximum row height " << maximum_height
1049  << " returning " << required_height << ".\n";
1050 
1051  return required_height;
1052 }
1053 
1055  grid& grid, const unsigned column, const unsigned maximum_width)
1056 {
1057  // The minimum width required.
1058  unsigned required_width = 0;
1059 
1060  for(std::size_t y = 0; y < grid.rows_; ++y) {
1061  grid::child& cell = grid.get_child(y, column);
1062  cell_request_reduce_width(cell, maximum_width);
1063 
1064  const point size(cell.get_best_size());
1065 
1066  if(required_width == 0 || static_cast<std::size_t>(size.x)
1067  > required_width) {
1068 
1069  required_width = size.x;
1070  }
1071  }
1072 
1073  DBG_GUI_L << LOG_IMPL_HEADER << " maximum column width " << maximum_width
1074  << " returning " << required_width << ".\n";
1075 
1076  return required_width;
1077 }
1078 
1079 void
1081  const unsigned maximum_height)
1082 {
1083  assert(child.widget_);
1084 
1085  if(child.widget_->get_visible() == widget::visibility::invisible) {
1086  return;
1087  }
1088 
1089  child.widget_->request_reduce_height(maximum_height
1090  - child.border_space().y);
1091 }
1092 
1093 void
1095  const unsigned maximum_width)
1096 {
1097  assert(child.widget_);
1098 
1099  if(child.widget_->get_visible() == widget::visibility::invisible) {
1100  return;
1101  }
1102 
1103  child.widget_->request_reduce_width(maximum_width - child.border_space().x);
1104 }
1105 
1107 {
1108  grid.set_rows_cols(1, 1);
1109  grid.set_child(widget,
1110  0,
1111  0,
1114  0);
1115 }
1116 
1117 } // namespace gui2
1118 
1119 
1120 /*WIKI
1121  * @page = GUILayout
1122  *
1123  * {{Autogenerated}}
1124  *
1125  * = Abstract =
1126  *
1127  * In the widget library the placement and sizes of elements is determined by
1128  * a grid. Therefore most widgets have no fixed size.
1129  *
1130  *
1131  * = Theory =
1132  *
1133  * We have two examples for the addon dialog, the first example the lower
1134  * buttons are in one grid, that means if the remove button gets wider
1135  * (due to translations) the connect button (4.1 - 2.2) will be aligned
1136  * to the left of the remove button. In the second example the connect
1137  * button will be partial underneath the remove button.
1138  *
1139  * A grid exists of x rows and y columns for all rows the number of columns
1140  * needs to be the same, there is no column (nor row) span. If spanning is
1141  * required place a nested grid to do so. In the examples every row has 1 column
1142  * but rows 3, 4 (and in the second 5) have a nested grid to add more elements
1143  * per row.
1144  *
1145  * In the grid every cell needs to have a widget, if no widget is wanted place
1146  * the special widget ''spacer''. This is a non-visible item which normally
1147  * shouldn't have a size. It is possible to give a spacer a size as well but
1148  * that is discussed elsewhere.
1149  *
1150  * Every row and column has a ''grow_factor'', since all columns in a grid are
1151  * aligned only the columns in the first row need to define their grow factor.
1152  * The grow factor is used to determine with the extra size available in a
1153  * dialog. The algorithm determines the extra size work like this:
1154  *
1155  * * determine the extra size
1156  * * determine the sum of the grow factors
1157  * * if this sum is 0 set the grow factor for every item to 1 and sum to sum of items.
1158  * * divide the extra size with the sum of grow factors
1159  * * for every item multiply the grow factor with the division value
1160  *
1161  * eg
1162  * extra size 100
1163  * grow factors 1, 1, 2, 1
1164  * sum 5
1165  * division 100 / 5 = 20
1166  * extra sizes 20, 20, 40, 20
1167  *
1168  * Since we force the factors to 1 if all zero it's not possible to have non
1169  * growing cells. This can be solved by adding an extra cell with a spacer and a
1170  * grow factor of 1. This is used for the buttons in the examples.
1171  *
1172  * Every cell has a ''border_size'' and ''border'' the ''border_size'' is the
1173  * number of pixels in the cell which aren't available for the widget. This is
1174  * used to make sure the items in different cells aren't put side to side. With
1175  * ''border'' it can be determined which sides get the border. So a border is
1176  * either 0 or ''border_size''.
1177  *
1178  * If the widget doesn't grow when there's more space available the alignment
1179  * determines where in the cell the widget is placed.
1180  *
1181  * == Examples ==
1182  *
1183  * |---------------------------------------|
1184  * | 1.1 |
1185  * |---------------------------------------|
1186  * | 2.1 |
1187  * |---------------------------------------|
1188  * | |-----------------------------------| |
1189  * | | 3.1 - 1.1 | 3.1 - 1.2 | |
1190  * | |-----------------------------------| |
1191  * |---------------------------------------|
1192  * | |-----------------------------------| |
1193  * | | 4.1 - 1.1 | 4.1 - 1.2 | 4.1 - 1.3 | |
1194  * | |-----------------------------------| |
1195  * | | 4.1 - 2.1 | 4.1 - 2.2 | 4.1 - 2.3 | |
1196  * | |-----------------------------------| |
1197  * |---------------------------------------|
1198  *
1199  *
1200  * 1.1 label : title
1201  * 2.1 label : description
1202  * 3.1 - 1.1 label : server
1203  * 3.1 - 1.2 text box : server to connect to
1204  * 4.1 - 1.1 spacer
1205  * 4.1 - 1.2 spacer
1206  * 4.1 - 1.3 button : remove addon
1207  * 4.1 - 2.1 spacer
1208  * 4.1 - 2.2 button : connect
1209  * 4.1 - 2.3 button : cancel
1210  *
1211  *
1212  * |---------------------------------------|
1213  * | 1.1 |
1214  * |---------------------------------------|
1215  * | 2.1 |
1216  * |---------------------------------------|
1217  * | |-----------------------------------| |
1218  * | | 3.1 - 1.1 | 3.1 - 1.2 | |
1219  * | |-----------------------------------| |
1220  * |---------------------------------------|
1221  * | |-----------------------------------| |
1222  * | | 4.1 - 1.1 | 4.1 - 1.2 | |
1223  * | |-----------------------------------| |
1224  * |---------------------------------------|
1225  * | |-----------------------------------| |
1226  * | | 5.1 - 1.1 | 5.1 - 1.2 | 5.1 - 2.3 | |
1227  * | |-----------------------------------| |
1228  * |---------------------------------------|
1229  *
1230  *
1231  * 1.1 label : title
1232  * 2.1 label : description
1233  * 3.1 - 1.1 label : server
1234  * 3.1 - 1.2 text box : server to connect to
1235  * 4.1 - 1.1 spacer
1236  * 4.1 - 1.2 button : remove addon
1237  * 5.1 - 1.1 spacer
1238  * 5.1 - 1.2 button : connect
1239  * 5.1 - 1.3 button : cancel
1240  *
1241  * = Praxis =
1242  *
1243  * This is the code needed to create the skeleton for the structure the extra
1244  * flags are omitted.
1245  *
1246  * [grid]
1247  * [row]
1248  * [column]
1249  * [label]
1250  * # 1.1
1251  * [/label]
1252  * [/column]
1253  * [/row]
1254  * [row]
1255  * [column]
1256  * [label]
1257  * # 2.1
1258  * [/label]
1259  * [/column]
1260  * [/row]
1261  * [row]
1262  * [column]
1263  * [grid]
1264  * [row]
1265  * [column]
1266  * [label]
1267  * # 3.1 - 1.1
1268  * [/label]
1269  * [/column]
1270  * [column]
1271  * [text_box]
1272  * # 3.1 - 1.2
1273  * [/text_box]
1274  * [/column]
1275  * [/row]
1276  * [/grid]
1277  * [/column]
1278  * [/row]
1279  * [row]
1280  * [column]
1281  * [grid]
1282  * [row]
1283  * [column]
1284  * [spacer]
1285  * # 4.1 - 1.1
1286  * [/spacer]
1287  * [/column]
1288  * [column]
1289  * [spacer]
1290  * # 4.1 - 1.2
1291  * [/spacer]
1292  * [/column]
1293  * [column]
1294  * [button]
1295  * # 4.1 - 1.3
1296  * [/button]
1297  * [/column]
1298  * [/row]
1299  * [row]
1300  * [column]
1301  * [spacer]
1302  * # 4.1 - 2.1
1303  * [/spacer]
1304  * [/column]
1305  * [column]
1306  * [button]
1307  * # 4.1 - 2.2
1308  * [/button]
1309  * [/column]
1310  * [column]
1311  * [button]
1312  * # 4.1 - 2.3
1313  * [/button]
1314  * [/column]
1315  * [/row]
1316  * [/grid]
1317  * [/column]
1318  * [/row]
1319  * [/grid]
1320  *
1321  *
1322  * [[Category: WML Reference]]
1323  * [[Category: GUI WML Reference]]
1324  */
Define the common log macros for the gui toolkit.
unsigned get_flags() const
Definition: grid.hpp:371
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:312
void set_parent(widget *parent)
Definition: widget.cpp:152
#define DBG_GUI_L
Definition: log.hpp:57
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:164
void set_layout_size(const point &size)
Definition: widget.cpp:332
std::vector< unsigned > row_grow_factor_
The grow factor for all rows.
Definition: grid.hpp:507
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:681
visibility get_visible() const
Definition: widget.cpp:500
Main class to show messages to the user.
Definition: message.hpp:34
std::unique_ptr< widget > widget_
Pointer to the widget.
Definition: grid.hpp:434
unsigned cols_
The number of grid columns.
Definition: grid.hpp:496
Child item of the grid.
Definition: grid.hpp:328
const std::string & id() const
Definition: widget.cpp:107
virtual bool has_widget(const widget &widget) const override
See widget::has_widget.
Definition: grid.cpp:666
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:505
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:450
#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:493
The message callbacks hold a reference to a message.
Definition: message.hpp:45
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:1080
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:528
void populate_dirty_list(window &caller, std::vector< widget *> &call_stack)
Adds a widget to the dirty list if it is dirty.
Definition: widget.cpp:414
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:102
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:190
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:235
#define LOG_CHILD_SCOPE_HEADER
Definition: grid.cpp:32
void set_visible(const visibility visible)
Definition: widget.cpp:473
void set_flags(const unsigned flags)
Definition: grid.hpp:376
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: grid.cpp:422
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:463
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:218
widget * parent()
Definition: widget.cpp:157
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:902
std::vector< unsigned > col_grow_factor_
The grow factor for all columns.
Definition: grid.hpp:510
virtual ~grid()
Definition: grid.cpp:54
virtual bool has_widget(const widget &widget) const
Does the widget contain the widget.
Definition: widget.cpp:592
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:501
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:410
void draw_background(surface &frame_buffer, int x_offset, int y_offset)
Draws the background of a widget.
Definition: widget.cpp:367
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:655
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:971
int get_y() const
Definition: widget.cpp:317
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:765
std::vector< child > children_
The child items.
Definition: grid.hpp:518
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:699
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:114
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:401
double g
Definition: astarsearch.cpp:64
void layout_initialize(const bool full_initialization)
Forwards grid::layout_initialize to the cell.
Definition: grid.cpp:893
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:1029
static const unsigned VERTICAL_ALIGN_CENTER
Definition: grid.hpp:50
bool can_wrap() const
Returns the can_wrap for the cell.
Definition: grid.hpp:363
static const unsigned HORIZONTAL_ALIGN_CENTER
Definition: grid.hpp:57
std::vector< unsigned > col_width_
The column widths in the grid.
Definition: grid.hpp:504
virtual void child_populate_dirty_list(window &caller, const std::vector< widget *> &call_stack) override
See widget::child_populate_dirty_list.
Definition: grid.cpp:627
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:1054
virtual void layout_children()
Allows a widget to update its children.
Definition: widget.cpp:292
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:1106
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:722
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: grid.cpp:642
bool grid()
Definition: general.cpp:505
static const unsigned VERTICAL_ALIGN_BOTTOM
Definition: grid.hpp:51
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:302
void set_cols(const unsigned cols)
Definition: grid.cpp:713
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:943
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 draw_foreground(surface &frame_buffer, int x_offset, int y_offset)
Draws the foreground of the widget.
Definition: widget.cpp:399
void set_border_size(const unsigned border_size)
Definition: grid.hpp:386
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:130
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:704
void draw_children(surface &frame_buffer, int x_offset, int y_offset)
Draws the children of a widget.
Definition: widget.cpp:384
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:213
point border_space() const
Returns the space needed for the border.
Definition: grid.cpp:908
const widget * get_widget(const unsigned row, const unsigned col) const
Returns the widget in the selected cell.
Definition: grid.hpp:180
const widget * get_widget() const
Definition: grid.hpp:391
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
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:63
point get_best_size() const
Returns the best size for the cell.
Definition: grid.cpp:740
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 std::deque< std::string > call_stack
Definition: function.cpp:39
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:1094
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:297
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55
point get_config_maximum_size() const
Gets the best size as defined in the config.
virtual void impl_draw_children(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_children.
Definition: grid.cpp:993