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