The Battle for Wesnoth  1.19.5+dev
distributor.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
18 /**
19  * @file
20  * Contains the event distributor.
21  *
22  * The event distributor exists of several classes which are combined in one
23  * templated distributor class. The classes are closely tight together.
24  *
25  * All classes have direct access to each others members since they should act
26  * as one. (Since the buttons are a templated subclass it's not possible to use
27  * private subclasses.)
28  *
29  * The mouse_motion class handles the mouse motion and holds the owner of us
30  * since all classes virtually inherit us.
31  *
32  * The mouse_button classes are templated classes per mouse button, the
33  * template parameters are used to make the difference between the mouse
34  * buttons. Although it's easily possible to add more mouse buttons in the
35  * code several places only expect a left, middle and right button.
36  *
37  * distributor is the main class to be used in the user code. This class
38  * contains the handling of the keyboard as well.
39  */
40 
43 #include "sdl/point.hpp"
44 
45 #include <chrono>
46 #include <string>
47 #include <vector>
48 
49 namespace gui2
50 {
51 class widget;
52 
53 namespace event
54 {
55 
56 /***** ***** ***** ***** mouse_motion ***** ***** ***** ***** *****/
57 
59 {
60 public:
61  mouse_motion(widget& owner, const dispatcher::queue_position queue_position);
62 
63  ~mouse_motion();
64 
65  /**
66  * Captures the mouse input.
67  *
68  * When capturing the widget that has the mouse focus_ does the capturing.
69  *
70  * @param capture Set or release the capturing.
71  */
72  void capture_mouse(const bool capture = true);
73 
74 protected:
75  /** The widget that currently has the mouse focus_. */
77 
78  /** Did the current widget capture the focus_? */
80 
81  /** The widget that owns us. */
83 
84  /** The timer for the hover event. */
85  std::size_t hover_timer_;
86 
87  /** The widget which should get the hover event. */
89 
90  /** The anchor point of the hover event. */
92 
93  /**
94  * Has the hover been shown for the widget?
95  *
96  * A widget won't get a second hover event after the tooltip has been
97  * triggered. Only after (shortly) entering another widget it will be shown
98  * again for this widget.
99  */
101 
102  /**
103  * Starts the hover timer.
104  *
105  * @param widget The widget that wants the tooltip.
106  * @param coordinate The anchor coordinate.
107  */
109 
110  /** Stops the current hover timer. */
111  void stop_hover_timer();
112 
113  /**
114  * Called when the mouse enters a widget.
115  *
116  * @param mouse_over The widget that should receive the event.
117  */
118  void mouse_enter(widget* mouse_over);
119 
120  /** Called when the mouse leaves the current widget. */
121  void mouse_leave();
122 
123 private:
124  /**
125  * Called when the mouse moves over a widget.
126  *
127  * @param mouse_over The widget that should receive the event.
128  * @param coordinate The current screen coordinate of the mouse.
129  */
130  void mouse_hover(widget* mouse_over, const point& coordinate);
131 
132  /** Called when the mouse wants the widget to show its tooltip. */
133  void show_tooltip();
134 
136  void signal_handler_sdl_mouse_motion(const event::ui_event event, bool& handled, const point& coordinate);
137 
139  const event::ui_event event, bool& handled, const point& coordinate, const point& distance);
140 
141  void signal_handler_sdl_wheel(const event::ui_event event, bool& handled, const point& coordinate);
142 
143  void signal_handler_show_helptip(const event::ui_event event, bool& handled, const point& coordinate);
144 };
145 
146 /***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/
147 
148 template<std::size_t I>
149 class mouse_button : public virtual mouse_motion
150 {
151 public:
152  mouse_button(widget& owner, const dispatcher::queue_position queue_position);
153 
154  /**
155  * Initializes the state of the button.
156  *
157  * @param button_state The initial state of all buttons, in which the bit corresponding to
158  mouse_button_event_types.mask will be set if the button is down, or unset if it is up.
159  */
160  void initialize_state(int32_t button_state);
161 
162 protected:
163  /** The time of the last click used for double clicking. */
164  std::chrono::steady_clock::time_point last_click_stamp_;
165 
166  /** The widget the last click was on, used for double clicking. */
168 
169  /**
170  * If the mouse isn't captured we need to verify the up is on the same
171  * widget as the down so we send a proper click, also needed to send the
172  * up to the right widget.
173  */
175 
176 private:
177  /** Is the button down? */
178  bool is_down_;
179 
181  void signal_handler_sdl_button_down(const event::ui_event event, bool& handled, const point& coordinate);
182 
184  void signal_handler_sdl_button_up(const event::ui_event event, bool& handled, const point& coordinate);
185 
187 };
188 
189 /***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
190 
194 
195 /**
196  * The event handler class for the widget library.
197  *
198  * C++ doesn't allow multiple inheritance to directly use more than one instance of a
199  * superclass.
200  *
201  * It's a diamond inheritance, as all of these have virtual base class mouse_motion;
202  * refactoring that would allow these multiple classes to be replaced with a simple
203  * (distributor has-a std::array<mouse_button, 3>) relationship.
204  */
205 class distributor :
206  public mouse_button_left,
207  public mouse_button_middle,
208  public mouse_button_right
209 {
210 public:
211  distributor(widget& owner, const dispatcher::queue_position queue_position);
212 
213  ~distributor();
214 
215  /**
216  * Initializes the state of the keyboard and mouse.
217  *
218  * Needed after initialization and reactivation.
219  */
220  void initialize_state();
221 
222  /**
223  * Captures the keyboard input.
224  *
225  * @param widget The widget which should capture the keyboard.
226  * Sending nullptr releases the capturing.
227  */
229 
230  /**
231  * Adds the widget to the keyboard chain.
232  *
233  * @param widget The widget to add to the chain. The widget
234  * should be valid widget, which hasn't been
235  * added to the chain yet.
236  */
238 
239  /**
240  * Remove the widget from the keyboard chain.
241  *
242  * @param widget The widget to be removed from the chain.
243  */
245 
246  /**
247  * Return the widget currently capturing keyboard input.
248  */
249  widget* keyboard_focus() const;
250 
251 private:
252  /** The widget that holds the keyboard focus_. */
254 
255  /**
256  * Fall back keyboard focus_ items.
257  *
258  * When the focused widget didn't handle the keyboard event (or no handler
259  * for the keyboard focus_) it is send all widgets in this vector. The order
260  * is from rbegin() to rend(). If the keyboard_focus_ is in the vector it
261  * won't get the event twice. The first item added to the vector should be
262  * the window, so it will be the last handler and can dispatch the hotkeys
263  * registered.
264  */
265  std::vector<widget*> keyboard_focus_chain_;
266 
267  /**
268  * Set of functions that handle certain events and sends them to the proper
269  * widget. These functions are called by the SDL event handling functions.
270  */
271 
272  void signal_handler_sdl_key_down(const SDL_Keycode key,
273  const SDL_Keymod modifier,
274  const std::string& unicode);
275 
276  void signal_handler_sdl_text_input(const std::string& unicode, int32_t start, int32_t len);
277  void signal_handler_sdl_text_editing(const std::string& unicode, int32_t start, int32_t len);
278 
279  template<typename Fcn, typename P1, typename P2, typename P3>
280  void signal_handler_keyboard_internal(event::ui_event evt, P1&& p1, P2&& p2, P3&& p3);
281 
283 };
284 
285 } // namespace event
286 
287 } // namespace gui2
Base class for event handling.
Definition: dispatcher.hpp:150
queue_position
The position where to add a new callback in the signal handler.
Definition: dispatcher.hpp:331
The event handler class for the widget library.
widget * keyboard_focus_
The widget that holds the keyboard focus_.
void keyboard_add_to_chain(widget *widget)
Adds the widget to the keyboard chain.
void keyboard_capture(widget *widget)
Captures the keyboard input.
std::vector< widget * > keyboard_focus_chain_
Fall back keyboard focus_ items.
void signal_handler_keyboard_internal(event::ui_event evt, P1 &&p1, P2 &&p2, P3 &&p3)
void keyboard_remove_from_chain(widget *widget)
Remove the widget from the keyboard chain.
void signal_handler_sdl_text_editing(const std::string &unicode, int32_t start, int32_t len)
void signal_handler_sdl_key_down(const SDL_Keycode key, const SDL_Keymod modifier, const std::string &unicode)
Set of functions that handle certain events and sends them to the proper widget.
void initialize_state()
Initializes the state of the keyboard and mouse.
distributor(widget &owner, const dispatcher::queue_position queue_position)
widget * keyboard_focus() const
Return the widget currently capturing keyboard input.
void signal_handler_notify_removal(dispatcher &widget, const ui_event event)
void signal_handler_sdl_text_input(const std::string &unicode, int32_t start, int32_t len)
void signal_handler_sdl_button_down(const event::ui_event event, bool &handled, const point &coordinate)
widget * last_clicked_widget_
The widget the last click was on, used for double clicking.
mouse_button(widget &owner, const dispatcher::queue_position queue_position)
void initialize_state(int32_t button_state)
Initializes the state of the button.
bool is_down_
Is the button down?
void mouse_button_click(widget *widget)
std::chrono::steady_clock::time_point last_click_stamp_
The time of the last click used for double clicking.
void signal_handler_sdl_button_up(const event::ui_event event, bool &handled, const point &coordinate)
widget * focus_
If the mouse isn't captured we need to verify the up is on the same widget as the down so we send a p...
bool mouse_captured_
Did the current widget capture the focus_?
Definition: distributor.hpp:79
void mouse_hover(widget *mouse_over, const point &coordinate)
Called when the mouse moves over a widget.
widget * hover_widget_
The widget which should get the hover event.
Definition: distributor.hpp:88
void signal_handler_sdl_mouse_motion(const event::ui_event event, bool &handled, const point &coordinate)
mouse_motion(widget &owner, const dispatcher::queue_position queue_position)
Definition: distributor.cpp:67
void mouse_enter(widget *mouse_over)
Called when the mouse enters a widget.
bool hover_shown_
Has the hover been shown for the widget?
void signal_handler_sdl_touch_motion(const event::ui_event event, bool &handled, const point &coordinate, const point &distance)
void capture_mouse(const bool capture=true)
Captures the mouse input.
void signal_handler_show_helptip(const event::ui_event event, bool &handled, const point &coordinate)
void mouse_leave()
Called when the mouse leaves the current widget.
void signal_handler_sdl_wheel(const event::ui_event event, bool &handled, const point &coordinate)
point hover_position_
The anchor point of the hover event.
Definition: distributor.hpp:91
void stop_hover_timer()
Stops the current hover timer.
void start_hover_timer(widget *widget, const point &coordinate)
Starts the hover timer.
std::size_t hover_timer_
The timer for the hover event.
Definition: distributor.hpp:85
widget * mouse_focus_
The widget that currently has the mouse focus_.
Definition: distributor.hpp:76
widget & owner_
The widget that owns us.
Definition: distributor.hpp:82
void show_tooltip()
Called when the mouse wants the widget to show its tooltip.
Base class for all widgets.
Definition: widget.hpp:55
EXIT_STATUS start(bool clear_id, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
Generic file dialog.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
Holds a 2D point.
Definition: point.hpp:25