The Battle for Wesnoth  1.17.0-dev
distributor.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2021
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 #include "video.hpp"
45 
46 #include <string>
47 #include <vector>
48 
49 namespace gui2
50 {
51 
52 class widget;
53 
54 namespace event
55 {
56 
57 /***** ***** ***** ***** mouse_motion ***** ***** ***** ***** *****/
58 
60 {
61 public:
62  mouse_motion(widget& owner, const dispatcher::queue_position queue_position);
63 
64  ~mouse_motion();
65 
66  /**
67  * Captures the mouse input.
68  *
69  * When capturing the widget that has the mouse focus_ does the capturing.
70  *
71  * @param capture Set or release the capturing.
72  */
73  void capture_mouse( // widget* widget);
74  const bool capture = true);
75 
76 protected:
77  /** The widget that currently has the mouse focus_. */
79 
80  /** Did the current widget capture the focus_? */
82 
83  /** The widget that owns us. */
85 
86  /** The timer for the hover event. */
87  std::size_t hover_timer_;
88 
89  /** The widget which should get the hover event. */
91 
92  /** The anchor point of the hover event. */
94 
95  /**
96  * Has the hover been shown for the widget?
97  *
98  * A widget won't get a second hover event after the tooltip has been
99  * triggered. Only after (shortly) entering another widget it will be shown
100  * again for this widget.
101  */
103 
104  /**
105  * Starts the hover timer.
106  *
107  * @param widget The widget that wants the tooltip.
108  * @param coordinate The anchor coordinate.
109  */
111 
112  /** Stops the current hover timer. */
113  void stop_hover_timer();
114 
115  /**
116  * Called when the mouse enters a widget.
117  *
118  * @param mouse_over The widget that should receive the event.
119  */
120  void mouse_enter(widget* mouse_over);
121 
122  /** Called when the mouse leaves the current widget. */
123  void mouse_leave();
124 
125 private:
126  /**
127  * Called when the mouse moves over a widget.
128  *
129  * @param mouse_over The widget that should receive the event.
130  * @param coordinate The current screen coordinate of the mouse.
131  */
132  void mouse_hover(widget* mouse_over, const point& coordinate);
133 
134  /** Called when the mouse wants the widget to show its tooltip. */
135  void show_tooltip();
136 
139  bool& handled,
140  const point& coordinate);
141 
143  bool& handled,
144  const point& coordinate,
145  const point& distance);
146 
147  void signal_handler_sdl_wheel(const event::ui_event event,
148  bool& handled,
149  const point& coordinate);
150 
152  bool& handled,
153  const point& coordinate);
154 };
155 
156 /***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/
157 
158 /**
159  * Small helper metastruct to configure instances of mouse_button.
160  */
162 {
169  /** Bitmask corresponding to this button's bit in SDL_GetMouseState's return value */
170  int32_t mask;
171  /** used for debug messages. */
172  std::string name;
173 };
174 
175 class mouse_button : public virtual mouse_motion
176 {
177 public:
179  widget& owner,
180  const dispatcher::queue_position queue_position);
181 
182  /**
183  * Initializes the state of the button.
184  *
185  * @param button_state The initial state of all buttons, in which the bit corresponding to
186  mouse_button_event_types.mask will be set if the button is down, or unset if it is up.
187  */
188  void initialize_state(int32_t button_state);
189 
190 protected:
191  /** The time of the last click used for double clicking. */
193 
194  /** The widget the last click was on, used for double clicking. */
196 
197  /**
198  * If the mouse isn't captured we need to verify the up is on the same
199  * widget as the down so we send a proper click, also needed to send the
200  * up to the right widget.
201  */
203 
204 private:
205  /** Which set of SDL events correspond to this button. */
207 
208  /** Is the button down? */
209  bool is_down_;
210 
212  void signal_handler_sdl_button_down(const event::ui_event event,
213  bool& handled,
214  const point& coordinate);
215 
217  void signal_handler_sdl_button_up(const event::ui_event event,
218  bool& handled,
219  const point& coordinate);
220 
221 
222  void mouse_button_click(widget* widget);
223 };
224 
225 /**
226  * Three subclasses of mouse_button, so that the distributor class can inherit from them;
227  * C++ doesn't allow multiple inheritance to directly use more than one instance of a
228  * superclass.
229  *
230  * It's a diamond inheritance, as all of these have virtual base class mouse_motion;
231  * refactoring that would allow these multiple classes to be replaced with a simple
232  * (distributor has-a std::array<mouse_button, 3>) relationship.
233  */
235 {
237  widget& owner,
238  const dispatcher::queue_position queue_position)
239  : mouse_motion(owner, queue_position)
240  , mouse_button(events, owner, queue_position)
241  {
242  }
243 };
245 {
247  widget& owner,
248  const dispatcher::queue_position queue_position)
249  : mouse_motion(owner, queue_position)
250  , mouse_button(events, owner, queue_position)
251  {
252  }
253 };
255 {
257  widget& owner,
258  const dispatcher::queue_position queue_position)
259  : mouse_motion(owner, queue_position)
260  , mouse_button(events, owner, queue_position)
261  {
262  }
263 };
264 
265 /***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
266 
267 
268 /** The event handler class for the widget library. */
269 class distributor :
270  public mouse_button_left,
271  public mouse_button_middle,
272  public mouse_button_right
273 {
274 public:
275  distributor(widget& owner, const dispatcher::queue_position queue_position);
276 
277  ~distributor();
278 
279  /**
280  * Initializes the state of the keyboard and mouse.
281  *
282  * Needed after initialization and reactivation.
283  */
284  void initialize_state();
285 
286  /**
287  * Captures the keyboard input.
288  *
289  * @param widget The widget which should capture the keyboard.
290  * Sending nullptr releases the capturing.
291  */
292  void keyboard_capture(widget* widget);
293 
294  /**
295  * Adds the widget to the keyboard chain.
296  *
297  * @param widget The widget to add to the chain. The widget
298  * should be valid widget, which hasn't been
299  * added to the chain yet.
300  */
301  void keyboard_add_to_chain(widget* widget);
302 
303  /**
304  * Remove the widget from the keyboard chain.
305  *
306  * @param widget The widget to be removed from the chain.
307  */
308  void keyboard_remove_from_chain(widget* widget);
309 
310  /**
311  * Return the widget currently capturing keyboard input.
312  */
313  widget* keyboard_focus() const;
314 
315 private:
317  {
318  public:
319  virtual void handle_event(const SDL_Event& ) {}
320  virtual void handle_window_event(const SDL_Event& ) {}
321  layer() : video2::draw_layering(false) { }
322  };
323 
324  // make sure the appropriate things happens when we close.
326 
327  /** The widget that holds the keyboard focus_. */
329 
330  /**
331  * Fall back keyboard focus_ items.
332  *
333  * When the focused widget didn't handle the keyboard event (or no handler
334  * for the keyboard focus_) it is send all widgets in this vector. The order
335  * is from rbegin() to rend(). If the keyboard_focus_ is in the vector it
336  * won't get the event twice. The first item added to the vector should be
337  * the window, so it will be the last handler and can dispatch the hotkeys
338  * registered.
339  */
340  std::vector<widget*> keyboard_focus_chain_;
341 
342  /**
343  * Set of functions that handle certain events and sends them to the proper
344  * widget. These functions are called by the SDL event handling functions.
345  */
346 
347  void signal_handler_sdl_key_down(const SDL_Keycode key,
348  const SDL_Keymod modifier,
349  const std::string& unicode);
350 
351  void signal_handler_sdl_text_input(const std::string& unicode, int32_t start, int32_t len);
352  void signal_handler_sdl_text_editing(const std::string& unicode, int32_t start, int32_t len);
353 
354  template<typename Fcn, typename P1, typename P2, typename P3>
355  void signal_handler_keyboard_internal(event::ui_event evt, P1&& p1, P2&& p2, P3&& p3);
356 
357  void signal_handler_notify_removal(dispatcher& widget, const ui_event event);
358 };
359 
360 } // namespace event
361 
362 } // namespace gui2
uint32_t last_click_stamp_
The time of the last click used for double clicking.
bool hover_shown_
Has the hover been shown for the widget?
mouse_button_middle(const mouse_button_event_types &events, widget &owner, const dispatcher::queue_position queue_position)
Three subclasses of mouse_button, so that the distributor class can inherit from them; C++ doesn&#39;t al...
void signal_handler_sdl_touch_motion(const event::ui_event event, bool &handled, const point &coordinate, const point &distance)
std::vector< widget * > keyboard_focus_chain_
Fall back keyboard focus_ items.
Base class for event handling.
Definition: dispatcher.hpp:307
void signal_handler_sdl_wheel(const event::ui_event event, bool &handled, const point &coordinate)
Base class for all widgets.
Definition: widget.hpp:49
widget * focus_
If the mouse isn&#39;t captured we need to verify the up is on the same widget as the down so we send a p...
mouse_button_left(const mouse_button_event_types &events, widget &owner, const dispatcher::queue_position queue_position)
mouse_button_right(const mouse_button_event_types &events, widget &owner, const dispatcher::queue_position queue_position)
widget * last_clicked_widget_
The widget the last click was on, used for double clicking.
void mouse_hover(widget *mouse_over, const point &coordinate)
Called when the mouse moves over a widget.
Generic file dialog.
Definition: field-fwd.hpp:23
void signal_handler_show_helptip(const event::ui_event event, bool &handled, const point &coordinate)
The event handler class for the widget library.
bool is_down_
Is the button down?
int32_t mask
Bitmask corresponding to this button&#39;s bit in SDL_GetMouseState&#39;s return value.
widget & owner_
The widget that owns us.
Definition: distributor.hpp:84
widget * keyboard_focus_
The widget that holds the keyboard focus_.
virtual void handle_window_event(const SDL_Event &)
void start_hover_timer(widget *widget, const point &coordinate)
Starts the hover timer.
point hover_position_
The anchor point of the hover event.
Definition: distributor.hpp:93
const mouse_button_event_types events_
Which set of SDL events correspond to this button.
Definition: video.cpp:51
void mouse_enter(widget *mouse_over)
Called when the mouse enters a widget.
void capture_mouse(const bool capture=true)
Captures the mouse input.
widget * mouse_focus_
The widget that currently has the mouse focus_.
Definition: distributor.hpp:78
std::size_t hover_timer_
The timer for the hover event.
Definition: distributor.hpp:87
Holds a 2D point.
Definition: point.hpp:24
void mouse_leave()
Called when the mouse leaves the current widget.
virtual void handle_event(const SDL_Event &)
void signal_handler_sdl_mouse_motion(const event::ui_event event, bool &handled, const point &coordinate)
queue_position
The position where to add a new callback in the signal handler.
Definition: dispatcher.hpp:478
Handling of system events.
Definition: manager.hpp:43
bool mouse_captured_
Did the current widget capture the focus_?
Definition: distributor.hpp:81
mouse_motion(widget &owner, const dispatcher::queue_position queue_position)
Definition: distributor.cpp:72
void stop_hover_timer()
Stops the current hover timer.
void show_tooltip()
Called when the mouse wants the widget to show its tooltip.
Small helper metastruct to configure instances of mouse_button.
EXIT_STATUS start(const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:30
widget * hover_widget_
The widget which should get the hover event.
Definition: distributor.hpp:90
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
std::string name
used for debug messages.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:48