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 http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
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  widget* build() const
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}), get_control_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())
296  {
297  connect_signal<event::DRAW>(std::bind(&window::draw, this));
298  }
299 
300  connect_signal<event::SDL_VIDEO_RESIZE>(std::bind(
301  &window::signal_handler_sdl_video_resize, this, _2, _3, _5));
302 
303  connect_signal<event::SDL_ACTIVATE>(std::bind(
305 
306  connect_signal<event::SDL_LEFT_BUTTON_UP>(
308  this,
309  _2,
310  _3,
311  _4,
312  SDL_BUTTON_LMASK),
314  connect_signal<event::SDL_MIDDLE_BUTTON_UP>(
316  this,
317  _2,
318  _3,
319  _4,
320  SDL_BUTTON_MMASK),
322  connect_signal<event::SDL_RIGHT_BUTTON_UP>(
324  this,
325  _2,
326  _3,
327  _4,
328  SDL_BUTTON_RMASK),
330 
331  connect_signal<event::SDL_KEY_DOWN>(
332  std::bind(
333  &window::signal_handler_sdl_key_down, this, _2, _3, _5, _6, true),
335  connect_signal<event::SDL_KEY_DOWN>(std::bind(
336  &window::signal_handler_sdl_key_down, this, _2, _3, _5, _6, false));
337 
338  connect_signal<event::MESSAGE_SHOW_TOOLTIP>(
340  this,
341  _2,
342  _3,
343  _5),
345 
346  connect_signal<event::MESSAGE_SHOW_HELPTIP>(
348  this,
349  _2,
350  _3,
351  _5),
353 
354  connect_signal<event::REQUEST_PLACEMENT>(
355  std::bind(
358 
359  connect_signal<event::CLOSE_WINDOW>(std::bind(&window::signal_handler_close_window, this));
360 
361  register_hotkey(hotkey::GLOBAL__HELPTIP, std::bind(gui2::helptip));
362 
363  /** @todo: should eventally become part of global hotkey handling. */
365  std::bind(&CVideo::toggle_fullscreen, std::ref(video_)));
366 }
367 
369 {
370  /*
371  * We need to delete our children here instead of waiting for the grid to
372  * automatically do it. The reason is when the grid deletes its children
373  * they will try to unregister them self from the linked widget list. At
374  * this point the member of window are destroyed and we enter UB. (For
375  * some reason the bug didn't trigger on g++ but it does on MSVC.
376  */
377  for(unsigned row = 0; row < get_grid().get_rows(); ++row) {
378  for(unsigned col = 0; col < get_grid().get_cols(); ++col) {
379  get_grid().remove_child(row, col);
380  }
381  }
382 
383  /*
384  * The tip needs to be closed if the window closes and the window is
385  * not a tip. If we don't do that the tip will unrender in the next
386  * window and cause drawing glitches.
387  * Another issue is that on smallgui and an MP game the tooltip not
388  * unrendered properly can capture the mouse and make playing impossible.
389  */
390  if(show_mode_ == modal) {
392  }
393 
394  manager::instance().remove(*this);
395 
396 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
397 
398  delete debug_layout_;
399 
400 #endif
401 }
402 
404 {
405  return manager::instance().get_window(handle);
406 }
407 
408 /*WIKI
409  * @page = GUIToolkitWML
410  * @order = 3_widget_window_2
411  *
412  * List if the id's that have generate a return value:
413  * * ok confirms the dialog.
414  * * cancel cancels the dialog.
415  *
416  */
417 retval window::get_retval_by_id(const std::string& id)
418 {
419  // Note it might change to a map later depending on the number
420  // of items.
421  if(id == "ok") {
422  return retval::OK;
423  } else if(id == "cancel" || id == "quit") {
424  return retval::CANCEL;
425  } else {
426  return retval::NONE;
427  }
428 }
429 
430 void window::show_tooltip(/*const unsigned auto_close_timeout*/)
431 {
432  log_scope2(log_gui_draw, "Window: show as tooltip.");
433 
434  generate_dot_file("show", SHOW);
435 
436  assert(status_ == NEW);
437 
440 
442 
443  /*
444  * Before show has been called, some functions might have done some testing
445  * on the window and called layout, which can give glitches. So
446  * reinvalidate the window to avoid those glitches.
447  */
449  suspend_drawing_ = false;
450 }
451 
452 void window::show_non_modal(/*const unsigned auto_close_timeout*/)
453 {
454  log_scope2(log_gui_draw, "Window: show non modal.");
455 
456  generate_dot_file("show", SHOW);
457 
458  assert(status_ == NEW);
459 
461 
463 
464  /*
465  * Before show has been called, some functions might have done some testing
466  * on the window and called layout, which can give glitches. So
467  * reinvalidate the window to avoid those glitches.
468  */
470  suspend_drawing_ = false;
471 
473 }
474 
475 int window::show(const unsigned auto_close_timeout)
476 {
477  /*
478  * Removes the old tip if one shown. The show_tip doesn't remove
479  * the tip, since it's the tip.
480  */
482 
483  show_mode_ = modal;
484 
486 
487  generate_dot_file("show", SHOW);
488 
489  assert(status_ == NEW);
490 
491  /*
492  * Before show has been called, some functions might have done some testing
493  * on the window and called layout, which can give glitches. So
494  * reinvalidate the window to avoid those glitches.
495  */
497  suspend_drawing_ = false;
498 
499  if(auto_close_timeout) {
500  // Make sure we're drawn before we try to close ourselves, which can
501  // happen if the timeout is small.
502  draw();
503 
504  SDL_Event event;
505  sdl::UserEvent data(CLOSE_WINDOW_EVENT, manager::instance().get_id(*this));
506 
507  event.type = CLOSE_WINDOW_EVENT;
508  event.user = data;
509 
510  delay_event(event, auto_close_timeout);
511  }
512 
513 
514  try
515  {
516  // Start our loop drawing will happen here as well.
517  bool mouse_button_state_initialized = false;
518  for(status_ = SHOWING; status_ != CLOSED;) {
519  // process installed callback if valid, to allow e.g. network
520  // polling
522 
523  if(!mouse_button_state_initialized) {
524  /*
525  * The state must be initialize when showing the dialog.
526  * However when initialized before this point there were random
527  * errors. This only happened when the 'click' was done fast; a
528  * slower click worked properly.
529  *
530  * So it seems the events need to be processed before SDL can
531  * return the proper button state. When initializing here all
532  * works fine.
533  */
534  mouse_button_state_ = SDL_GetMouseState(nullptr, nullptr);
535  mouse_button_state_initialized = true;
536  }
537 
538  if(status_ == REQUEST_CLOSE) {
539  status_ = exit_hook_(*this) ? CLOSED : SHOWING;
540  }
541 
542  // Add a delay so we don't keep spinning if there's no event.
543  SDL_Delay(10);
544  }
545  }
546  catch(...)
547  {
548  /**
549  * @todo Clean up the code duplication.
550  *
551  * In the future the restoring shouldn't be needed so the duplication
552  * doesn't hurt too much but keep this todo as a reminder.
553  */
554  suspend_drawing_ = true;
555  throw;
556  }
557 
558  suspend_drawing_ = true;
559 
560  if(text_box_base* tb = dynamic_cast<text_box_base*>(event_distributor_->keyboard_focus())) {
561  tb->interrupt_composition();
562  }
563 
564  return retval_;
565 }
566 
568 {
569  /***** ***** ***** ***** Init ***** ***** ***** *****/
570  // Prohibited from drawing?
571  if(suspend_drawing_) {
572  return;
573  }
574 
575  /***** ***** Layout ***** *****/
576  if(need_layout_) {
577  layout();
578  need_layout_ = false;
579  } else {
580  // Let widgets update themselves.
581  layout_children();
582  }
583 
584  // Draw background.
585  this->draw_background();
586 
587  // Draw children.
588  this->draw_children();
589 
590  // Draw foreground.
591  this->draw_foreground();
592 
593 
594  if(callback_next_draw_ != nullptr) {
596  callback_next_draw_ = nullptr;
597  }
598 }
599 
601  : window_(window)
602 {
605 }
606 
608 {
611 }
612 
614 {
616  need_layout_ = true;
617  }
618 }
619 widget* window::find_at(const point& coordinate, const bool must_be_active)
620 {
621  return panel::find_at(coordinate, must_be_active);
622 }
623 
625  const bool must_be_active) const
626 {
627  return panel::find_at(coordinate, must_be_active);
628 }
629 
630 widget* window::find(const std::string& id, const bool must_be_active)
631 {
632  return container_base::find(id, must_be_active);
633 }
634 
635 const widget* window::find(const std::string& id, const bool must_be_active)
636  const
637 {
638  return container_base::find(id, must_be_active);
639 }
640 
641 void window::init_linked_size_group(const std::string& id,
642  const bool fixed_width,
643  const bool fixed_height)
644 {
645  assert(fixed_width || fixed_height);
646  assert(!has_linked_size_group(id));
647 
648  linked_size_[id] = linked_size(fixed_width, fixed_height);
649 }
650 
651 bool window::has_linked_size_group(const std::string& id)
652 {
653  return linked_size_.find(id) != linked_size_.end();
654 }
655 
656 void window::add_linked_widget(const std::string& id, widget* wgt)
657 {
658  assert(wgt);
659  if(!has_linked_size_group(id)) {
660  ERR_GUI << "Unknown linked group '" << id << "'; skipping\n";
661  return;
662  }
663 
664  std::vector<widget*>& widgets = linked_size_[id].widgets;
665  if(std::find(widgets.begin(), widgets.end(), wgt) == widgets.end()) {
666  widgets.push_back(wgt);
667  }
668 }
669 
670 void window::remove_linked_widget(const std::string& id, const widget* wgt)
671 {
672  assert(wgt);
673  if(!has_linked_size_group(id)) {
674  return;
675  }
676 
677  std::vector<widget*>& widgets = linked_size_[id].widgets;
678 
680  = std::find(widgets.begin(), widgets.end(), wgt);
681 
682  if(itor != widgets.end()) {
683  widgets.erase(itor);
684 
685  assert(std::find(widgets.begin(), widgets.end(), wgt)
686  == widgets.end());
687  }
688 }
689 
691 {
692  /***** Initialize. *****/
693 
694  const auto conf = cast_config_to<window_definition>();
695  assert(conf);
696 
698 
699  const point mouse = get_mouse_position();
700 
701  variables_.add("mouse_x", wfl::variant(mouse.x));
702  variables_.add("mouse_y", wfl::variant(mouse.y));
703  variables_.add("window_width", wfl::variant(0));
704  variables_.add("window_height", wfl::variant(0));
705  variables_.add("size_request_mode", wfl::variant("maximum"));
706 
708 
709  int maximum_width = 0;
710  int maximum_height = 0;
711 
713  if(maximum_width_ > 0) {
714  maximum_width = std::min(maximum_width_, settings::screen_width);
715  } else {
716  maximum_width = settings::screen_width;
717  }
718 
719  if(maximum_height_ > 0) {
720  maximum_height = std::min(maximum_height_, settings::screen_height);
721  } else {
722  maximum_height = settings::screen_height;
723  }
724  } else {
725  maximum_width = w_(variables_, &functions_);
726  maximum_height = h_(variables_, &functions_);
727  }
728 
729  /***** Handle click dismiss status. *****/
730  button* click_dismiss_button = nullptr;
731  if((click_dismiss_button
732  = find_widget<button>(this, "click_dismiss", false, false))) {
733 
734  click_dismiss_button->set_visible(widget::visibility::invisible);
735  }
736  if(click_dismiss_) {
737  button* btn = find_widget<button>(this, "ok", false, false);
738  if(btn) {
740  click_dismiss_button = btn;
741  }
742  VALIDATE(click_dismiss_button,
743  _("Click dismiss needs a 'click_dismiss' or 'ok' button."));
744  }
745 
746  /***** Layout. *****/
747  layout_initialize(true);
748  generate_dot_file("layout_initialize", LAYOUT);
749 
751 
752  try
753  {
754  window_implementation::layout(*this, maximum_width, maximum_height);
755  }
756  catch(const layout_exception_resize_failed&)
757  {
758 
759  /** @todo implement the scrollbars on the window. */
760 
761  std::stringstream sstr;
762  sstr << __FILE__ << ":" << __LINE__ << " in function '" << __func__
763  << "' found the following problem: Failed to size window;"
764  << " wanted size " << get_best_size() << " available size "
765  << maximum_width << ',' << maximum_height << " screen size "
767 
768  throw wml_exception(_("Failed to show a dialog, "
769  "which doesn't fit on the screen."),
770  sstr.str());
771  }
772 
773  /****** Validate click dismiss status. *****/
775  assert(click_dismiss_button);
776  click_dismiss_button->set_visible(widget::visibility::visible);
777 
779  *click_dismiss_button,
780  std::bind(&window::set_retval, this, retval::OK, true));
781 
782  layout_initialize(true);
783  generate_dot_file("layout_initialize", LAYOUT);
784 
786 
787  try
788  {
790  *this, maximum_width, maximum_height);
791  }
792  catch(const layout_exception_resize_failed&)
793  {
794 
795  /** @todo implement the scrollbars on the window. */
796 
797  std::stringstream sstr;
798  sstr << __FILE__ << ":" << __LINE__ << " in function '" << __func__
799  << "' found the following problem: Failed to size window;"
800  << " wanted size " << get_best_size() << " available size "
801  << maximum_width << ',' << maximum_height << " screen size "
803  << '.';
804 
805  throw wml_exception(_("Failed to show a dialog, "
806  "which doesn't fit on the screen."),
807  sstr.str());
808  }
809  }
810 
811  /***** Get the best location for the window *****/
813  assert(size.x <= maximum_width && size.y <= maximum_height);
814 
815  point origin(0, 0);
816 
818 
819  switch(horizontal_placement_) {
821  // Do nothing
822  break;
824  origin.x = (settings::screen_width - size.x) / 2;
825  break;
827  origin.x = settings::screen_width - size.x;
828  break;
829  default:
830  assert(false);
831  }
832  switch(vertical_placement_) {
834  // Do nothing
835  break;
837  origin.y = (settings::screen_height - size.y) / 2;
838  break;
840  origin.y = settings::screen_height - size.y;
841  break;
842  default:
843  assert(false);
844  }
845  } else {
846 
847  variables_.add("window_width", wfl::variant(size.x));
848  variables_.add("window_height", wfl::variant(size.y));
849 
851  layout_initialize(true);
852 
856 
857  size = get_best_size();
858  variables_.add("window_width", wfl::variant(size.x));
859  variables_.add("window_height", wfl::variant(size.y));
860  }
861 
862  variables_.add("size_request_mode", wfl::variant("size"));
863 
864  size.x = w_(variables_, &functions_);
865  size.y = h_(variables_, &functions_);
866 
867  variables_.add("window_width", wfl::variant(size.x));
868  variables_.add("window_height", wfl::variant(size.y));
869 
870  origin.x = x_(variables_, &functions_);
871  origin.y = y_(variables_, &functions_);
872  }
873 
874  /***** Set the window size *****/
875  place(origin, size);
876 
877  generate_dot_file("layout_finished", LAYOUT);
878  need_layout_ = false;
879 
881 }
882 
884 {
885  // evaluate the group sizes
886  for(auto & linked_size : linked_size_)
887  {
888 
889  point max_size(0, 0);
890 
891  // Determine the maximum size.
892  for(auto widget : linked_size.second.widgets)
893  {
894 
895  const point size = widget->get_best_size();
896 
897  if(size.x > max_size.x) {
898  max_size.x = size.x;
899  }
900  if(size.y > max_size.y) {
901  max_size.y = size.y;
902  }
903  }
904  if(linked_size.second.width != -1) {
905  linked_size.second.width = max_size.x;
906  }
907  if(linked_size.second.height != -1) {
908  linked_size.second.height = max_size.y;
909  }
910 
911  // Set the maximum size.
912  for(auto widget : linked_size.second.widgets)
913  {
914 
916 
917  if(linked_size.second.width != -1) {
918  size.x = max_size.x;
919  }
920  if(linked_size.second.height != -1) {
921  size.y = max_size.y;
922  }
923 
924  widget->set_layout_size(size);
925  }
926  }
927 }
928 
929 bool window::click_dismiss(const int mouse_button_mask)
930 {
931  if(does_click_dismiss()) {
932  if((mouse_button_state_ & mouse_button_mask) == 0) {
934  } else {
935  mouse_button_state_ &= ~mouse_button_mask;
936  }
937  return true;
938  }
939  return false;
940 }
941 
942 namespace
943 {
944 
945 /**
946  * Swaps an item in a grid for another one.
947  * This differs slightly from the standard swap_grid utility, so it's defined by itself here.
948  */
949 void window_swap_grid(grid* g,
950  grid* content_grid,
951  widget* widget,
952  const std::string& id)
953 {
954  assert(content_grid);
955  assert(widget);
956 
957  // Make sure the new child has same id.
958  widget->set_id(id);
959 
960  // Get the container containing the wanted widget.
961  grid* parent_grid = nullptr;
962  if(g) {
963  parent_grid = find_widget<grid>(g, id, false, false);
964  }
965  if(!parent_grid) {
966  parent_grid = find_widget<grid>(content_grid, id, true, false);
967  assert(parent_grid);
968  }
969  if(grid* grandparent_grid = dynamic_cast<grid*>(parent_grid->parent())) {
970  grandparent_grid->swap_child(id, widget, false);
971  } else if(container_base* c
972  = dynamic_cast<container_base*>(parent_grid->parent())) {
973 
974  c->get_grid().swap_child(id, widget, true);
975  } else {
976  assert(false);
977  }
978 }
979 
980 } // namespace
981 
982 void window::finalize(const std::shared_ptr<builder_grid>& content_grid)
983 {
984  window_swap_grid(nullptr, &get_grid(), content_grid->build(), "_window_content_grid");
985 }
986 
987 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
988 
989 void window::generate_dot_file(const std::string& generator,
990  const unsigned domain)
991 {
992  debug_layout_->generate_dot_file(generator, domain);
993 }
994 #endif
995 
997  const unsigned maximum_width,
998  const unsigned maximum_height)
999 {
1001 
1002  /*
1003  * For now we return the status, need to test later whether this can
1004  * entirely be converted to an exception based system as in 'promised' on
1005  * the algorithm page.
1006  */
1007 
1008  try
1009  {
1010  point size = window.get_best_size();
1011 
1012  DBG_GUI_L << LOG_IMPL_HEADER << " best size : " << size
1013  << " maximum size : " << maximum_width << ','
1014  << maximum_height << ".\n";
1015  if(size.x <= static_cast<int>(maximum_width)
1016  && size.y <= static_cast<int>(maximum_height)) {
1017 
1018  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Fits, nothing to do.\n";
1019  return;
1020  }
1021 
1022  if(size.x > static_cast<int>(maximum_width)) {
1023  window.reduce_width(maximum_width);
1024 
1025  size = window.get_best_size();
1026  if(size.x > static_cast<int>(maximum_width)) {
1027  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Resize width failed."
1028  << " Wanted width " << maximum_width
1029  << " resulting width " << size.x << ".\n";
1031  }
1033  << " Status: Resize width succeeded.\n";
1034  }
1035 
1036  if(size.y > static_cast<int>(maximum_height)) {
1037  window.reduce_height(maximum_height);
1038 
1039  size = window.get_best_size();
1040  if(size.y > static_cast<int>(maximum_height)) {
1041  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Resize height failed."
1042  << " Wanted height " << maximum_height
1043  << " resulting height " << size.y << ".\n";
1045  }
1047  << " Status: Resize height succeeded.\n";
1048  }
1049 
1050  assert(size.x <= static_cast<int>(maximum_width)
1051  && size.y <= static_cast<int>(maximum_height));
1052 
1053 
1054  DBG_GUI_L << LOG_IMPL_HEADER << " Result: Resizing succeeded.\n";
1055  return;
1056  }
1057  catch(const layout_exception_width_modified&)
1058  {
1060  << " Status: Width has been modified, rerun.\n";
1061 
1062  window.layout_initialize(false);
1063  window.layout_linked_widgets();
1064  layout(window, maximum_width, maximum_height);
1065  return;
1066  }
1067 }
1068 
1069 void window::mouse_capture(const bool capture)
1070 {
1071  assert(event_distributor_);
1072  event_distributor_->capture_mouse(capture);
1073 }
1074 
1076 {
1077  assert(event_distributor_);
1078  event_distributor_->keyboard_capture(widget);
1079 }
1080 
1082 {
1083  assert(event_distributor_);
1084  event_distributor_->keyboard_add_to_chain(widget);
1085 }
1086 
1088 {
1089  assert(event_distributor_);
1090  event_distributor_->keyboard_remove_from_chain(widget);
1091 }
1092 
1094 {
1095  if(std::find(tab_order.begin(), tab_order.end(), widget) != tab_order.end()) {
1096  return;
1097  }
1098  assert(event_distributor_);
1099  if(tab_order.empty() && !event_distributor_->keyboard_focus()) {
1100  keyboard_capture(widget);
1101  }
1102  if(at < 0 || at >= static_cast<int>(tab_order.size())) {
1103  tab_order.push_back(widget);
1104  } else {
1105  tab_order.insert(tab_order.begin() + at, widget);
1106  }
1107 }
1108 
1110  bool& handled,
1111  const point& new_size)
1112 {
1113  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1114 
1117  settings::screen_width = new_size.x;
1118  settings::screen_height = new_size.y;
1120 
1121  handled = true;
1122 }
1123 
1125  bool& handled,
1126  bool& halt,
1127  const int mouse_button_mask)
1128 {
1129  DBG_GUI_E << LOG_HEADER << ' ' << event << " mouse_button_mask "
1130  << static_cast<unsigned>(mouse_button_mask) << ".\n";
1131 
1132  handled = halt = click_dismiss(mouse_button_mask);
1133 }
1134 
1135 static bool is_active(const widget* wgt)
1136 {
1137  if(const styled_widget* control = dynamic_cast<const styled_widget*>(wgt)) {
1138  return control->get_active() && control->get_visible() == widget::visibility::visible;
1139  }
1140  return false;
1141 }
1142 
1144  bool& handled,
1145  const SDL_Keycode key,
1146  const SDL_Keymod mod,
1147  bool handle_tab)
1148 {
1149  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1150 
1151  if(text_box_base* tb = dynamic_cast<text_box_base*>(event_distributor_->keyboard_focus())) {
1152  if(tb->is_composing()) {
1153  if(handle_tab && !tab_order.empty() && key == SDLK_TAB) {
1154  tb->interrupt_composition();
1155  } else {
1156  return;
1157  }
1158  }
1159  }
1160  if(!enter_disabled_ && (key == SDLK_KP_ENTER || key == SDLK_RETURN)) {
1162  handled = true;
1163  } else if(key == SDLK_ESCAPE && !escape_disabled_) {
1165  handled = true;
1166  } else if(key == SDLK_SPACE) {
1167  handled = click_dismiss(0);
1168  } else if(handle_tab && !tab_order.empty() && key == SDLK_TAB) {
1169  assert(event_distributor_);
1170  widget* focus = event_distributor_->keyboard_focus();
1171  auto iter = std::find(tab_order.begin(), tab_order.end(), focus);
1172  do {
1173  if(mod & KMOD_SHIFT) {
1174  if(iter == tab_order.begin()) {
1175  iter = tab_order.end();
1176  }
1177  iter--;
1178  } else {
1179  if(iter == tab_order.end()) {
1180  iter = tab_order.begin();
1181  } else {
1182  iter++;
1183  if(iter == tab_order.end()) {
1184  iter = tab_order.begin();
1185  }
1186  }
1187  }
1188  } while(!is_active(*iter));
1189  keyboard_capture(*iter);
1190  handled = true;
1191  }
1192 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
1193  if(key == SDLK_F12) {
1194  debug_layout_->generate_dot_file("manual", debug_layout_graph::MANUAL);
1195  handled = true;
1196  }
1197 #endif
1198 }
1199 
1201  bool& handled,
1203 {
1204  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1205 
1207  = dynamic_cast<event::message_show_tooltip&>(message);
1208 
1209  dialogs::tip::show(tooltip_.id, request.message, request.location, request.source_rect);
1210 
1211  handled = true;
1212 }
1213 
1215  bool& handled,
1217 {
1218  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1219 
1221  = dynamic_cast<event::message_show_helptip&>(message);
1222 
1223  dialogs::tip::show(helptip_.id, request.message, request.location, request.source_rect);
1224 
1225  handled = true;
1226 }
1227 
1229  bool& handled)
1230 {
1231  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
1232 
1234 
1235  handled = true;
1236 }
1237 
1239 {
1241 }
1242 
1243 // }---------- DEFINITION ---------{
1244 
1245 /*WIKI
1246  * @page = GUIWidgetDefinitionWML
1247  * @order = 1_window
1248  *
1249  * == Window ==
1250  *
1251  * The definition of a window. A window is a kind of panel see the panel for
1252  * which fields exist
1253  *
1254  * @begin{parent}{name="gui/"}
1255  * @begin{tag}{name="window_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
1256  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="gui/panel_definition/resolution"}
1257  * @allow{link}{name="gui/window/resolution/grid"}
1258  * @allow{link}{name="gui/panel_definition/resolution/background"}
1259  * @allow{link}{name="gui/panel_definition/resolution/foreground"}
1260  * @end{tag}{name="resolution"}
1261  * @end{tag}{name="window_definition"}
1262  * @end{parent}{name="gui/"}
1263  */
1266 {
1267  DBG_GUI_P << "Parsing window " << id << '\n';
1268 
1269  load_resolutions<resolution>(cfg);
1270 }
1271 
1273  : panel_definition::resolution(cfg), grid(nullptr)
1274 {
1275  const config& child = cfg.child("grid");
1276  // VALIDATE(child, _("No grid defined."));
1277 
1278  /** @todo Evaluate whether the grid should become mandatory. */
1279  if(child) {
1280  grid = std::make_shared<builder_grid>(child);
1281  }
1282 }
1283 
1284 // }------------ END --------------
1285 
1286 } // namespace gui2
1287 
1288 
1289 /**
1290  * @page layout_algorithm Layout algorithm
1291  *
1292  * @section introduction Introduction
1293  *
1294  * This page describes how the layout engine for the dialogs works. First
1295  * a global overview of some terms used in this document.
1296  *
1297  * - @ref gui2::widget "Widget"; Any item which can be used in the widget
1298  * toolkit. Not all widgets are visible. In general widgets cannot be
1299  * sized directly, but this is controlled by a window. A widget has an
1300  * internal size cache and if the value in the cache is not equal to 0,0
1301  * that value is its best size. This value gets set when the widget can
1302  * honor a resize request. It will be set with the value which honors
1303  * the request.
1304  *
1305  * - @ref gui2::grid "Grid"; A grid is an invisible container which holds
1306  * one or more widgets. Several widgets have a grid in them to hold
1307  * multiple widgets eg panels and windows.
1308  *
1309  * - @ref gui2::grid::child "Grid cell"; Every widget which is in a grid is
1310  * put in a grid cell. These cells also hold the information about the gaps
1311  * between widgets the behavior on growing etc. All grid cells must have a
1312  * widget inside them.
1313  *
1314  * - @ref gui2::window "Window"; A window is a top level item which has a
1315  * grid with its children. The window handles the sizing of the window and
1316  * makes sure everything fits.
1317  *
1318  * - @ref gui2::window::linked_size "Shared size group"; A shared size
1319  * group is a number of widgets which share width and or height. These
1320  * widgets are handled separately in the layout algorithm. All grid cells
1321  * width such a widget will get the same height and or width and these
1322  * widgets won't be resized when there's not enough size. To be sure that
1323  * these widgets don't cause trouble for the layout algorithm, they must be
1324  * in a container with scrollbars so there will always be a way to properly
1325  * layout them. The engine must enforce this restriction so the shared
1326  * layout property must be set by the engine after validation.
1327  *
1328  * - All visible grid cells; A grid cell is visible when the widget inside
1329  * of it doesn't have the state visibility::invisible. Widgets which have the
1330  * state @ref visibility::hidden are sized properly since when they become
1331  * @ref visibility::visible the layout shouldn't be invalidated. A grid cell
1332  * that's invisible has size 0,0.
1333  *
1334  * - All resizable grid cells; A grid cell is resizable under the following
1335  * conditions:
1336  * - The widget is visibility::visible.
1337  * - The widget is not in a shared size group.
1338  *
1339  * There are two layout algorithms with a different purpose.
1340  *
1341  * - The Window algorithm; this algorithm's goal is it to make sure all grid
1342  * cells fit in the window. Sizing the grid cells depends on the widget
1343  * size as well, but this algorithm only sizes the grid cells and doesn't
1344  * handle the widgets inside them.
1345  *
1346  * - The Grid algorithm; after the Window algorithm made sure that all grid
1347  * cells fit this algorithm makes sure the widgets are put in the optimal
1348  * state in their grid cell.
1349  *
1350  * @section layout_algorithm_window Window
1351  *
1352  * Here is the algorithm used to layout the window:
1353  *
1354  * - Perform a full initialization
1355  * (@ref gui2::widget::layout_initialize (full_initialization = true)):
1356  * - Clear the internal best size cache for all widgets.
1357  * - For widgets with scrollbars hide them unless the
1358  * @ref gui2::scrollbar_container::scrollbar_mode "scrollbar_mode" is
1359  * ALWAYS_VISIBLE or AUTO_VISIBLE.
1360  * - Handle shared sizes:
1361  * - Height and width:
1362  * - Get the best size for all widgets that share height and width.
1363  * - Set the maximum of width and height as best size for all these
1364  * widgets.
1365  * - Width only:
1366  * - Get the best width for all widgets which share their width.
1367  * - Set the maximum width for all widgets, but keep their own height.
1368  * - Height only:
1369  * - Get the best height for all widgets which share their height.
1370  * - Set the maximum height for all widgets, but keep their own width.
1371  * - Start layout loop:
1372  * - Get best size.
1373  * - If width <= maximum_width && height <= maximum_height we're done.
1374  * - If width > maximum_width, optimize the width:
1375  * - For every grid cell in a grid row there will be a resize request
1376  * (@ref gui2::grid::reduce_width):
1377  * - Sort the widgets in the row on the resize priority.
1378  * - Loop through this priority queue until the row fits
1379  * - If priority != 0 try to share the extra width else all
1380  * widgets are tried to reduce the full size.
1381  * - Try to shrink the widgets by either wrapping or using a
1382  * scrollbar (@ref gui2::widget::request_reduce_width).
1383  * - If the row fits in the wanted width this row is done.
1384  * - Else try the next priority.
1385  * - All priorities done and the width still doesn't fit.
1386  * - Loop through this priority queue until the row fits.
1387  * - If priority != 0:
1388  * - try to share the extra width
1389  * -Else:
1390  * - All widgets are tried to reduce the full size.
1391  * - Try to shrink the widgets by sizing them smaller as really
1392  * wanted (@ref gui2::widget::demand_reduce_width).
1393  * For labels, buttons etc. they get ellipsized.
1394  * - If the row fits in the wanted width this row is done.
1395  * - Else try the next priority.
1396  * - All priorities done and the width still doesn't fit.
1397  * - Throw a layout width doesn't fit exception.
1398  * - If height > maximum_height, optimize the height
1399  * (@ref gui2::grid::reduce_height):
1400  * - For every grid cell in a grid column there will be a resize request:
1401  * - Sort the widgets in the column on the resize priority.
1402  * - Loop through this priority queue until the column fits:
1403  * - If priority != 0 try to share the extra height else all
1404  * widgets are tried to reduce the full size.
1405  * - Try to shrink the widgets by using a scrollbar
1406  * (@ref gui2::widget::request_reduce_height).
1407  * - If succeeded for a widget the width is influenced and the
1408  * width might be invalid.
1409  * - Throw a width modified exception.
1410  * - If the column fits in the wanted height this column is done.
1411  * - Else try the next priority.
1412  * - All priorities done and the height still doesn't fit.
1413  * - Loop through this priority queue until the column fits.
1414  * - If priority != 0 try to share the extra height else all
1415  * widgets are tried to reduce the full size.
1416  * - Try to shrink the widgets by sizing them smaller as really
1417  * wanted (@ref gui2::widget::demand_reduce_width).
1418  * For labels, buttons etc. they get ellipsized .
1419  * - If the column fits in the wanted height this column is done.
1420  * - Else try the next priority.
1421  * - All priorities done and the height still doesn't fit.
1422  * - Throw a layout height doesn't fit exception.
1423  * - End layout loop.
1424  *
1425  * - Catch @ref gui2::layout_exception_width_modified "width modified":
1426  * - Goto relayout.
1427  *
1428  * - Catch
1429  * @ref gui2::layout_exception_width_resize_failed "width resize failed":
1430  * - If the window has a horizontal scrollbar which isn't shown but can be
1431  * shown.
1432  * - Show the scrollbar.
1433  * - goto relayout.
1434  * - Else show a layout failure message.
1435  *
1436  * - Catch
1437  * @ref gui2::layout_exception_height_resize_failed "height resize failed":
1438  * - If the window has a vertical scrollbar which isn't shown but can be
1439  * shown:
1440  * - Show the scrollbar.
1441  * - goto relayout.
1442  * - Else:
1443  * - show a layout failure message.
1444  *
1445  * - Relayout:
1446  * - Initialize all widgets
1447  * (@ref gui2::widget::layout_initialize (full_initialization = false))
1448  * - Handle shared sizes, since the reinitialization resets that state.
1449  * - Goto start layout loop.
1450  *
1451  * @section grid Grid
1452  *
1453  * This section will be documented later.
1454  */
Define the common log macros for the gui toolkit.
bool click_dismiss_
Do we want to have easy close behavior?
Definition: window.hpp:529
const std::string message
The message to show on the tooltip.
Definition: message.hpp:67
void keyboard_capture(widget *widget)
Definition: window.cpp:1075
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:504
void remove()
Removes a tip.
Definition: tooltip.cpp:189
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:1124
#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:256
std::function< bool(window &)> exit_hook_
Definition: window.hpp:730
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:1143
#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:619
typed_formula< unsigned > h_
The formula to calculate the height of the dialog.
Definition: window.hpp:498
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:472
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:475
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:134
CVideo & video_
Needed so we can change what&#39;s drawn on the screen.
Definition: window.hpp:425
void show_non_modal()
Shows the window non modal.
Definition: window.cpp:452
void generate_dot_file(const std::string &, const unsigned)
Definition: window.hpp:640
Helper struct to force widgets the have the same size.
Definition: window.hpp:544
#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:567
The message for MESSAGE_SHOW_HELPTIP.
Definition: message.hpp:77
Base class for all widgets.
Definition: widget.hpp:47
virtual const std::string & get_control_type() const override
Inherited from styled_widget, implemented by REGISTER_WIDGET.
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:1109
#define LOG_IMPL_HEADER
Definition: window.cpp:81
static CVideo & get_singleton()
Definition: video.hpp:48
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:1081
typed_formula< unsigned > w_
The formula to calculate the width of the dialog.
Definition: window.hpp:495
-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:612
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:555
The window has been closed.
Definition: window.hpp:156
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:1135
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:428
#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:552
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
#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:458
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:532
const SDL_Rect source_rect
The size of the entity requesting to show a helptip.
Definition: message.hpp:91
bool invalidate_layout_blocked_
Is invalidate_layout blocked, see invalidate_layout_blocker.
Definition: window.hpp:455
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:449
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:164
void signal_handler_close_window()
Definition: window.cpp:1238
typed_formula< bool > reevaluate_best_size_
The formula to determine whether the size is good.
Definition: window.hpp:501
builder_window::window_resolution::tooltip_info helptip_
The settings for the helptip.
Definition: window.hpp:510
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:982
The window is new and not yet shown.
Definition: window.hpp:150
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:492
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:464
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:641
typed_formula< unsigned > x_
The formula to calculate the x value of the dialog.
Definition: window.hpp:489
void set_mouse_behavior(const mouse_behavior mouse_behavior)
Definition: dispatcher.hpp:775
bool escape_disabled_
Disable the escape key see our setter for more info.
Definition: window.hpp:535
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
static window * window_instance(const unsigned handle)
Returns the instance of a window.
Definition: window.cpp:403
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
Definition: window.cpp:656
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: window.cpp:630
Helper class, don&#39;t construct this directly.
static const unsigned VERTICAL_ALIGN_TOP
Definition: grid.hpp:49
void remove_from_keyboard_chain(widget *widget)
Remove the widget from the keyboard chain.
Definition: window.cpp:1087
bool faked() const
Definition: video.hpp:65
unsigned maximum_height_
The maximum height if automatic_placement_ is true.
Definition: window.hpp:486
void signal_handler_message_show_tooltip(const event::ui_event event, bool &handled, event::message &message)
Definition: window.cpp:1200
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:483
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:152
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:480
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:565
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:651
bool click_dismiss(const int mouse_button_mask)
Handles a mouse click event for dismissing the dialog.
Definition: window.cpp:929
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:346
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:1228
builder_window::window_resolution::tooltip_info tooltip_
The settings for the tooltip.
Definition: window.hpp:507
show_mode show_mode_
The mode in which the window is shown.
Definition: window.hpp:435
static void layout(window &window, const unsigned maximum_width, const unsigned maximum_height)
Layouts the window.
Definition: window.cpp:996
window_definition(const config &cfg)
Definition: window.cpp:1264
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:417
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:140
void signal_handler_message_show_helptip(const event::ui_event event, bool &handled, event::message &message)
Definition: window.cpp:1214
const t_string & tooltip() const
void show_tooltip()
Shows the window as a tooltip.
Definition: window.cpp:430
unsigned screen_height
Definition: settings.cpp:26
Definition: contexts.hpp:43
void set_id(const std::string &id)
Definition: widget.cpp:94
void mouse_capture(const bool capture=true)
Definition: window.cpp:1069
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
void layout()
Layouts the window.
Definition: window.cpp:690
Simple push button.
Definition: button.hpp:35
void run_event_loop()
Definition: events.cpp:420
std::unique_ptr< event::distributor > event_distributor_
Definition: window.hpp:645
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:613
void draw_background()
Draws the background of a widget.
Definition: widget.cpp:398
friend class debug_layout_graph
Definition: window.hpp:65
dialogs::modal_dialog * owner_
The dialog that owns the window.
Definition: window.hpp:441
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:670
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:558
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:1093
mock_char c
void set_want_keyboard_input(const bool want_keyboard_input)
Definition: dispatcher.hpp:785
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:63
#define LOG_IMPL_SCOPE_HEADER
Definition: window.cpp:79
The window is being shown.
Definition: window.hpp:151
std::map< std::string, linked_size > linked_size_
List of the widgets, whose size are linked together.
Definition: window.hpp:562
wfl::map_formula_callable variables_
The variables of the canvas.
Definition: window.hpp:452
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:883
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:154
std::function< void()> callback_next_draw_
Definition: window.hpp:731
Basic exception when the layout doesn&#39;t fit.