-
-
Notifications
You must be signed in to change notification settings - Fork 988
/
distributor.hpp
374 lines (305 loc) · 10.5 KB
/
distributor.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/*
Copyright (C) 2009 - 2018 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
/**
* @file
* Contains the event distributor.
*
* The event distributor exists of several classes which are combined in one
* templated distributor class. The classes are closely tight together.
*
* All classes have direct access to each others members since they should act
* as one. (Since the buttons are a templated subclass it's not possible to use
* private subclasses.)
*
* The mouse_motion class handles the mouse motion and holds the owner of us
* since all classes virtually inherit us.
*
* The mouse_button classes are templated classes per mouse button, the
* template parameters are used to make the difference between the mouse
* buttons. Although it's easily possible to add more mouse buttons in the
* code several places only expect a left, middle and right button.
*
* distributor is the main class to be used in the user code. This class
* contains the handling of the keyboard as well.
*/
#include "gui/core/event/dispatcher.hpp"
#include "gui/core/event/handler.hpp"
#include "sdl/point.hpp"
#include "video.hpp"
#include <string>
#include <vector>
namespace gui2
{
class widget;
namespace event
{
/***** ***** ***** ***** mouse_motion ***** ***** ***** ***** *****/
class mouse_motion
{
public:
mouse_motion(widget& owner, const dispatcher::queue_position queue_position);
~mouse_motion();
/**
* Captures the mouse input.
*
* When capturing the widget that has the mouse focus_ does the capturing.
*
* @param capture Set or release the capturing.
*/
void capture_mouse( // widget* widget);
const bool capture = true);
protected:
/** The widget that currently has the mouse focus_. */
widget* mouse_focus_;
/** Did the current widget capture the focus_? */
bool mouse_captured_;
/** The widget that owns us. */
widget& owner_;
/** The timer for the hover event. */
std::size_t hover_timer_;
/** The widget which should get the hover event. */
widget* hover_widget_;
/** The anchor point of the hover event. */
point hover_position_;
/**
* Has the hover been shown for the widget?
*
* A widget won't get a second hover event after the tooltip has been
* triggered. Only after (shortly) entering another widget it will be shown
* again for this widget.
*/
bool hover_shown_;
/**
* Starts the hover timer.
*
* @param widget The widget that wants the tooltip.
* @param coordinate The anchor coordinate.
*/
void start_hover_timer(widget* widget, const point& coordinate);
/** Stops the current hover timer. */
void stop_hover_timer();
/**
* Called when the mouse enters a widget.
*
* @param mouse_over The widget that should receive the event.
*/
void mouse_enter(widget* mouse_over);
/** Called when the mouse leaves the current widget. */
void mouse_leave();
private:
/**
* Called when the mouse moves over a widget.
*
* @param mouse_over The widget that should receive the event.
* @param coordinate The current screen coordinate of the mouse.
*/
void mouse_hover(widget* mouse_over, const point& coordinate);
/** Called when the mouse wants the widget to show its tooltip. */
void show_tooltip();
bool signal_handler_sdl_mouse_motion_entered_;
void signal_handler_sdl_mouse_motion(const event::ui_event event,
bool& handled,
const point& coordinate);
void signal_handler_sdl_touch_motion(const event::ui_event event,
bool& handled,
const point& coordinate,
const point& distance);
void signal_handler_sdl_wheel(const event::ui_event event,
bool& handled,
const point& coordinate);
void signal_handler_show_helptip(const event::ui_event event,
bool& handled,
const point& coordinate);
};
/***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/
/**
* Small helper metastruct to specialize mouse_button with and provide ui_event type
* aliases without needing to make mouse_button take a million template types.
*/
template<
ui_event sdl_button_down,
ui_event sdl_button_up,
ui_event button_down,
ui_event button_up,
ui_event button_click,
ui_event button_double_click>
struct mouse_button_event_types_wrapper
{
static const ui_event sdl_button_down_event = sdl_button_down;
static const ui_event sdl_button_up_event = sdl_button_up;
static const ui_event button_down_event = button_down;
static const ui_event button_up_event = button_up;
static const ui_event button_click_event = button_click;
static const ui_event button_double_click_event = button_double_click;
};
template<typename T>
class mouse_button : public virtual mouse_motion
{
public:
mouse_button(const std::string& name_,
widget& owner,
const dispatcher::queue_position queue_position);
/**
* Initializes the state of the button.
*
* @param is_down The initial state of the button, if true down
* else initialized as up.
*/
void initialize_state(const bool is_down);
protected:
/** The time of the last click used for double clicking. */
uint32_t last_click_stamp_;
/** The widget the last click was on, used for double clicking. */
widget* last_clicked_widget_;
/**
* If the mouse isn't captured we need to verify the up is on the same
* widget as the down so we send a proper click, also needed to send the
* up to the right widget.
*/
widget* focus_;
private:
/** used for debug messages. */
const std::string name_;
/** Is the button down? */
bool is_down_;
bool signal_handler_sdl_button_down_entered_;
void signal_handler_sdl_button_down(const event::ui_event event,
bool& handled,
const point& coordinate);
bool signal_handler_sdl_button_up_entered_;
void signal_handler_sdl_button_up(const event::ui_event event,
bool& handled,
const point& coordinate);
void mouse_button_click(widget* widget);
};
/***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
using mouse_button_left = mouse_button<
mouse_button_event_types_wrapper<
SDL_LEFT_BUTTON_DOWN,
SDL_LEFT_BUTTON_UP,
LEFT_BUTTON_DOWN,
LEFT_BUTTON_UP,
LEFT_BUTTON_CLICK,
LEFT_BUTTON_DOUBLE_CLICK>
>;
using mouse_button_middle = mouse_button<
mouse_button_event_types_wrapper<
SDL_MIDDLE_BUTTON_DOWN,
SDL_MIDDLE_BUTTON_UP,
MIDDLE_BUTTON_DOWN,
MIDDLE_BUTTON_UP,
MIDDLE_BUTTON_CLICK,
MIDDLE_BUTTON_DOUBLE_CLICK>
>;
using mouse_button_right = mouse_button<
mouse_button_event_types_wrapper<
SDL_RIGHT_BUTTON_DOWN,
SDL_RIGHT_BUTTON_UP,
RIGHT_BUTTON_DOWN,
RIGHT_BUTTON_UP,
RIGHT_BUTTON_CLICK,
RIGHT_BUTTON_DOUBLE_CLICK>
>;
/** The event handler class for the widget library. */
class distributor :
public mouse_button_left,
public mouse_button_middle,
public mouse_button_right
{
public:
distributor(widget& owner, const dispatcher::queue_position queue_position);
~distributor();
/**
* Initializes the state of the keyboard and mouse.
*
* Needed after initialization and reactivation.
*/
void initialize_state();
/**
* Captures the keyboard input.
*
* @param widget The widget which should capture the keyboard.
* Sending nullptr releases the capturing.
*/
void keyboard_capture(widget* widget);
/**
* Adds the widget to the keyboard chain.
*
* @param widget The widget to add to the chain. The widget
* should be valid widget, which hasn't been
* added to the chain yet.
*/
void keyboard_add_to_chain(widget* widget);
/**
* Remove the widget from the keyboard chain.
*
* @param widget The widget to be removed from the chain.
*/
void keyboard_remove_from_chain(widget* widget);
/**
* Return the widget currently capturing keyboard input.
*/
widget* keyboard_focus() const;
private:
class layer : public video2::draw_layering
{
public:
virtual void handle_event(const SDL_Event& ) {}
virtual void handle_window_event(const SDL_Event& ) {}
layer() : video2::draw_layering(false) { }
};
// make sure the appropriate things happens when we close.
layer layer_;
#if 0
bool hover_pending_; /**< Is there a hover event pending? */
unsigned hover_id_; /**< Id of the pending hover event. */
SDL_Rect hover_box_; /**< The area the mouse can move in,
* moving outside invalidates the
* pending hover event.
*/
bool had_hover_; /**< A widget only gets one hover event
* per enter cycle.
*/
/** The widget of the currently active tooltip. */
widget* tooltip_;
/** The widget of the currently active help popup. */
widget* help_popup_;
#endif
/** The widget that holds the keyboard focus_. */
widget* keyboard_focus_;
/**
* Fall back keyboard focus_ items.
*
* When the focused widget didn't handle the keyboard event (or no handler
* for the keyboard focus_) it is send all widgets in this vector. The order
* is from rbegin() to rend(). If the keyboard_focus_ is in the vector it
* won't get the event twice. The first item added to the vector should be
* the window, so it will be the last handler and can dispatch the hotkeys
* registered.
*/
std::vector<widget*> keyboard_focus_chain_;
/**
* Set of functions that handle certain events and sends them to the proper
* widget. These functions are called by the SDL event handling functions.
*/
void signal_handler_sdl_key_down(const SDL_Keycode key,
const SDL_Keymod modifier,
const std::string& unicode);
void signal_handler_sdl_text_input(const std::string& unicode, int32_t start, int32_t len);
void signal_handler_sdl_text_editing(const std::string& unicode, int32_t start, int32_t len);
template<typename Fcn, typename P1, typename P2, typename P3>
void signal_handler_keyboard_internal(event::ui_event evt, P1&& p1, P2&& p2, P3&& p3);
void signal_handler_notify_removal(dispatcher& widget, const ui_event event);
};
} // namespace event
} // namespace gui2