21 #define GETTEXT_DOMAIN "wesnoth-lib"
54 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
74 namespace wfl {
class function_symbol_table; }
75 namespace gui2 {
class button; }
78 #define ERR_GUI LOG_STREAM(err, log_gui)
80 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
81 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
83 #define LOG_IMPL_SCOPE_HEADER \
84 window.get_control_type() + " [" + window.id() + "] " + __func__
85 #define LOG_IMPL_HEADER LOG_IMPL_SCOPE_HEADER + ':'
88 #define DBG_DP LOG_STREAM(debug, log_display)
89 #define LOG_DP LOG_STREAM(info, log_display)
90 #define WRN_DP LOG_STREAM(warn, log_display)
110 virtual std::unique_ptr<widget>
build()
const override
121 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
122 const unsigned SHOW = debug_layout_graph::SHOW;
123 const unsigned LAYOUT = debug_layout_graph::LAYOUT;
126 const unsigned SHOW = 0;
127 const unsigned LAYOUT = 0;
137 static uint32_t delay_event_callback(
const uint32_t,
void* event)
139 SDL_PushEvent(
static_cast<SDL_Event*
>(event));
140 delete static_cast<SDL_Event*
>(event);
153 static void delay_event(
const SDL_Event& event,
const uint32_t delay)
155 SDL_AddTimer(delay, delay_event_callback,
new SDL_Event(event));
163 static void helptip()
165 DBG_GUI_E <<
"Pushing SHOW_HELPTIP_EVENT event in queue.";
173 SDL_PushEvent(&event);
187 static manager& instance();
189 void add(window& window);
191 void remove(window& window);
193 unsigned get_id(window& window);
207 manager& manager::instance()
209 static manager window_manager;
210 return window_manager;
213 void manager::add(window& win)
226 if(itor->second == &win) {
234 unsigned manager::get_id(window& win)
240 if(itor->second == &win) {
270 , invalidate_layout_blocked_(false)
272 , automatic_placement_(definition.automatic_placement)
273 , horizontal_placement_(definition.horizontal_placement)
274 , vertical_placement_(definition.vertical_placement)
275 , maximum_width_(definition.maximum_width)
276 , maximum_height_(definition.maximum_height)
279 ,
w_(definition.width)
280 , h_(definition.height)
281 , reevaluate_best_size_(definition.reevaluate_best_size)
282 , functions_(definition.functions)
284 , helptip_(definition.helptip)
285 , click_dismiss_(false)
286 , enter_disabled_(false)
287 , escape_disabled_(false)
289 , mouse_button_state_(0)
290 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
291 , debug_layout_(new debug_layout_graph(this))
293 , event_distributor_(new event::distributor(*this, event::dispatcher::front_child))
294 , exit_hook_([](
window&)->bool { return true; })
296 manager::instance().add(*
this);
300 connect_signal<event::SDL_VIDEO_RESIZE>(std::bind(
301 &window::signal_handler_sdl_video_resize,
this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5));
303 connect_signal<event::SDL_ACTIVATE>(std::bind(
304 &event::distributor::initialize_state, event_distributor_.get()));
306 connect_signal<event::SDL_LEFT_BUTTON_UP>(
307 std::bind(&window::signal_handler_click_dismiss,
309 std::placeholders::_2,
310 std::placeholders::_3,
311 std::placeholders::_4,
313 event::dispatcher::front_child);
314 connect_signal<event::SDL_MIDDLE_BUTTON_UP>(
315 std::bind(&window::signal_handler_click_dismiss,
317 std::placeholders::_2,
318 std::placeholders::_3,
319 std::placeholders::_4,
321 event::dispatcher::front_child);
322 connect_signal<event::SDL_RIGHT_BUTTON_UP>(
323 std::bind(&window::signal_handler_click_dismiss,
325 std::placeholders::_2,
326 std::placeholders::_3,
327 std::placeholders::_4,
329 event::dispatcher::front_child);
331 connect_signal<event::SDL_KEY_DOWN>(
333 &window::signal_handler_sdl_key_down,
this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5, std::placeholders::_6,
true),
334 event::dispatcher::back_post_child);
335 connect_signal<event::SDL_KEY_DOWN>(std::bind(
336 &window::signal_handler_sdl_key_down,
this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5, std::placeholders::_6,
false));
338 connect_signal<event::MESSAGE_SHOW_TOOLTIP>(
339 std::bind(&window::signal_handler_message_show_tooltip,
341 std::placeholders::_2,
342 std::placeholders::_3,
343 std::placeholders::_5),
344 event::dispatcher::back_pre_child);
346 connect_signal<event::MESSAGE_SHOW_HELPTIP>(
347 std::bind(&window::signal_handler_message_show_helptip,
349 std::placeholders::_2,
350 std::placeholders::_3,
351 std::placeholders::_5),
352 event::dispatcher::back_pre_child);
354 connect_signal<event::REQUEST_PLACEMENT>(
356 &window::signal_handler_request_placement,
this, std::placeholders::_2, std::placeholders::_3),
357 event::dispatcher::back_pre_child);
359 connect_signal<event::CLOSE_WINDOW>(std::bind(&window::signal_handler_close_window,
this));
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);
390 if(show_mode_ == show_mode::modal) {
394 manager::instance().remove(*
this);
401 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
403 delete debug_layout_;
413 retval window::get_retval_by_id(
const std::string&
id)
419 }
else if(
id ==
"cancel" ||
id ==
"quit") {
429 if(has_linked_size_group(
lg.id)) {
435 init_linked_size_group(
lg.id,
lg.fixed_width,
lg.fixed_height);
440 const auto conf = cast_config_to<window_definition>();
444 init_grid(*conf->grid);
445 finalize(*definition.
grid);
447 init_grid(*definition.
grid);
450 add_to_keyboard_chain(
this);
453 void window::show_tooltip()
459 if(!is_connected()) {
460 LOG_DP <<
"connecting " <<
id() <<
" on show_tooltip";
466 generate_dot_file(
"show", SHOW);
468 assert(status_ == status::NEW);
470 set_mouse_behavior(event::dispatcher::mouse_behavior::none);
471 set_want_keyboard_input(
false);
482 DBG_DP <<
"show tooltip queued to " << get_rectangle();
485 void window::show_non_modal()
491 if(!is_connected()) {
492 LOG_DP <<
"connecting " <<
id() <<
" on show_non_modal";
498 generate_dot_file(
"show", SHOW);
500 assert(status_ == status::NEW);
502 set_mouse_behavior(event::dispatcher::mouse_behavior::hit);
504 show_mode_ = show_mode::modeless;
514 DBG_DP <<
"show non-modal queued to " << get_rectangle();
525 if(!is_connected()) {
526 LOG_DP <<
"connecting " <<
id() <<
" on show";
536 show_mode_ = show_mode::modal;
540 generate_dot_file(
"show", SHOW);
555 if(auto_close_timeout) {
562 delay_event(event, auto_close_timeout);
568 bool mouse_button_state_initialized =
false;
569 for(status_ = status::SHOWING; status_ != status::CLOSED;) {
573 if(!mouse_button_state_initialized) {
585 mouse_button_state_initialized =
true;
589 if(status_ == status::REQUEST_CLOSE) {
590 status_ = exit_hook_(*
this) ? status::CLOSED : status::SHOWING;
606 tb->interrupt_composition();
622 this->draw_background();
625 this->draw_children();
628 this->draw_foreground();
642 LOG_DP <<
"disconnecting " <<
id() <<
" on hide";
651 DBG_DP <<
"window::expose " << region;
652 rect i = get_rectangle().intersect(region);
666 return get_rectangle();
669 window::invalidate_layout_blocker::invalidate_layout_blocker(
window&
window)
678 assert(window_.invalidate_layout_blocked_);
679 window_.invalidate_layout_blocked_ =
false;
694 const bool must_be_active)
const
711 const bool fixed_width,
712 const bool fixed_height)
714 assert(fixed_width || fixed_height);
729 ERR_GUI <<
"Unknown linked group '" <<
id <<
"'; skipping";
734 if(std::find(widgets.begin(), widgets.end(), wgt) == widgets.end()) {
735 widgets.push_back(wgt);
749 = std::find(widgets.begin(), widgets.end(), wgt);
751 if(itor != widgets.end()) {
754 assert(std::find(widgets.begin(), widgets.end(), wgt)
764 DBG_DP <<
"window::layout";
768 const auto conf = cast_config_to<window_definition>();
803 button* click_dismiss_button =
nullptr;
804 if((click_dismiss_button
805 = find_widget<button>(
this,
"click_dismiss",
false,
false))) {
810 button* btn = find_widget<button>(
this,
"ok",
false,
false);
813 click_dismiss_button = btn;
816 _(
"Click dismiss needs a 'click_dismiss' or 'ok' button."));
834 std::stringstream sstr;
835 sstr << __FILE__ <<
":" << __LINE__ <<
" in function '" << __func__
836 <<
"' found the following problem: Failed to size window;"
838 << maximum_width <<
',' << maximum_height <<
" screen size "
842 "which doesn't fit on the screen."),
848 assert(click_dismiss_button);
852 *click_dismiss_button,
863 *
this, maximum_width, maximum_height);
870 std::stringstream sstr;
871 sstr << __FILE__ <<
":" << __LINE__ <<
" in function '" << __func__
872 <<
"' found the following problem: Failed to size window;"
874 << maximum_width <<
',' << maximum_height <<
" screen size "
879 "which doesn't fit on the screen."),
890 assert(
size.x >= 0 &&
static_cast<unsigned>(
size.x) <= maximum_width
891 &&
size.y >= 0 &&
static_cast<unsigned>(
size.y) <= maximum_height);
967 point max_size(0, 0);
975 if(
size.x > max_size.x) {
978 if(
size.y > max_size.y) {
1025 static const std::string
id =
"_window_content_grid";
1030 auto* parent_grid = find_widget<grid>(&
get_grid(),
id,
true,
false);
1031 assert(parent_grid);
1033 if(
grid* grandparent_grid =
dynamic_cast<grid*
>(parent_grid->parent())) {
1034 grandparent_grid->swap_child(
id, std::move(
widget),
false);
1036 c->get_grid().swap_child(
id, std::move(
widget),
true);
1042 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
1045 const unsigned domain)
1047 debug_layout_->generate_dot_file(
generator, domain);
1052 const unsigned maximum_width,
1053 const unsigned maximum_height)
1068 <<
" maximum size : " << maximum_width <<
','
1069 << maximum_height <<
".";
1070 if(
size.x <=
static_cast<int>(maximum_width)
1071 &&
size.y <=
static_cast<int>(maximum_height)) {
1077 if(
size.x >
static_cast<int>(maximum_width)) {
1081 if(
size.x >
static_cast<int>(maximum_width)) {
1083 <<
" Wanted width " << maximum_width
1084 <<
" resulting width " <<
size.x <<
".";
1088 <<
" Status: Resize width succeeded.";
1091 if(
size.y >
static_cast<int>(maximum_height)) {
1095 if(
size.y >
static_cast<int>(maximum_height)) {
1097 <<
" Wanted height " << maximum_height
1098 <<
" resulting height " <<
size.y <<
".";
1102 <<
" Status: Resize height succeeded.";
1105 assert(
size.x <=
static_cast<int>(maximum_width)
1106 &&
size.y <=
static_cast<int>(maximum_height));
1115 <<
" Status: Width has been modified, rerun.";
1157 if(at < 0 || at >=
static_cast<int>(
tab_order.size())) {
1166 const point& new_size)
1182 const int mouse_button_mask)
1185 <<
static_cast<unsigned>(mouse_button_mask) <<
".";
1200 const SDL_Keycode key,
1201 const SDL_Keymod mod,
1207 if(tb->is_composing()) {
1208 if(handle_tab && !
tab_order.empty() && key == SDLK_TAB) {
1209 tb->interrupt_composition();
1215 if(!
enter_disabled_ && (key == SDLK_KP_ENTER || key == SDLK_RETURN)) {
1221 }
else if(key == SDLK_SPACE) {
1223 }
else if(handle_tab && !
tab_order.empty() && key == SDLK_TAB) {
1228 if(mod & KMOD_SHIFT) {
1247 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
1248 if(key == SDLK_F12) {
1249 debug_layout_->generate_dot_file(
"manual", debug_layout_graph::MANUAL);
1305 load_resolutions<resolution>(cfg);
1316 grid = std::make_shared<builder_grid>(*child);
A config object defines a single node in a WML file, with access to child nodes.
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Euivalent to mandatory_child, but returns an empty optional if the nth child was not found.
A generic container base class.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
void reduce_height(const unsigned maximum_height)
Tries to reduce the height of a container.
const grid & get_grid() const
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
void reduce_width(const unsigned maximum_width)
Tries to reduce the width of a container.
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
virtual void place(const point &origin, const point &size) override
See widget::place.
Main class to show messages to the user.
Basic template class to generate new items.
static const unsigned HORIZONTAL_ALIGN_RIGHT
static const unsigned VERTICAL_ALIGN_BOTTOM
static const unsigned VERTICAL_ALIGN_CENTER
static const unsigned HORIZONTAL_ALIGN_CENTER
static const unsigned VERTICAL_ALIGN_TOP
static const unsigned HORIZONTAL_ALIGN_LEFT
builder_window(const config &cfg)
virtual std::unique_ptr< widget > build() const override
A panel is a visible container to hold multiple widgets.
Abstract base class for text items.
~invalidate_layout_blocker()
base class of top level items, the only item which needs to store the final canvases to draw on.
bool need_layout_
When set the form needs a full layout redraw cycle.
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
const unsigned vertical_placement_
Sets the vertical placement.
bool invalidate_layout_blocked_
Is invalidate_layout blocked, see invalidate_layout_blocker.
typed_formula< bool > reevaluate_best_size_
The formula to determine whether the size is good.
typed_formula< unsigned > maximum_width_
The maximum width if automatic_placement_ is true.
void remove_from_keyboard_chain(widget *widget)
Remove the widget from the keyboard chain.
void keyboard_capture(widget *widget)
void invalidate_layout()
Updates the size of the window.
void add_to_keyboard_chain(widget *widget)
Adds the widget to the keyboard chain.
void signal_handler_message_show_tooltip(const event::ui_event event, bool &handled, const event::message &message)
void mouse_capture(const bool capture=true)
typed_formula< unsigned > maximum_height_
The maximum height if automatic_placement_ is true.
int mouse_button_state_
The state of the mouse button.
std::unique_ptr< event::distributor > event_distributor_
void signal_handler_sdl_video_resize(const event::ui_event event, bool &handled, const point &new_size)
status
The status of the window.
builder_window::window_resolution::tooltip_info tooltip_
The settings for the tooltip.
void signal_handler_sdl_key_down(const event::ui_event event, bool &handled, const SDL_Keycode key, const SDL_Keymod mod, bool handle_tab)
virtual void layout() override
Lays out the window.
void signal_handler_message_show_helptip(const event::ui_event event, bool &handled, const event::message &message)
void layout_linked_widgets()
Layouts the linked widgets.
std::vector< widget * > tab_order
List of widgets in the tabbing order.
typed_formula< unsigned > h_
The formula to calculate the height of the dialog.
void signal_handler_request_placement(const event::ui_event event, bool &handled)
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
bool escape_disabled_
Disable the escape key see our setter for more info.
bool does_click_dismiss() const
Does the window close easily?
void signal_handler_close_window()
bool click_dismiss_
Do we want to have easy close behavior?
void add_linked_widget(const std::string &id, widget *widget)
Adds a widget to a linked size group.
const unsigned horizontal_placement_
Sets the horizontal placement.
void add_to_tab_order(widget *widget, int at=-1)
Add the widget to the tabbing order.
const bool automatic_placement_
Do we wish to place the widget automatically?
void finalize(const builder_grid &content_grid)
Finishes the initialization of the grid.
builder_window::window_resolution::tooltip_info helptip_
The settings for the helptip.
bool click_dismiss(const int mouse_button_mask)
Handles a mouse click event for dismissing the dialog.
typed_formula< unsigned > x_
The formula to calculate the x value of the dialog.
typed_formula< unsigned > y_
The formula to calculate the y value of the dialog.
void generate_dot_file(const std::string &, const unsigned)
wfl::map_formula_callable variables_
The variables of the canvas.
void remove_linked_widget(const std::string &id, const widget *widget)
Removes a widget from a linked size group.
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 'event'.
bool enter_disabled_
Disable the enter key see our setter for more info.
void init_linked_size_group(const std::string &id, const bool fixed_width, const bool fixed_height)
Initializes a linked size group.
typed_formula< unsigned > w_
The formula to calculate the width of the dialog.
wfl::function_symbol_table functions_
The formula definitions available for the calculation formulas.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
std::map< std::string, linked_size > linked_size_
List of the widgets, whose size are linked together.
bool has_linked_size_group(const std::string &id)
Is the linked size group defined for this window?
This file contains the definitions for the gui2::event::message class.
Contains the event distributor.
Drawing functions, for drawing things on the screen.
#define CLOSE_WINDOW_EVENT
#define SHOW_HELPTIP_EVENT
static std::string _(const char *str)
Define the common log macros for the gui toolkit.
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
std::string id
Text to match against addon_info.tags()
Defines the exception classes for the layout algorithm.
Standard logging facilities (interface).
#define log_scope2(domain, description)
::rect get_clip()
Get the current clipping area, in draw coordinates.
void draw()
Trigger a draw cycle.
void pump_and_draw()
pump() then immediately draw()
void pump()
Process all events currently in the queue.
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
void remove()
Removes a tip.
ui_event
The event sent to the dispatcher.
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
void init_mouse_location()
Initializes the location of the mouse.
unsigned screen_width
The screen resolution and pixel pitch should be available for all widgets since their drawing method ...
unsigned gamemap_width
The size of the map area, if not available equal to the screen size.
void get_screen_size_variables(wfl::map_formula_callable &variable)
Gets a formula object with the screen size.
static bool is_active(const widget *wgt)
lg::log_domain log_gui_draw("gui/draw")
point get_mouse_position()
Returns the current mouse position.
retval
Default window/dialog return values.
@ OK
Dialog was closed with the OK button.
@ AUTO_CLOSE
The dialog was closed automatically as its timeout had been reached.
@ CANCEL
Dialog was closed with the CANCEL button.
@ NONE
Default, unset return value.
lg::log_domain log_gui_layout("gui/layout")
std::shared_ptr< halo_record > handle
Contains the implementation details for lexical_cast and shouldn't be used directly.
static std::string at(const std::string &file, int line)
uint32_t get_mouse_button_mask()
Returns the current mouse button mask.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
SDL_Window * get_window()
void toggle_fullscreen()
Toggle fullscreen mode.
std::string::const_iterator iterator
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Contains the SDL_Rect helper code.
This file contains the settings handling of the widget library.
virtual std::unique_ptr< widget > build() const override
Inherited from builder_widget.
std::vector< linked_group_definition > linked_groups
The message for MESSAGE_SHOW_HELPTIP.
const SDL_Rect source_rect
The size of the entity requesting to show a helptip.
const point location
The location where to show the helptip.
const std::string message
The message to show on the helptip.
The message callbacks hold a reference to a message.
Exception thrown when the height resizing has failed.
Basic exception when the layout doesn't fit.
Exception thrown when the width has been modified during resizing.
Exception thrown when the width resizing has failed.
Helper struct to force widgets the have the same size.
int height
The current height of all widgets in the group, -1 if the height is not linked.
int width
The current width of all widgets in the group, -1 if the width is not linked.
std::vector< widget * > widgets
The widgets linked.
resolution(const config &cfg)
window_definition(const config &cfg)
static void layout(window &window, const unsigned maximum_width, const unsigned maximum_height)
Layouts the window.
An abstract description of a rectangle with integer coordinates.
Helper class, don't construct this directly.
Helper for header for the window.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE(cond, message)
The macro to use for the validation of WML.