The Battle for Wesnoth  1.15.0-dev
window.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Implementation of window.hpp.
18  */
19 
20 #define GETTEXT_DOMAIN "wesnoth-lib"
21 
23 
24 #include "config.hpp"
25 #include "cursor.hpp"
26 #include "events.hpp"
27 #include "floating_label.hpp"
28 #include "formula/callable.hpp"
29 #include "gettext.hpp"
30 #include "log.hpp"
36 #include "gui/core/log.hpp"
38 #include "sdl/point.hpp"
41 #include "gui/dialogs/tooltip.hpp"
42 #include "gui/widgets/button.hpp"
46 #include "gui/widgets/grid.hpp"
47 #include "gui/widgets/helper.hpp"
48 #include "gui/widgets/panel.hpp"
49 #include "gui/widgets/settings.hpp"
50 #include "gui/widgets/widget.hpp"
51 #include "gui/widgets/window.hpp"
52 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
53 #include "gui/widgets/debug.hpp"
54 #endif
55 #include "preferences/general.hpp"
56 #include "preferences/display.hpp"
57 #include "sdl/rect.hpp"
58 #include "sdl/surface.hpp"
59 #include "formula/variant.hpp"
60 #include "video.hpp"
61 #include "wml_exception.hpp"
62 #include "sdl/userevent.hpp"
63 
64 #include "utils/functional.hpp"
65 
66 #include <algorithm>
67 #include <iterator>
68 #include <stdexcept>
69 
70 namespace wfl { class function_symbol_table; }
71 namespace gui2 { class button; }
72 
73 static lg::log_domain log_gui("gui/layout");
74 #define ERR_GUI LOG_STREAM(err, log_gui)
75 
76 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
77 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
78 
79 #define LOG_IMPL_SCOPE_HEADER \
80  window.get_control_type() + " [" + window.id() + "] " + __func__
81 #define LOG_IMPL_HEADER LOG_IMPL_SCOPE_HEADER + ':'
82 
83 namespace gui2
84 {
85 
86 // ------------ WIDGET -----------{
87 
88 namespace implementation
89 {
90 /** @todo See whether this hack can be removed. */
91 // Needed to fix a compiler error in REGISTER_WIDGET.
93 {
94 public:
96  {
97  }
98 
99  using builder_styled_widget::build;
100 
101  virtual widget_ptr build() const override
102  {
103  return nullptr;
104  }
105 };
106 
107 } // namespace implementation
109 
110 namespace
111 {
112 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
113 const unsigned SHOW = debug_layout_graph::SHOW;
114 const unsigned LAYOUT = debug_layout_graph::LAYOUT;
115 #else
116 // values are irrelevant when DEBUG_WINDOW_LAYOUT_GRAPHS is not defined.
117 const unsigned SHOW = 0;
118 const unsigned LAYOUT = 0;
119 #endif
120 
121 /**
122 
123  * SDL_AddTimer() callback for delay_event.
124  *
125  * @param event The event to push in the event queue.
126  *
127  * @return The new timer interval (always 0).
128  */
129 static uint32_t delay_event_callback(const uint32_t, void* event)
130 {
131  SDL_PushEvent(static_cast<SDL_Event*>(event));
132  delete static_cast<SDL_Event*>(event);
133  return 0;
134 }
135 
136 /**
137  * Allows an event to be delayed a certain amount of time.
138  *
139  * @note the delay is the minimum time, after the time has passed the event
140  * will be pushed in the SDL event queue, so it might delay more.
141  *
142  * @param event The event to delay.
143  * @param delay The number of ms to delay the event.
144  */
145 static void delay_event(const SDL_Event& event, const uint32_t delay)
146 {
147  SDL_AddTimer(delay, delay_event_callback, new SDL_Event(event));
148 }
149 
150 /**
151  * Adds a SHOW_HELPTIP event to the SDL event queue.
152  *
153  * The event is used to show the helptip for the currently focused widget.
154  */
155 static void helptip()
156 {
157  DBG_GUI_E << "Pushing SHOW_HELPTIP_EVENT event in queue.\n";
158 
159  SDL_Event event;
161 
162  event.type = SHOW_HELPTIP_EVENT;
163  event.user = data;
164 
165  SDL_PushEvent(&event);
166 }
167 
168 /**
169  * Small helper class to get an unique id for every window instance.
170  *
171  * This is used to send event to the proper window, this allows windows to post
172  * messages to themselves and let them delay for a certain amount of time.
173  */
174 class manager
175 {
176  manager();
177 
178 public:
179  static manager& instance();
180 
181  void add(window& window);
182 
183  void remove(window& window);
184 
185  unsigned get_id(window& window);
186 
187  window* get_window(const unsigned id);
188 
189 private:
190  // The number of active window should be rather small
191  // so keep it simple and don't add a reverse lookup map.
192  std::map<unsigned, window*> windows_;
193 };
194 
196 {
197 }
198 
199 manager& manager::instance()
200 {
201  static manager window_manager;
202  return window_manager;
203 }
204 
205 void manager::add(window& win)
206 {
207  static unsigned id;
208  ++id;
209  windows_[id] = &win;
210 }
211 
212 void manager::remove(window& win)
213 {
215  itor != windows_.end();
216  ++itor) {
217 
218  if(itor->second == &win) {
219  windows_.erase(itor);
220  return;
221  }
222  }
223  assert(false);
224 }
225 
226 unsigned manager::get_id(window& win)
227 {
229  itor != windows_.end();
230  ++itor) {
231 
232  if(itor->second == &win) {
233  return itor->first;
234  }
235  }
236  assert(false);
237 
238  return 0;
239 }
240 
241 window* manager::get_window(const unsigned id)
242 {
244 
245  if(itor == windows_.end()) {
246  return nullptr;
247  } else {
248  return itor->second;
249  }
250 }
251 
252 } // namespace
253 
254 window::window(const builder_window::window_resolution* definition)
255  : panel(implementation::builder_window(::config {"definition", definition->definition}), type())
258  , status_(NEW)
259  , show_mode_(none)
261  , owner_(nullptr)
262  , need_layout_(true)
263  , variables_()
265  , suspend_drawing_(true)
266  , automatic_placement_(definition->automatic_placement)
267  , horizontal_placement_(definition->horizontal_placement)
268  , vertical_placement_(definition->vertical_placement)
269  , maximum_width_(definition->maximum_width)
270  , maximum_height_(definition->maximum_height)
271  , x_(definition->x)
272  , y_(definition->y)
273  , w_(definition->width)
274  , h_(definition->height)
275  , reevaluate_best_size_(definition->reevaluate_best_size)
276  , functions_(definition->functions)
277  , tooltip_(definition->tooltip)
278  , helptip_(definition->helptip)
279  , click_dismiss_(false)
280  , enter_disabled_(false)
281  , escape_disabled_(false)
282  , linked_size_()
283  , mouse_button_state_(0) /**< Needs to be initialized in @ref show. */
284 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
285  , debug_layout_(new debug_layout_graph(this))
286 #endif
288  , exit_hook_([](window&)->bool { return true; })
289  , callback_next_draw_(nullptr)
290 {
291  manager::instance().add(*this);
292 
293  connect();
294 
295  if(!video_.faked() && !video_.non_interactive()) {
296  connect_signal<event::DRAW>(std::bind(&window::draw, this));
297  }
298 
299  connect_signal<event::SDL_VIDEO_RESIZE>(std::bind(
300  &window::signal_handler_sdl_video_resize, this, _2, _3, _5));
301 
302  connect_signal<event::SDL_ACTIVATE>(std::bind(
304 
305  connect_signal<event::SDL_LEFT_BUTTON_UP>(
307  this,
308  _2,
309  _3,
310  _4,
311  SDL_BUTTON_LMASK),
313  connect_signal<event::SDL_MIDDLE_BUTTON_UP>(
315  this,
316  _2,
317  _3,
318  _4,
319  SDL_BUTTON_MMASK),
321  connect_signal<event::SDL_RIGHT_BUTTON_UP>(
323  this,
324  _2,
325  _3,
326  _4,
327  SDL_BUTTON_RMASK),
329 
330  connect_signal<event::SDL_KEY_DOWN>(
331  std::bind(
332  &window::signal_handler_sdl_key_down, this, _2, _3, _5, _6, true),
334  connect_signal<event::SDL_KEY_DOWN>(std::bind(
335  &window::signal_handler_sdl_key_down, this, _2, _3, _5, _6, false));
336 
337  connect_signal<event::MESSAGE_SHOW_TOOLTIP>(
339  this,
340  _2,
341  _3,
342  _5),
344 
345  connect_signal<event::MESSAGE_SHOW_HELPTIP>(
347  this,
348  _2,
349  _3,
350  _5),
352 
353  connect_signal<event::REQUEST_PLACEMENT>(
354  std::bind(
357 
358  connect_signal<event::CLOSE_WINDOW>(std::bind(&window::signal_handler_close_window, this));
359 
360  register_hotkey(hotkey::GLOBAL__HELPTIP, std::bind(gui2::helptip));
361 
362  /** @todo: should eventally become part of global hotkey handling. */
364  std::bind(&CVideo::toggle_fullscreen, std::ref(video_)));
365 }
366 
368 {
369  /*
370  * We need to delete our children here instead of waiting for the grid to
371  * automatically do it. The reason is when the grid deletes its children
372  * they will try to unregister them self from the linked widget list. At
373  * this point the member of window are destroyed and we enter UB. (For
374  * some reason the bug didn't trigger on g++ but it does on MSVC.
375  */
376  for(unsigned row = 0; row < get_grid().get_rows(); ++row) {
377  for(unsigned col = 0; col < get_grid().get_cols(); ++col) {
378  get_grid().remove_child(row, col);
379  }
380  }
381 
382  /*
383  * The tip needs to be closed if the window closes and the window is
384  * not a tip. If we don't do that the tip will unrender in the next
385  * window and cause drawing glitches.
386  * Another issue is that on smallgui and an MP game the tooltip not
387  * unrendered properly can capture the mouse and make playing impossible.
388  */
389  if(show_mode_ == modal) {
391  }
392 
393  manager::instance().remove(*this);
394 
395 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
396 
397  delete debug_layout_;
398 
399 #endif
400 }
401 
403 {
404  return manager::instance().get_window(handle);
405 }
406 
407 /*WIKI
408  * @page = GUIToolkitWML
409  * @order = 3_widget_window_2
410  *
411  * List if the id's that have generate a return value:
412  * * ok confirms the dialog.
413  * * cancel cancels the dialog.
414  *
415  */
416 retval window::get_retval_by_id(const std::string& id)
417 {
418  // Note it might change to a map later depending on the number
419  // of items.
420  if(id == "ok") {
421  return retval::OK;
422  } else if(id == "cancel" || id == "quit") {
423  return retval::CANCEL;
424  } else {
425  return retval::NONE;
426  }
427 }
428 
429 void window::show_tooltip(/*const unsigned auto_close_timeout*/)
430 {
431  log_scope2(log_gui_draw, "Window: show as tooltip.");
432 
433  generate_dot_file("show", SHOW);
434 
435  assert(status_ == NEW);
436 
439 
441 
442  /*
443  * Before show has been called, some functions might have done some testing
444  * on the window and called layout, which can give glitches. So
445  * reinvalidate the window to avoid those glitches.
446  */
448  suspend_drawing_ = false;
449 }
450 
451 void window::show_non_modal(/*const unsigned auto_close_timeout*/)
452 {
453  log_scope2(log_gui_draw, "Window: show non modal.");
454 
455  generate_dot_file("show", SHOW);
456 
457  assert(status_ == NEW);
458 
460 
462 
463  /*
464  * Before show has been called, some functions might have done some testing
465  * on the window and called layout, which can give glitches. So
466  * reinvalidate the window to avoid those glitches.
467  */
469  suspend_drawing_ = false;
470 
472 }
473 
474 int window::show(const unsigned auto_close_timeout)
475 {
476  /*
477  * Removes the old tip if one shown. The show_tip doesn't remove
478  * the tip, since it's the tip.
479  */
481 
482  show_mode_ = modal;
483 
485 
486  generate_dot_file("show", SHOW);
487 
488  assert(status_ == NEW);
489 
490  /*
491  * Before show has been called, some functions might have done some testing
492  * on the window and called layout, which can give glitches. So
493  * reinvalidate the window to avoid those glitches.
494  */
496  suspend_drawing_ = false;
497 
498  if(auto_close_timeout) {
499  // Make sure we're drawn before we try to close ourselves, which can
500  // happen if the timeout is small.
501  draw();
502 
503  SDL_Event event;
504  sdl::UserEvent data(CLOSE_WINDOW_EVENT, manager::instance().get_id(*this));
505 
506  event.type = CLOSE_WINDOW_EVENT;
507  event.user = data;
508 
509  delay_event(event, auto_close_timeout);
510  }
511 
512 
513  try
514  {
515  // Start our loop drawing will happen here as well.
516  bool mouse_button_state_initialized = false;
517  for(status_ = SHOWING; status_ != CLOSED;) {
518  // process installed callback if valid, to allow e.g. network
519  // polling
521 
522  if(!mouse_button_state_initialized) {
523  /*
524  * The state must be initialize when showing the dialog.
525  * However when initialized before this point there were random
526  * errors. This only happened when the 'click' was done fast; a
527  * slower click worked properly.
528  *
529  * So it seems the events need to be processed before SDL can
530  * return the proper button state. When initializing here all
531  * works fine.
532  */
533  mouse_button_state_ = SDL_GetMouseState(nullptr, nullptr);
534  mouse_button_state_initialized = true;
535  }
536 
537  if(status_ == REQUEST_CLOSE) {
538  status_ = exit_hook_(*this) ? CLOSED : SHOWING;
539  }
540 
541  // Add a delay so we don't keep spinning if there's no event.
542  SDL_Delay(10);
543  }
544  }
545  catch(...)
546  {
547  /**
548  * @todo Clean up the code duplication.
549  *
550  * In the future the restoring shouldn't be needed so the duplication
551  * doesn't hurt too much but keep this todo as a reminder.
552  */
553  suspend_drawing_ = true;
554  throw;
555  }
556 
557  suspend_drawing_ = true;
558 
559  if(text_box_base* tb = dynamic_cast<text_box_base*>(event_distributor_->keyboard_focus())) {
560  tb->interrupt_composition();
561  }
562 
563  return retval_;
564 }
565 
567 {
568  /***** ***** ***** ***** Init ***** ***** ***** *****/
569  // Prohibited from drawing?
570  if(suspend_drawing_) {
571  return;
572  }
573 
574  /***** ***** Layout ***** *****/
575  if(need_layout_) {
576  layout();
577  need_layout_ = false;
578  } else {
579  // Let widgets update themselves.
580  layout_children();
581  }
582 
583  // Draw background.
584  this->draw_background();
585 
586  // Draw children.
587  this->draw_children();
588 
589  // Draw foreground.
590  this->draw_foreground();
591 
592 
593  if(callback_next_draw_ != nullptr) {
595  callback_next_draw_ = nullptr;
596  }
597 }
598 
600  : window_(window)
601 {
604 }
605 
607 {
610 }
611 
613 {
615  need_layout_ = true;
616  }
617 }
618 widget* window::find_at(const point& coordinate, const bool must_be_active)
619 {
620  return panel::find_at(coordinate, must_be_active);
621 }
622 
624  const bool must_be_active) const
625 {
626  return panel::find_at(coordinate, must_be_active);
627 }
628 
629 widget* window::find(const std::string& id, const bool must_be_active)
630 {
631  return container_base::find(id, must_be_active);
632 }
633 
634 const widget* window::find(const std::string& id, const bool must_be_active)
635  const
636 {
637  return container_base::find(id, must_be_active);
638 }
639 
640 void window::init_linked_size_group(const std::string& id,
641  const bool fixed_width,
642  const bool fixed_height)
643 {
644  assert(fixed_width || fixed_height);
645  assert(!has_linked_size_group(id));
646 
647  linked_size_[id] = linked_size(fixed_width, fixed_height);
648 }
649 
650 bool window::has_linked_size_group(const std::string& id)
651 {
652  return linked_size_.find(id) != linked_size_.end();
653 }
654 
655 void window::add_linked_widget(const std::string& id, widget* wgt)
656 {
657  assert(wgt);
658  if(!has_linked_size_group(id)) {
659  ERR_GUI << "Unknown linked group '" << id << "'; skipping\n";
660  return;
661  }
662 
663  std::vector<widget*>& widgets = linked_size_[id].widgets;
664  if(std::find(widgets.begin(), widgets.end(), wgt) == widgets.end()) {
665  widgets.push_back(wgt);
666  }
667 }
668 
669 void window::remove_linked_widget(const std::string& id, const widget* wgt)
670 {
671  assert(wgt);
672  if(!has_linked_size_group(id)) {
673  return;
674  }
675 
676  std::vector<widget*>& widgets = linked_size_[id].widgets;
677 
679  = std::find(widgets.begin(), widgets.end(), wgt);
680 
681  if(itor != widgets.end()) {
682  widgets.erase(itor);
683 
684  assert(std::find(widgets.begin(), widgets.end(), wgt)
685  == widgets.end());
686  }
687 }
688 
690 {
691  /***** Initialize. *****/
692 
693  const auto conf = cast_config_to<window_definition>();
694  assert(conf);
695 
697 
698  const point mouse = get_mouse_position();
699 
700  variables_.add("mouse_x", wfl::variant(mouse.x));
701  variables_.add("mouse_y", wfl::variant(mouse.y));
702  variables_.add("window_width", wfl::variant(0));
703  variables_.add("window_height", wfl::variant(0));
704  variables_.add("size_request_mode", wfl::variant("maximum"));
705 
707 
708  int maximum_width = 0;
709  int maximum_height = 0;
710 
712  if(maximum_width_ > 0) {
713  maximum_width = std::min(maximum_width_, settings::screen_width);
714  } else {
715  maximum_width = settings::screen_width;
716  }
717 
718  if(maximum_height_ > 0) {
719  maximum_height = std::min(maximum_height_, settings::screen_height);
720  } else {
721  maximum_height = settings::screen_height;
722  }
723  } else {
724  maximum_width = w_(variables_, &functions_);
725  maximum_height = h_(variables_, &functions_);
726  }
727 
728  /***** Handle click dismiss status. *****/
729  button* click_dismiss_button = nullptr;
730  if((click_dismiss_button
731  = find_widget<button>(this, "click_dismiss", false, false))) {
732 
733  click_dismiss_button->set_visible(widget::visibility::invisible);
734  }
735  if(click_dismiss_) {
736  button* btn = find_widget<button>(this, "ok", false, false);
737  if(btn) {
739  click_dismiss_button = btn;
740  }
741  VALIDATE(click_dismiss_button,
742  _("Click dismiss needs a 'click_dismiss' or 'ok' button."));
743  }
744 
745  /***** Layout. *****/
746  layout_initialize(true);
747  generate_dot_file("layout_initialize", LAYOUT);
748 
750 
751  try
752  {
753  window_implementation::layout(*this, maximum_width, maximum_height);
754  }
755  catch(const layout_exception_resize_failed&)
756  {
757 
758  /** @todo implement the scrollbars on the window. */
759 
760  std::stringstream sstr;
761  sstr << __FILE__ << ":" << __LINE__ << " in function '" << __func__
762  << "' found the following problem: Failed to size window;"
763  << " wanted size " << get_best_size() << " available size "
764  << maximum_width << ',' << maximum_height << " screen size "
766 
767  throw wml_exception(_("Failed to show a dialog, "
768  "which doesn't fit on the screen."),
769  sstr.str());
770  }
771 
772  /****** Validate click dismiss status. *****/
774  assert(click_dismiss_button);
775  click_dismiss_button->set_visible(widget::visibility::visible);
776 
778  *click_dismiss_button,
779  std::bind(&window::set_retval, this, retval::OK, true));
780 
781  layout_initialize(true);
782  generate_dot_file("layout_initialize", LAYOUT);
783 
785 
786  try
787  {
789  *this, maximum_width, maximum_height);
790  }
791  catch(const layout_exception_resize_failed&)
792  {
793 
794  /** @todo implement the scrollbars on the window. */
795 
796  std::stringstream sstr;
797  sstr << __FILE__ << ":" << __LINE__ << " in function '" << __func__
798  << "' found the following problem: Failed to size window;"
799  << " wanted size " << get_best_size() << " available size "
800  << maximum_width << ',' << maximum_height << " screen size "
802  << '.';
803 
804  throw wml_exception(_("Failed to show a dialog, "
805  "which doesn't fit on the screen."),
806  sstr.str());
807  }
808  }
809 
810  /***** Get the best location for the window *****/
812  assert(size.x <= maximum_width && size.y <= maximum_height);
813 
814  point origin(0, 0);
815 
817 
818  switch(horizontal_placement_) {
820  // Do nothing
821  break;
823  origin.x = (settings::screen_width - size.x) / 2;
824  break;
826  origin.x = settings::screen_width - size.x;
827  break;
828  default:
829  assert(false);
830  }
831  switch(vertical_placement_) {
833  // Do nothing
834  break;
836  origin.y = (settings::screen_height - size.y) / 2;
837  break;
839  origin.y = settings::screen_height - size.y;
840  break;
841  default:
842  assert(false);
843  }
844  } else {
845 
846  variables_.add("window_width", wfl::variant(size.x));
847  variables_.add("window_height", wfl::variant(size.y));
848 
850  layout_initialize(true);
851 
855 
856  size = get_best_size();
857  variables_.add("window_width", wfl::variant(size.x));
858  variables_.add("window_height", wfl::variant(size.y));
859  }
860 
861  variables_.add("size_request_mode", wfl::variant("size"));
862 
863  size.x = w_(variables_, &functions_);
864  size.y = h_(variables_, &functions_);
865 
866  variables_.add("window_width", wfl::variant(size.x));
867  variables_.add("window_height", wfl::variant(size.y));
868 
869  origin.x = x_(variables_, &functions_);
870  origin.y = y_(variables_, &functions_);
871  }
872 
873  /***** Set the window size *****/
874  place(origin, size);
875 
876  generate_dot_file("layout_finished", LAYOUT);
877  need_layout_ = false;
878 
880 }
881 
883 {
884  // evaluate the group sizes
885  for(auto & linked_size : linked_size_)
886  {
887 
888  point max_size(0, 0);
889 
890  // Determine the maximum size.
891  for(auto widget : linked_size.second.widgets)
892  {
893 
894  const point size = widget->get_best_size();
895 
896  if(size.x > max_size.x) {
897  max_size.x = size.x;
898  }
899  if(size.y > max_size.y) {
900  max_size.y = size.y;
901  }
902  }
903  if(linked_size.second.width != -1) {
904  linked_size.second.width = max_size.x;
905  }
906  if(linked_size.second.height != -1) {
907  linked_size.second.height = max_size.y;
908  }
909 
910  // Set the maximum size.
911  for(auto widget : linked_size.second.widgets)
912  {
913 
915 
916  if(linked_size.second.width != -1) {
917  size.x = max_size.x;
918  }
919  if(linked_size.second.height != -1) {
920  size.y = max_size.y;
921  }
922 
923  widget->set_layout_size(size);
924  }
925  }
926 }
927 
928 bool window::click_dismiss(const int mouse_button_mask)
929 {
930  if(does_click_dismiss()) {
931  if((mouse_button_state_ & mouse_button_mask) == 0) {
933  } else {
934  mouse_button_state_ &= ~mouse_button_mask;
935  }
936  return true;
937  }
938  return false;
939 }
940 
941 namespace
942 {
943 
944 /**
945  * Swaps an item in a grid for another one.
946  * This differs slightly from the standard swap_grid utility, so it's defined by itself here.
947  */
948 void window_swap_grid(grid* g,
949  grid* content_grid,
951  const std::string& id)
952 {
953  assert(content_grid);
954  assert(widget);
955 
956  // Make sure the new child has same id.
957  widget->set_id(id);
958 
959  // Get the container containing the wanted widget.
960  grid* parent_grid = nullptr;
961  if(g) {
962  parent_grid = find_widget<grid>(g, id, false, false);
963  }
964  if(!parent_grid) {
965  parent_grid = find_widget<grid>(content_grid, id, true, false);
966  assert(parent_grid);
967  }
968  if(grid* grandparent_grid = dynamic_cast<grid*>(parent_grid->parent())) {
969  grandparent_grid->swap_child(id, widget, false);
970  } else if(container_base* c
971  = dynamic_cast<container_base*>(parent_grid->parent())) {
972 
973  c->get_grid().swap_child(id, widget, true);
974  } else {
975  assert(false);
976  }
977 }
978 
979 } // namespace
980 
981 void window::finalize(const std::shared_ptr<builder_grid>& content_grid)
982 {
983  window_swap_grid(nullptr, &get_grid(), content_grid->build(), "_window_content_grid");
984 }
985 
986 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
987 
988 void window::generate_dot_file(const std::string& generator,
989  const unsigned domain)
990 {
991  debug_layout_->generate_dot_file(generator, domain);
992 }
993 #endif
994 
996  const unsigned maximum_width,
997  const unsigned maximum_height)
998 {
1000 
1001  /*
1002  * For now we return the status, need to test later whether this can
1003  * entirely be converted to an exception based system as in 'promised' on
1004  * the algorithm page.
1005  */
1006 
1007  try
1008  {
1009  point size = window.get_best_size();
1010 
1011  DBG_GUI_L << LOG_IMPL_HEADER << " best size : " << size
1012  << " maximum size : " << maximum_width << ','
1013  << maximum_height << ".\n";
1014  if(size.x <= static_cast<int>(maximum_width)
1015  && size.y <= static_cast<int>(maximum_height)) {
1016 
1017  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Fits, nothing to do.\n";
1018  return;
1019  }
1020 
1021  if(size.x > static_cast<int>(maximum_width)) {
1022  window.reduce_width(maximum_width);
1023 
1024  size = window.get_best_size();
1025  if(size.x > static_cast<int>(maximum_width)) {
1026  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Resize width failed."
1027  << " Wanted width " << maximum_width
1028  << " resulting width " << size.x << ".\n";
1030  }
1032  << " Status: Resize width succeeded.\n";
1033  }
1034 
1035  if(size.y > static_cast<int>(maximum_height)) {
1036  window.reduce_height(maximum_height);
1037 
1038  size = window.get_best_size();
1039  if(size.y > static_cast<int>(maximum_height)) {
1040  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Resize height failed."
1041  << " Wanted height " << maximum_height
1042  << " resulting height " << size.y << ".\n";
1044  }
1046  << " Status: Resize height succeeded.\n";
1047  }
1048 
1049  assert(size.x <= static_cast<int>(maximum_width)
1050  && size.y <= static_cast<int>(maximum_height));
1051 
1052 
1053  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Resizing succeeded.\n";
1054  return;
1055  }
1056  catch(const layout_exception_width_modified&)
1057  {
1059  << " Status: Width has been modified, rerun.\n";
1060 
1061  window.layout_initialize(false);
1062  window.layout_linked_widgets();
1063  layout(window, maximum_width, maximum_height);
1064  return;
1065  }
1066 }
1067 
1068 void window::mouse_capture(const bool capture)
1069 {
1070  assert(event_distributor_);
1071  event_distributor_->capture_mouse(capture);
1072 }
1073 
1075 {
1076  assert(event_distributor_);
1077  event_distributor_->keyboard_capture(widget);
1078 }
1079 
1081 {
1082  assert(event_distributor_);
1083  event_distributor_->keyboard_add_to_chain(widget);
1084 }
1085 
1087 {
1088  assert(event_distributor_);
1089  event_distributor_->keyboard_remove_from_chain(widget);
1090 }
1091 
1093 {
1094  if(std::find(tab_order.begin(), tab_order.end(), widget) != tab_order.end()) {
1095  return;
1096  }
1097  assert(event_distributor_);
1098  if(tab_order.empty() && !event_distributor_->keyboard_focus()) {
1099  keyboard_capture(widget);
1100  }
1101  if(at < 0 || at >= static_cast<int>(tab_order.size())) {
1102  tab_order.push_back(widget);
1103  } else {
1104  tab_order.insert(tab_order.begin() + at, widget);
1105  }
1106 }
1107 
1109  bool& handled,
1110  const point& new_size)
1111 {
1112  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1113 
1116  settings::screen_width = new_size.x;
1117  settings::screen_height = new_size.y;
1119 
1120  handled = true;
1121 }
1122 
1124  bool& handled,
1125  bool& halt,
1126  const int mouse_button_mask)
1127 {
1128  DBG_GUI_E << LOG_HEADER << ' ' << event << " mouse_button_mask "
1129  << static_cast<unsigned>(mouse_button_mask) << ".\n";
1130 
1131  handled = halt = click_dismiss(mouse_button_mask);
1132 }
1133 
1134 static bool is_active(const widget* wgt)
1135 {
1136  if(const styled_widget* control = dynamic_cast<const styled_widget*>(wgt)) {
1137  return control->get_active() && control->get_visible() == widget::visibility::visible;
1138  }
1139  return false;
1140 }
1141 
1143  bool& handled,
1144  const SDL_Keycode key,
1145  const SDL_Keymod mod,
1146  bool handle_tab)
1147 {
1148  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1149 
1150  if(text_box_base* tb = dynamic_cast<text_box_base*>(event_distributor_->keyboard_focus())) {
1151  if(tb->is_composing()) {
1152  if(handle_tab && !tab_order.empty() && key == SDLK_TAB) {
1153  tb->interrupt_composition();
1154  } else {
1155  return;
1156  }
1157  }
1158  }
1159  if(!enter_disabled_ && (key == SDLK_KP_ENTER || key == SDLK_RETURN)) {
1161  handled = true;
1162  } else if(key == SDLK_ESCAPE && !escape_disabled_) {
1164  handled = true;
1165  } else if(key == SDLK_SPACE) {
1166  handled = click_dismiss(0);
1167  } else if(handle_tab && !tab_order.empty() && key == SDLK_TAB) {
1168  assert(event_distributor_);
1169  widget* focus = event_distributor_->keyboard_focus();
1170  auto iter = std::find(tab_order.begin(), tab_order.end(), focus);
1171  do {
1172  if(mod & KMOD_SHIFT) {
1173  if(iter == tab_order.begin()) {
1174  iter = tab_order.end();
1175  }
1176  iter--;
1177  } else {
1178  if(iter == tab_order.end()) {
1179  iter = tab_order.begin();
1180  } else {
1181  iter++;
1182  if(iter == tab_order.end()) {
1183  iter = tab_order.begin();
1184  }
1185  }
1186  }
1187  } while(!is_active(*iter));
1188  keyboard_capture(*iter);
1189  handled = true;
1190  }
1191 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
1192  if(key == SDLK_F12) {
1193  debug_layout_->generate_dot_file("manual", debug_layout_graph::MANUAL);
1194  handled = true;
1195  }
1196 #endif
1197 }
1198 
1200  bool& handled,
1201  const event::message& message)
1202 {
1203  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1204 
1205  const event::message_show_tooltip& request
1206  = dynamic_cast<const event::message_show_tooltip&>(message);
1207 
1208  dialogs::tip::show(tooltip_.id, request.message, request.location, request.source_rect);
1209 
1210  handled = true;
1211 }
1212 
1214  bool& handled,
1215  const event::message& message)
1216 {
1217  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1218 
1219  const event::message_show_helptip& request
1220  = dynamic_cast<const event::message_show_helptip&>(message);
1221 
1222  dialogs::tip::show(helptip_.id, request.message, request.location, request.source_rect);
1223 
1224  handled = true;
1225 }
1226 
1228  bool& handled)
1229 {
1230  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1231 
1233 
1234  handled = true;
1235 }
1236 
1238 {
1240 }
1241 
1242 // }---------- DEFINITION ---------{
1243 
1244 /*WIKI
1245  * @page = GUIWidgetDefinitionWML
1246  * @order = 1_window
1247  *
1248  * == Window ==
1249  *
1250  * The definition of a window. A window is a kind of panel see the panel for
1251  * which fields exist
1252  *
1253  * @begin{parent}{name="gui/"}
1254  * @begin{tag}{name="window_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
1255  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="gui/panel_definition/resolution"}
1256  * @allow{link}{name="gui/window/resolution/grid"}
1257  * @allow{link}{name="gui/panel_definition/resolution/background"}
1258  * @allow{link}{name="gui/panel_definition/resolution/foreground"}
1259  * @end{tag}{name="resolution"}
1260  * @end{tag}{name="window_definition"}
1261  * @end{parent}{name="gui/"}
1262  */
1265 {
1266  DBG_GUI_P << "Parsing window " << id << '\n';
1267 
1268  load_resolutions<resolution>(cfg);
1269 }
1270 
1272  : panel_definition::resolution(cfg), grid(nullptr)
1273 {
1274  const config& child = cfg.child("grid");
1275  // VALIDATE(child, _("No grid defined."));
1276 
1277  /** @todo Evaluate whether the grid should become mandatory. */
1278  if(child) {
1279  grid = std::make_shared<builder_grid>(child);
1280  }
1281 }
1282 
1283 // }------------ END --------------
1284 
1285 } // namespace gui2
1286 
1287 
1288 /**
1289  * @page layout_algorithm Layout algorithm
1290  *
1291  * @section introduction Introduction
1292  *
1293  * This page describes how the layout engine for the dialogs works. First
1294  * a global overview of some terms used in this document.
1295  *
1296  * - @ref gui2::widget "Widget"; Any item which can be used in the widget
1297  * toolkit. Not all widgets are visible. In general widgets cannot be
1298  * sized directly, but this is controlled by a window. A widget has an
1299  * internal size cache and if the value in the cache is not equal to 0,0
1300  * that value is its best size. This value gets set when the widget can
1301  * honor a resize request. It will be set with the value which honors
1302  * the request.
1303  *
1304  * - @ref gui2::grid "Grid"; A grid is an invisible container which holds
1305  * one or more widgets. Several widgets have a grid in them to hold
1306  * multiple widgets eg panels and windows.
1307  *
1308  * - @ref gui2::grid::child "Grid cell"; Every widget which is in a grid is
1309  * put in a grid cell. These cells also hold the information about the gaps
1310  * between widgets the behavior on growing etc. All grid cells must have a
1311  * widget inside them.
1312  *
1313  * - @ref gui2::window "Window"; A window is a top level item which has a
1314  * grid with its children. The window handles the sizing of the window and
1315  * makes sure everything fits.
1316  *
1317  * - @ref gui2::window::linked_size "Shared size group"; A shared size
1318  * group is a number of widgets which share width and or height. These
1319  * widgets are handled separately in the layout algorithm. All grid cells
1320  * width such a widget will get the same height and or width and these
1321  * widgets won't be resized when there's not enough size. To be sure that
1322  * these widgets don't cause trouble for the layout algorithm, they must be
1323  * in a container with scrollbars so there will always be a way to properly
1324  * layout them. The engine must enforce this restriction so the shared
1325  * layout property must be set by the engine after validation.
1326  *
1327  * - All visible grid cells; A grid cell is visible when the widget inside
1328  * of it doesn't have the state visibility::invisible. Widgets which have the
1329  * state @ref visibility::hidden are sized properly since when they become
1330  * @ref visibility::visible the layout shouldn't be invalidated. A grid cell
1331  * that's invisible has size 0,0.
1332  *
1333  * - All resizable grid cells; A grid cell is resizable under the following
1334  * conditions:
1335  * - The widget is visibility::visible.
1336  * - The widget is not in a shared size group.
1337  *
1338  * There are two layout algorithms with a different purpose.
1339  *
1340  * - The Window algorithm; this algorithm's goal is it to make sure all grid
1341  * cells fit in the window. Sizing the grid cells depends on the widget
1342  * size as well, but this algorithm only sizes the grid cells and doesn't
1343  * handle the widgets inside them.
1344  *
1345  * - The Grid algorithm; after the Window algorithm made sure that all grid
1346  * cells fit this algorithm makes sure the widgets are put in the optimal
1347  * state in their grid cell.
1348  *
1349  * @section layout_algorithm_window Window
1350  *
1351  * Here is the algorithm used to layout the window:
1352  *
1353  * - Perform a full initialization
1354  * (@ref gui2::widget::layout_initialize (full_initialization = true)):
1355  * - Clear the internal best size cache for all widgets.
1356  * - For widgets with scrollbars hide them unless the
1357  * @ref gui2::scrollbar_container::scrollbar_mode "scrollbar_mode" is
1358  * ALWAYS_VISIBLE or AUTO_VISIBLE.
1359  * - Handle shared sizes:
1360  * - Height and width:
1361  * - Get the best size for all widgets that share height and width.
1362  * - Set the maximum of width and height as best size for all these
1363  * widgets.
1364  * - Width only:
1365  * - Get the best width for all widgets which share their width.
1366  * - Set the maximum width for all widgets, but keep their own height.
1367  * - Height only:
1368  * - Get the best height for all widgets which share their height.
1369  * - Set the maximum height for all widgets, but keep their own width.
1370  * - Start layout loop:
1371  * - Get best size.
1372  * - If width <= maximum_width && height <= maximum_height we're done.
1373  * - If width > maximum_width, optimize the width:
1374  * - For every grid cell in a grid row there will be a resize request
1375  * (@ref gui2::grid::reduce_width):
1376  * - Sort the widgets in the row on the resize priority.
1377  * - Loop through this priority queue until the row fits
1378  * - If priority != 0 try to share the extra width else all
1379  * widgets are tried to reduce the full size.
1380  * - Try to shrink the widgets by either wrapping or using a
1381  * scrollbar (@ref gui2::widget::request_reduce_width).
1382  * - If the row fits in the wanted width this row is done.
1383  * - Else try the next priority.
1384  * - All priorities done and the width still doesn't fit.
1385  * - Loop through this priority queue until the row fits.
1386  * - If priority != 0:
1387  * - try to share the extra width
1388  * -Else:
1389  * - All widgets are tried to reduce the full size.
1390  * - Try to shrink the widgets by sizing them smaller as really
1391  * wanted (@ref gui2::widget::demand_reduce_width).
1392  * For labels, buttons etc. they get ellipsized.
1393  * - If the row fits in the wanted width this row is done.
1394  * - Else try the next priority.
1395  * - All priorities done and the width still doesn't fit.
1396  * - Throw a layout width doesn't fit exception.
1397  * - If height > maximum_height, optimize the height
1398  * (@ref gui2::grid::reduce_height):
1399  * - For every grid cell in a grid column there will be a resize request:
1400  * - Sort the widgets in the column on the resize priority.
1401  * - Loop through this priority queue until the column fits:
1402  * - If priority != 0 try to share the extra height else all
1403  * widgets are tried to reduce the full size.
1404  * - Try to shrink the widgets by using a scrollbar
1405  * (@ref gui2::widget::request_reduce_height).
1406  * - If succeeded for a widget the width is influenced and the
1407  * width might be invalid.
1408  * - Throw a width modified exception.
1409  * - If the column fits in the wanted height this column is done.
1410  * - Else try the next priority.
1411  * - All priorities done and the height still doesn't fit.
1412  * - Loop through this priority queue until the column fits.
1413  * - If priority != 0 try to share the extra height else all
1414  * widgets are tried to reduce the full size.
1415  * - Try to shrink the widgets by sizing them smaller as really
1416  * wanted (@ref gui2::widget::demand_reduce_width).
1417  * For labels, buttons etc. they get ellipsized .
1418  * - If the column fits in the wanted height this column is done.
1419  * - Else try the next priority.
1420  * - All priorities done and the height still doesn't fit.
1421  * - Throw a layout height doesn't fit exception.
1422  * - End layout loop.
1423  *
1424  * - Catch @ref gui2::layout_exception_width_modified "width modified":
1425  * - Goto relayout.
1426  *
1427  * - Catch
1428  * @ref gui2::layout_exception_width_resize_failed "width resize failed":
1429  * - If the window has a horizontal scrollbar which isn't shown but can be
1430  * shown.
1431  * - Show the scrollbar.
1432  * - goto relayout.
1433  * - Else show a layout failure message.
1434  *
1435  * - Catch
1436  * @ref gui2::layout_exception_height_resize_failed "height resize failed":
1437  * - If the window has a vertical scrollbar which isn't shown but can be
1438  * shown:
1439  * - Show the scrollbar.
1440  * - goto relayout.
1441  * - Else:
1442  * - show a layout failure message.
1443  *
1444  * - Relayout:
1445  * - Initialize all widgets
1446  * (@ref gui2::widget::layout_initialize (full_initialization = false))
1447  * - Handle shared sizes, since the reinitialization resets that state.
1448  * - Goto start layout loop.
1449  *
1450  * @section grid Grid
1451  *
1452  * This section will be documented later.
1453  */
Define the common log macros for the gui toolkit.
bool click_dismiss_
Do we want to have easy close behavior?
Definition: window.hpp:528
const std::string message
The message to show on the tooltip.
Definition: message.hpp:67
void keyboard_capture(widget *widget)
Definition: window.cpp:1074
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
#define DBG_GUI_P
Definition: log.hpp:68
wfl::function_symbol_table functions_
The formula definitions available for the calculation formulas.
Definition: window.hpp:503
void remove()
Removes a tip.
Definition: tooltip.cpp:188
Defines the exception classes for the layout algorithm.
void signal_handler_click_dismiss(const event::ui_event event, bool &handled, bool &halt, const int mouse_button_mask)
The handler for the click dismiss mouse &#39;event&#39;.
Definition: window.cpp:1123
#define ERR_GUI
Definition: window.cpp:74
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:423
void reduce_width(const unsigned maximum_width)
Tries to reduce the width of a container.
Helper for header for the window.
bool does_click_dismiss() const
Does the window close easily?
Definition: window.hpp:255
std::function< bool(window &)> exit_hook_
Definition: window.hpp:734
const std::string message
The message to show on the helptip.
Definition: message.hpp:85
Abstract base class for text items.
void signal_handler_sdl_key_down(const event::ui_event event, bool &handled, const SDL_Keycode key, const SDL_Keymod mod, bool handle_tab)
Definition: window.cpp:1142
#define DBG_GUI_L
Definition: log.hpp:57
static lg::log_domain log_gui("gui/layout")
void set_layout_size(const point &size)
Definition: widget.cpp:327
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: window.cpp:618
typed_formula< unsigned > h_
The formula to calculate the height of the dialog.
Definition: window.hpp:497
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
const unsigned horizontal_placement_
Sets the horizontal placement.
Definition: window.hpp:471
virtual void place(const point &origin, const point &size) override
See widget::place.
int show(const unsigned auto_close_timeout=0)
Shows the window.
Definition: window.cpp:474
static help_manager manager
The help manager.
Definition: help.cpp:34
const grid & get_grid() const
const point location
The location where to show the tooltip.
Definition: message.hpp:70
Visible container to hold multiple widgets.
Definition: panel.hpp:37
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
Main class to show messages to the user.
Definition: message.hpp:34
void register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function &function)
Registers a hotkey.
Definition: dispatcher.cpp:133
CVideo & video_
Needed so we can change what&#39;s drawn on the screen.
Definition: window.hpp:424
void show_non_modal()
Shows the window non modal.
Definition: window.cpp:451
void generate_dot_file(const std::string &, const unsigned)
Definition: window.hpp:644
Helper struct to force widgets the have the same size.
Definition: window.hpp:543
#define LOG_SCOPE_HEADER
Definition: window.cpp:76
const std::string & id() const
Definition: widget.cpp:106
unsigned int get_rows() const
Definition: grid.hpp:300
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...
void draw()
Draws the window.
Definition: window.cpp:566
The message for MESSAGE_SHOW_HELPTIP.
Definition: message.hpp:77
Base class for all widgets.
Definition: widget.hpp:48
lg::log_domain log_gui_layout("gui/layout")
Definition: log.hpp:56
const SDL_Rect source_rect
The size of the entity requesting to show a tooltip.
Definition: message.hpp:73
void signal_handler_sdl_video_resize(const event::ui_event event, bool &handled, const point &new_size)
Definition: window.cpp:1108
#define LOG_IMPL_HEADER
Definition: window.cpp:81
static CVideo & get_singleton()
Definition: video.hpp:48
bool non_interactive() const
Definition: video.cpp:90
static const std::string & type()
Static type getter that does not rely on the widget being constructed.
Contains the event distributor.
unsigned gamemap_width
The size of the map area, if not available equal to the screen size.
Definition: settings.cpp:30
void add_to_keyboard_chain(widget *widget)
Adds the widget to the keyboard chain.
Definition: window.cpp:1080
typed_formula< unsigned > w_
The formula to calculate the width of the dialog.
Definition: window.hpp:494
void signal_handler_message_show_tooltip(const event::ui_event event, bool &handled, const event::message &message)
Definition: window.cpp:1199
-file util.hpp
Definitions for the interface to Wesnoth Markup Language (WML).
const point location
The location where to show the helptip.
Definition: message.hpp:88
void draw_foreground()
Draws the foreground of the widget.
Definition: widget.cpp:417
int mouse_button_state_
The state of the mouse button.
Definition: window.hpp:611
void get_screen_size_variables(wfl::map_formula_callable &variable)
Gets a formula object with the screen size.
Definition: helper.cpp:99
int x
x coordinate.
Definition: point.hpp:44
void init_mouse_location()
Initializes the location of the mouse.
Definition: handler.cpp:775
Generic file dialog.
Definition: field-fwd.hpp:22
int width
The current width of all widgets in the group, -1 if the width is not linked.
Definition: window.hpp:554
The window has been closed.
Definition: window.hpp:155
The message callbacks hold a reference to a message.
Definition: message.hpp:46
#define CLOSE_WINDOW_EVENT
Definition: events.hpp:26
static bool is_active(const widget *wgt)
Definition: window.cpp:1134
The event handler class for the widget library.
Base container class.
Definition: grid.hpp:30
void connect()
Connects the dispatcher to the event handler.
Definition: dispatcher.cpp:48
static std::string at(const std::string &file, int line)
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
status status_
The status of the window.
Definition: window.hpp:427
#define LOG_HEADER
Definition: window.cpp:77
void reduce_height(const unsigned maximum_height)
Tries to reduce the height of a container.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
std::vector< widget * > widgets
The widgets linked.
Definition: window.hpp:551
Exception thrown when the width has been modified during resizing.
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:189
The dialog was closed automatically as its timeout had been reached.
Definition: retval.hpp:40
const t_string id
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
bool suspend_drawing_
Avoid drawing the window.
Definition: window.hpp:457
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:252
bool enter_disabled_
Disable the enter key see our setter for more info.
Definition: window.hpp:531
const SDL_Rect source_rect
The size of the entity requesting to show a helptip.
Definition: message.hpp:91
std::shared_ptr< widget > widget_ptr
Definition: widget.hpp:732
bool invalidate_layout_blocked_
Is invalidate_layout blocked, see invalidate_layout_blocker.
Definition: window.hpp:454
void set_visible(const visibility visible)
Definition: widget.cpp:445
bool need_layout_
When set the form needs a full layout redraw cycle.
Definition: window.hpp:448
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:163
void signal_handler_close_window()
Definition: window.cpp:1237
typed_formula< bool > reevaluate_best_size_
The formula to determine whether the size is good.
Definition: window.hpp:500
builder_window::window_resolution::tooltip_info helptip_
The settings for the helptip.
Definition: window.hpp:509
unsigned gamemap_height
Definition: settings.cpp:31
widget * parent()
Definition: widget.cpp:156
static const unsigned HORIZONTAL_ALIGN_RIGHT
Definition: grid.hpp:58
void finalize(const std::shared_ptr< builder_grid > &content_grid)
Finishes the initialization of the grid.
Definition: window.cpp:981
The window is new and not yet shown.
Definition: window.hpp:149
This file contains the definitions for the gui2::event::message class.
The message for MESSAGE_SHOW_TOOLTIP.
Definition: message.hpp:59
unsigned int get_cols() const
Definition: grid.hpp:306
typed_formula< unsigned > y_
The formula to calculate the y value of the dialog.
Definition: window.hpp:491
Exception thrown when the width resizing has failed.
Basic template class to generate new items.
#define log_scope2(domain, description)
Definition: log.hpp:187
const bool automatic_placement_
Do we wish to place the widget automatically?
Definition: window.hpp:463
void init_linked_size_group(const std::string &id, const bool fixed_width, const bool fixed_height)
Initializes a linked size group.
Definition: window.cpp:640
typed_formula< unsigned > x_
The formula to calculate the x value of the dialog.
Definition: window.hpp:488
void set_mouse_behavior(const mouse_behavior mouse_behavior)
Definition: dispatcher.hpp:778
bool escape_disabled_
Disable the escape key see our setter for more info.
Definition: window.hpp:534
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
static window * window_instance(const unsigned handle)
Returns the instance of a window.
Definition: window.cpp:402
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
Definition: window.cpp:655
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: window.cpp:629
Helper class, don&#39;t construct this directly.
static const unsigned VERTICAL_ALIGN_TOP
Definition: grid.hpp:49
virtual widget_ptr build() const override
Definition: window.cpp:101
void remove_from_keyboard_chain(widget *widget)
Remove the widget from the keyboard chain.
Definition: window.cpp:1086
bool faked() const
Definition: video.hpp:65
unsigned maximum_height_
The maximum height if automatic_placement_ is true.
Definition: window.hpp:485
std::map< unsigned, window * > windows_
Definition: window.cpp:192
#define DBG_GUI_E
Definition: log.hpp:34
Default, unset return value.
Definition: retval.hpp:31
#define SHOW_HELPTIP_EVENT
Definition: events.hpp:27
unsigned maximum_width_
The maximum width if automatic_placement_ is true.
Definition: window.hpp:482
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
void toggle_fullscreen()
Definition: video.cpp:446
The user set the widget invisible, that means:
The window has been requested to be closed but still needs to evaluate the request.
Definition: window.hpp:151
window * get_window()
Get the parent window.
Definition: widget.cpp:113
double g
Definition: astarsearch.cpp:63
const unsigned vertical_placement_
Sets the vertical placement.
Definition: window.hpp:479
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:408
std::vector< widget * > tab_order
List of widgets in the tabbing order.
Definition: window.hpp:564
static const unsigned VERTICAL_ALIGN_CENTER
Definition: grid.hpp:50
bool has_linked_size_group(const std::string &id)
Is the linked size group defined for this window?
Definition: window.cpp:650
bool click_dismiss(const int mouse_button_mask)
Handles a mouse click event for dismissing the dialog.
Definition: window.cpp:928
static const unsigned HORIZONTAL_ALIGN_CENTER
Definition: grid.hpp:57
Holds a 2D point.
Definition: point.hpp:23
unsigned screen_width
The screen resolution should be available for all widgets since their drawing method will depend on i...
Definition: settings.cpp:25
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:345
lg::log_domain log_gui_draw("gui/draw")
Definition: log.hpp:27
Base class for all visible items.
A generic container base class.
void signal_handler_request_placement(const event::ui_event event, bool &handled)
Definition: window.cpp:1227
builder_window::window_resolution::tooltip_info tooltip_
The settings for the tooltip.
Definition: window.hpp:506
show_mode show_mode_
The mode in which the window is shown.
Definition: window.hpp:434
static void layout(window &window, const unsigned maximum_width, const unsigned maximum_height)
Layouts the window.
Definition: window.cpp:995
window_definition(const config &cfg)
Definition: window.cpp:1263
static const unsigned VERTICAL_ALIGN_BOTTOM
Definition: grid.hpp:51
static retval get_retval_by_id(const std::string &id)
Gets the retval for the default buttons.
Definition: window.cpp:416
point get_mouse_position()
Returns the current mouse position.
Definition: helper.cpp:116
Contains the SDL_Rect helper code.
The user sets the widget visible, that means:
void remove_child(const unsigned row, const unsigned col)
Removes and frees a widget in a cell.
Definition: grid.cpp:141
const t_string & tooltip() const
void show_tooltip()
Shows the window as a tooltip.
Definition: window.cpp:429
unsigned screen_height
Definition: settings.cpp:26
Definition: contexts.hpp:43
void mouse_capture(const bool capture=true)
Definition: window.cpp:1068
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
void layout()
Layouts the window.
Definition: window.cpp:689
Simple push button.
Definition: button.hpp:35
void run_event_loop()
Definition: events.cpp:436
std::unique_ptr< event::distributor > event_distributor_
Definition: window.hpp:649
void signal_handler_message_show_helptip(const event::ui_event event, bool &handled, const event::message &message)
Definition: window.cpp:1213
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:612
void draw_background()
Draws the background of a widget.
Definition: widget.cpp:398
friend class debug_layout_graph
Definition: window.hpp:64
dialogs::modal_dialog * owner_
The dialog that owns the window.
Definition: window.hpp:440
retval
Default window/dialog return values.
Definition: retval.hpp:28
virtual void layout_children() override
See widget::layout_children.
static const unsigned HORIZONTAL_ALIGN_LEFT
Definition: grid.hpp:56
Dialog was closed with the OK button.
Definition: retval.hpp:34
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
void remove_linked_widget(const std::string &id, const widget *widget)
Removes a widget from a linked size group.
Definition: window.cpp:669
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
int height
The current height of all widgets in the group, -1 if the height is not linked.
Definition: window.hpp:557
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
void add_to_tab_order(widget *widget, int at=-1)
Add the widget to the tabbing order.
Definition: window.cpp:1092
mock_char c
void set_want_keyboard_input(const bool want_keyboard_input)
Definition: dispatcher.hpp:788
std::shared_ptr< halo_record > handle
Definition: halo.hpp:31
int y
y coordinate.
Definition: point.hpp:47
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
#define LOG_IMPL_SCOPE_HEADER
Definition: window.cpp:79
The window is being shown.
Definition: window.hpp:150
std::map< std::string, linked_size > linked_size_
List of the widgets, whose size are linked together.
Definition: window.hpp:561
wfl::map_formula_callable variables_
The variables of the canvas.
Definition: window.hpp:451
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
void initialize_state()
Initializes the state of the keyboard and mouse.
HOTKEY_COMMAND get_id(const std::string &command)
returns get_hotkey_command(command).id
builder_window(const config &cfg)
Definition: window.cpp:95
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:47
void layout_linked_widgets()
Layouts the linked widgets.
Definition: window.cpp:882
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
Definition: tooltip.cpp:153
std::function< void()> callback_next_draw_
Definition: window.hpp:735
Basic exception when the layout doesn&#39;t fit.