21 #define GETTEXT_DOMAIN "wesnoth-lib"
53 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
69 #define ERR_GUI LOG_STREAM(err, log_gui)
71 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
72 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
74 #define LOG_IMPL_SCOPE_HEADER \
75 window.get_control_type() + " [" + window.id() + "] " + __func__
76 #define LOG_IMPL_HEADER LOG_IMPL_SCOPE_HEADER + ':'
79 #define DBG_DP LOG_STREAM(debug, log_display)
80 #define LOG_DP LOG_STREAM(info, log_display)
81 #define WRN_DP LOG_STREAM(warn, log_display)
101 virtual std::unique_ptr<widget>
build()
const override
112 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
113 const unsigned SHOW = debug_layout_graph::SHOW;
114 const unsigned LAYOUT = debug_layout_graph::LAYOUT;
117 const unsigned SHOW = 0;
118 const unsigned LAYOUT = 0;
128 static uint32_t delay_event_callback(
const uint32_t,
void* event)
130 SDL_PushEvent(
static_cast<SDL_Event*
>(event));
131 delete static_cast<SDL_Event*
>(event);
144 static void delay_event(
const SDL_Event& event,
const uint32_t delay)
146 SDL_AddTimer(delay, delay_event_callback,
new SDL_Event(event));
154 static void helptip()
156 DBG_GUI_E <<
"Pushing SHOW_HELPTIP_EVENT event in queue.";
164 SDL_PushEvent(&event);
178 static manager& instance();
180 void add(window& window);
182 void remove(window& window);
184 unsigned get_id(window& window);
198 manager& manager::instance()
200 static manager window_manager;
201 return window_manager;
204 void manager::add(window& win)
214 if(itor->second == &win) {
223 unsigned manager::get_id(window& win)
225 for(
const auto& [
id, window_ptr] :
windows_) {
226 if(window_ptr == &win) {
254 , invalidate_layout_blocked_(false)
256 , automatic_placement_(definition.automatic_placement)
257 , horizontal_placement_(definition.horizontal_placement)
258 , vertical_placement_(definition.vertical_placement)
259 , maximum_width_(definition.maximum_width)
260 , maximum_height_(definition.maximum_height)
263 ,
w_(definition.width)
264 , h_(definition.height)
265 , reevaluate_best_size_(definition.reevaluate_best_size)
266 , functions_(definition.functions)
268 , helptip_(definition.helptip)
269 , click_dismiss_(definition.click_dismiss)
270 , enter_disabled_(false)
271 , escape_disabled_(false)
273 , mouse_button_state_(0)
274 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
275 , debug_layout_(new debug_layout_graph(this))
277 , event_distributor_(new event::distributor(*this, event::dispatcher::front_child))
278 , exit_hook_([] {
return true; })
280 manager::instance().add(*
this);
284 for(
const auto& [
id, fixed_width, fixed_height] : definition.linked_groups) {
285 if(!init_linked_size_group(
id, fixed_width, fixed_height)) {
286 FAIL(
VGETTEXT(
"Linked ‘$id’ group has multiple definitions.", {{
"id",
id}}));
290 const auto conf = cast_config_to<window_definition>();
294 init_grid(*conf->grid);
295 finalize(*definition.grid);
297 init_grid(*definition.grid);
300 add_to_keyboard_chain(
this);
302 connect_signal<event::SDL_VIDEO_RESIZE>(std::bind(
305 connect_signal<event::SDL_ACTIVATE>(std::bind(
308 connect_signal<event::SDL_LEFT_BUTTON_UP>(
311 std::placeholders::_2,
312 std::placeholders::_3,
313 std::placeholders::_4,
316 connect_signal<event::SDL_MIDDLE_BUTTON_UP>(
319 std::placeholders::_2,
320 std::placeholders::_3,
321 std::placeholders::_4,
324 connect_signal<event::SDL_RIGHT_BUTTON_UP>(
327 std::placeholders::_2,
328 std::placeholders::_3,
329 std::placeholders::_4,
334 connect_signal<event::SDL_KEY_DOWN>(
338 connect_signal<event::SDL_KEY_DOWN>(std::bind(
341 connect_signal<event::MESSAGE_SHOW_TOOLTIP>(
344 std::placeholders::_2,
345 std::placeholders::_3,
346 std::placeholders::_5),
349 connect_signal<event::MESSAGE_SHOW_HELPTIP>(
352 std::placeholders::_2,
353 std::placeholders::_3,
354 std::placeholders::_5),
357 connect_signal<event::REQUEST_PLACEMENT>(
397 manager::instance().remove(*
this);
416 }
else if(
id ==
"cancel" ||
id ==
"quit") {
430 LOG_DP <<
"connecting " <<
id() <<
" on show_tooltip";
462 LOG_DP <<
"connecting " <<
id() <<
" on show_non_modal";
496 LOG_DP <<
"connecting " <<
id() <<
" on show";
525 if(auto_close_timeout) {
532 delay_event(event, auto_close_timeout);
541 bool mouse_button_state_initialized =
false;
549 if(!mouse_button_state_initialized) {
561 mouse_button_state_initialized =
true;
582 tb->interrupt_composition();
627 LOG_DP <<
"disconnecting " <<
id() <<
" on hide";
642 bool raw_size_changed = buf_raw.x !=
render.x || buf_raw.y !=
render.y;
643 bool draw_size_changed = buf_draw.x !=
draw.x || buf_draw.y !=
draw.y;
644 if (!raw_size_changed && !draw_size_changed) {
649 if(raw_size_changed) {
650 LOG_DP <<
"regenerating window render buffer as " <<
render;
653 if(raw_size_changed || draw_size_changed) {
654 LOG_DP <<
"updating window render buffer draw size to " <<
draw;
684 LOG_DP <<
"deferring region " << screen_region;
712 DBG_DP <<
"window::expose " << region;
748 assert(window_.invalidate_layout_blocked_);
749 window_.invalidate_layout_blocked_ =
false;
764 const bool must_be_active)
const
782 assert(fixed_width || fixed_height);
783 auto [iter, success] =
linked_size_.try_emplace(
id, fixed_width, fixed_height);
796 ERR_GUI <<
"Unknown linked group '" <<
id <<
"'; skipping";
801 if(
std::find(widgets.begin(), widgets.end(), wgt) == widgets.end()) {
802 widgets.push_back(wgt);
814 auto itor =
std::find(widgets.begin(), widgets.end(), wgt);
816 if(itor != widgets.end()) {
819 assert(
std::find(widgets.begin(), widgets.end(), wgt)
829 DBG_DP <<
"window::layout";
833 const auto conf = cast_config_to<window_definition>();
868 button* click_dismiss_button = find_widget<button>(
"click_dismiss",
false,
false);
869 if(click_dismiss_button) {
873 button* btn = find_widget<button>(
"ok",
false,
false);
876 click_dismiss_button = btn;
879 _(
"Click dismiss needs a ‘click_dismiss’ or ‘ok’ button."));
897 std::stringstream sstr;
898 sstr << __FILE__ <<
":" << __LINE__ <<
" in function '" << __func__
899 <<
"' found the following problem: Failed to size window;"
901 << maximum_width <<
',' << maximum_height <<
" screen size "
905 "which doesn’t fit on the screen."),
911 assert(click_dismiss_button);
915 *click_dismiss_button,
926 *
this, maximum_width, maximum_height);
933 std::stringstream sstr;
934 sstr << __FILE__ <<
":" << __LINE__ <<
" in function '" << __func__
935 <<
"' found the following problem: Failed to size window;"
937 << maximum_width <<
',' << maximum_height <<
" screen size "
942 "which doesn’t fit on the screen."),
953 assert(
size.x >= 0 &&
static_cast<unsigned>(
size.x) <= maximum_width
954 &&
size.y >= 0 &&
static_cast<unsigned>(
size.y) <= maximum_height);
1030 point max_size(0, 0);
1038 if(
size.x > max_size.x) {
1039 max_size.x =
size.x;
1041 if(
size.y > max_size.y) {
1042 max_size.y =
size.y;
1059 size.x = max_size.x;
1062 size.y = max_size.y;
1088 static const std::string
id =
"_window_content_grid";
1094 assert(parent_grid);
1096 if(
grid* grandparent_grid =
dynamic_cast<grid*
>(parent_grid->parent())) {
1097 grandparent_grid->swap_child(
id, std::move(
widget),
false);
1099 c->get_grid().swap_child(
id, std::move(
widget),
true);
1105 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
1108 const unsigned domain)
1110 debug_layout_->generate_dot_file(
generator, domain);
1115 const unsigned maximum_width,
1116 const unsigned maximum_height)
1131 <<
" maximum size : " << maximum_width <<
','
1132 << maximum_height <<
".";
1133 if(
size.x <=
static_cast<int>(maximum_width)
1134 &&
size.y <=
static_cast<int>(maximum_height)) {
1140 if(
size.x >
static_cast<int>(maximum_width)) {
1144 if(
size.x >
static_cast<int>(maximum_width)) {
1146 <<
" Wanted width " << maximum_width
1147 <<
" resulting width " <<
size.x <<
".";
1151 <<
" Status: Resize width succeeded.";
1154 if(
size.y >
static_cast<int>(maximum_height)) {
1158 if(
size.y >
static_cast<int>(maximum_height)) {
1160 <<
" Wanted height " << maximum_height
1161 <<
" resulting height " <<
size.y <<
".";
1165 <<
" Status: Resize height succeeded.";
1168 assert(
size.x <=
static_cast<int>(maximum_width)
1169 &&
size.y <=
static_cast<int>(maximum_height));
1178 <<
" Status: Width has been modified, rerun.";
1220 if(at < 0 || at >=
static_cast<int>(
tab_order.size())) {
1229 const point& new_size)
1245 const int mouse_button_mask)
1248 <<
static_cast<unsigned>(mouse_button_mask) <<
".";
1263 const SDL_Keycode key,
1264 const SDL_Keymod mod,
1270 if(tb->is_composing()) {
1271 if(handle_tab && !
tab_order.empty() && key == SDLK_TAB) {
1272 tb->interrupt_composition();
1278 if(key == SDLK_KP_ENTER || key == SDLK_RETURN) {
1279 if (mod & (KMOD_CTRL | KMOD_ALT | KMOD_GUI | KMOD_SHIFT)) {
1293 }
else if(key == SDLK_SPACE) {
1295 }
else if(handle_tab && !
tab_order.empty() && key == SDLK_TAB) {
1300 if(mod & KMOD_SHIFT) {
1319 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
1320 if(key == SDLK_F12) {
1321 debug_layout_->generate_dot_file(
"manual", debug_layout_graph::MANUAL);
1377 load_resolutions<resolution>(cfg);
1388 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)
Equivalent 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_view 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.
void connect()
Connects the dispatcher to the event handler.
void set_mouse_behavior(const mouse_behavior mouse_behavior)
void disconnect()
Disconnects the dispatcher from the event handler.
void set_want_keyboard_input(const bool want_keyboard_input)
bool is_connected() const
Return whether the dispatcher is currently connected.
void initialize_state()
Initializes the state of the keyboard and mouse.
Basic template class to generate new items.
static const unsigned HORIZONTAL_ALIGN_RIGHT
unsigned int get_rows() const
static const unsigned VERTICAL_ALIGN_BOTTOM
static const unsigned VERTICAL_ALIGN_CENTER
static const unsigned HORIZONTAL_ALIGN_CENTER
void remove_child(const unsigned row, const unsigned col)
Removes and frees a widget in a cell.
static const unsigned VERTICAL_ALIGN_TOP
unsigned int get_cols() const
static const unsigned HORIZONTAL_ALIGN_LEFT
builder_window(const config &cfg)
virtual std::unique_ptr< widget > build() const override
Abstract base class for text items.
invalidate_layout_blocker(window &window)
~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.
virtual rect screen_location() override
The current draw location of the window, on the screen.
void update_render_textures()
Ensure render textures are valid and correct.
void show_tooltip()
Shows the window as a tooltip.
int mouse_button_state_
The state of the mouse button.
void hide()
Hides the window.
void show_non_modal()
Shows the window non modal.
std::unique_ptr< event::distributor > event_distributor_
void signal_handler_sdl_video_resize(const event::ui_event event, bool &handled, const point &new_size)
std::map< std::string, linked_size, std::less<> > linked_size_
List of the widgets, whose size are linked together.
static window * window_instance(const unsigned handle)
Returns the instance of a window.
status
The status of the window.
@ CLOSED
The window has been closed.
@ NEW
The window is new and not yet shown.
@ SHOWING
The window is being shown.
@ REQUEST_CLOSE
The window has been requested to be closed but still needs to evaluate the request.
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.
show_mode show_mode_
The mode in which the window is shown.
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.
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
int show(unsigned auto_close_timeout=0)
Shows the window, running an event loop until it should close.
rect awaiting_rerender_
The part of the window (if any) currently marked for rerender.
void signal_handler_request_placement(const event::ui_event event, bool &handled)
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.
void defer_region(const rect ®ion)
Defer rendering of a particular region to next frame.
const unsigned horizontal_placement_
Sets the horizontal placement.
static retval get_retval_by_id(const std::string &id)
Gets the retval for the default buttons.
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.
std::function< bool()> exit_hook_
std::vector< rect > deferred_regions_
Parts of the window (if any) with rendering deferred to next frame.
bool hidden_
Avoid drawing the window.
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)
virtual bool expose(const rect ®ion) override
Called by draw_manager when it believes a redraw is necessary.
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.
virtual void render() override
Ensure the window's internal render buffer is up-to-date.
bool init_linked_size_group(const std::string &id, const bool fixed_width, const bool fixed_height)
Initializes a linked size group.
void draw()
Draws the window.
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.
status status_
The status of the window.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
texture render_buffer_
The internal render buffer used by render() and expose().
bool has_linked_size_group(const std::string &id)
Is the linked size group defined for this window?
Wrapper class to encapsulate creation and management of an SDL_Texture.
void set_src(const rect &r)
Set the source region of the texture used for drawing operations.
point draw_size() const
The size of the texture in draw-space.
void set_draw_size(int w, int h)
Set the intended size of the texture, in draw-space.
point get_raw_size() const
The raw internal texture size.
void clear_src()
Clear the source region.
Definitions for the interface to Wesnoth Markup Language (WML).
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 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)
render_target_setter set_render_target(const texture &t)
Set the given texture as the active render target.
clip_setter override_clip(const SDL_Rect &clip)
Override the clipping area.
void clear()
Clear the current render target.
void blit(const texture &tex, const SDL_Rect &dst)
Draws a texture, or part of a texture, at the given location.
::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.
constexpr const SDL_Rect empty_rect
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
std::size_t size(std::string_view 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(...).
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
SDL_Window * get_window()
int get_pixel_scale()
Get the current active pixel scale multiplier.
void toggle_fullscreen()
Toggle fullscreen mode.
Contains the SDL_Rect helper code.
This file contains the settings handling of the widget library.
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
virtual std::unique_ptr< widget > build() const override
Inherited from builder_widget.
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.
bool empty() const
False if both w and h are > 0, true otherwise.
rect & expand_to_cover(const SDL_Rect &r)
Minimally expand this rect to fully contain another.
void clip(const SDL_Rect &r)
Clip this rectangle by the given rectangle.
void shift(const point &p)
Shift the rectangle by the given relative position.
rect intersect(const SDL_Rect &r) const
Calculates the intersection of this rectangle and another; that is, the maximal rectangle that is con...
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.