The Battle for Wesnoth  1.19.13+dev
handler.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2025
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 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
20 #include "events.hpp"
22 #include "gui/core/timer.hpp"
23 #include "gui/core/log.hpp"
24 #include "gui/widgets/helper.hpp"
25 #include "gui/widgets/widget.hpp"
26 #include "gui/widgets/window.hpp"
27 #include "hotkey/hotkey_item.hpp"
28 #include "video.hpp"
29 #include "utils/ranges.hpp"
30 
31 #include <SDL2/SDL.h>
32 
33 #include <cassert>
34 
35 /**
36  * @todo The items below are not implemented yet.
37  *
38  * - Tooltips have a fixed short time until showing up.
39  * - Tooltips are shown until the widget is exited.
40  * - Help messages aren't shown yet.
41  *
42  * @note it might be that tooltips will be shown independent of a window and in
43  * their own window, therefore the code will be cleaned up after that has been
44  * determined.
45  */
46 
47 /*
48  * At some point in the future this event handler should become the main event
49  * handler. This switch controls the experimental switch for that change.
50  */
51 //#define MAIN_EVENT_HANDLER
52 
53 /* Since this code is still very experimental it's not enabled yet. */
54 //#define ENABLE
55 
56 namespace gui2
57 {
58 
59 namespace event
60 {
61 
62 /***** Static data. *****/
63 static std::unique_ptr<class sdl_event_handler> handler_ = nullptr;
64 static std::unique_ptr<events::event_context> event_context = nullptr;
65 
66 #ifdef MAIN_EVENT_HANDLER
67 static unsigned draw_interval = 0;
68 static unsigned event_poll_interval = 0;
69 
70 /***** Static functions. *****/
71 
72 /**
73  * SDL_AddTimer() callback for the draw event.
74  *
75  * When this callback is called it pushes a new draw event in the event queue.
76  *
77  * @returns The new timer interval, 0 to stop.
78  */
79 static uint32_t timer_sdl_draw_event(uint32_t, void*)
80 {
81  // DBG_GUI_E << "Pushing draw event in queue.";
82 
83  SDL_Event event;
85 
86  event.type = DRAW_EVENT;
87  event.user = data;
88 
89  SDL_PushEvent(&event);
90  return draw_interval;
91 }
92 
93 /**
94  * SDL_AddTimer() callback for the poll event.
95  *
96  * When this callback is called it will run the events in the SDL event queue.
97  *
98  * @returns The new timer interval, 0 to stop.
99  */
100 static uint32_t timer_sdl_poll_events(uint32_t, void*)
101 {
102  try
103  {
104  events::pump();
105  }
106  catch(video::quit&)
107  {
108  return 0;
109  }
110  return event_poll_interval;
111 }
112 #endif
113 
114 /***** handler class. *****/
115 
116 /**
117  * This singleton class handles all events.
118  *
119  * It's a new experimental class.
120  */
122 {
123  friend bool gui2::is_in_dialog();
124 
125 public:
127 
129 
130  /** Inherited from events::sdl_handler. */
131  void handle_event(const SDL_Event& event) override;
132 
133  /** Inherited from events::sdl_handler. */
134  void handle_window_event(const SDL_Event& event) override;
135 
136  /**
137  * Connects a dispatcher.
138  *
139  * @param dispatcher The dispatcher to connect.
140  */
142 
143  /**
144  * Disconnects a dispatcher.
145  *
146  * @param dispatcher The dispatcher to disconnect.
147  */
149 
150  /**
151  * Returns all dispatchers in the Z order.
152  */
153  std::vector<dispatcher*>& get_dispatchers() { return dispatchers_; }
154 
155  /** The dispatcher that captured the mouse focus. */
157 
158 private:
159  /**
160  * Reinitializes the state of all dispatchers.
161  *
162  * This is needed when the application gets activated, to make sure the
163  * state of mainly the mouse is set properly.
164  */
165  void activate();
166 
167  /***** Handlers *****/
168 
169  /** Fires a raw SDL event. */
170  void raw_event(const SDL_Event &event);
171 
172  /**
173  * Fires a video resize event.
174  *
175  * @param new_size The new size of the window.
176  */
177  void video_resize(const point& new_size);
178 
179  /**
180  * Fires a generic mouse event.
181  *
182  * @param event The event to fire.
183  * @param position The position of the mouse.
184  */
185  void mouse(const ui_event event, const point& position);
186 
187  /**
188  * Fires a mouse button up event.
189  *
190  * @param position The position of the mouse.
191  * @param button The SDL id of the button that caused the
192  * event.
193  */
194  void mouse_button_up(const point& position, const uint8_t button);
195 
196  /**
197  * Fires a mouse button down event.
198  *
199  * @param position The position of the mouse.
200  * @param button The SDL id of the button that caused the
201  * event.
202  */
203  void mouse_button_down(const point& position, const uint8_t button);
204 
205  /**
206  * Fires a mouse wheel event.
207  *
208  * @param position The position of the mouse.
209  * @param scrollx The amount of horizontal scrolling.
210  * @param scrolly The amount of vertical scrolling.
211  */
212  void mouse_wheel(const point& position, int scrollx, int scrolly);
213 
214  /**
215  * Gets the dispatcher that wants to receive the keyboard input.
216  *
217  * @returns The dispatcher.
218  * @retval nullptr No dispatcher found.
219  */
221 
222  /**
223  * Fires a touch-moved event.
224  *
225  * @param position The position touched.
226  * @param distance The distance moved.
227  */
228  void touch_motion(const point& position, const point& distance);
229 
230  /**
231  * Fires a touch "finger down" event.
232  *
233  * @param position The position touched.
234  */
235  void touch_down(const point& position);
236 
237  /**
238  * Fires a touch "finger up" event.
239  *
240  * @param position The position touched.
241  */
242  void touch_up(const point& position);
243 
244  /**
245  * Fires a touch gesture event.
246  * @param center the center of gesture
247  * @param dTheta the amount that the fingers rotated during this motion
248  * @param dDist the amount that the fingers pinched during this motion
249  * @param numFingers the number of fingers used in the gesture
250  */
251  void touch_multi_gesture(const point& center, float dTheta, float dDist, uint8_t numFingers);
252 
253  /**
254  * Handles a hat motion event.
255  *
256  * @param event The SDL joystick hat event triggered.
257  */
258  void hat_motion(const SDL_Event& event);
259 
260  /**
261  * Handles a joystick button down event.
262  *
263  * @param event The SDL joystick button event triggered.
264  */
265  void button_down(const SDL_Event& event);
266 
267  /**
268  * Fires a key down event.
269  *
270  * @param event The SDL keyboard event triggered.
271  */
272  void key_down(const SDL_Event& event);
273 
274  /**
275  * Handles the pressing of a hotkey.
276  *
277  * @param key The hotkey item pressed.
278  *
279  * @returns True if there was a valid dispatcher with
280  * which to execute the hotkey callback, false
281  * otherwise.
282  */
283  bool hotkey_pressed(const hotkey::hotkey_ptr& key);
284 
285  /**
286  * Fires a key down event.
287  *
288  * @param key The SDL key code of the key pressed.
289  * @param modifier The SDL key modifiers used.
290  * @param unicode The unicode value for the key pressed.
291  */
292  void key_down(const SDL_Keycode key,
293  const SDL_Keymod modifier,
294  const std::string& unicode);
295 
296  /**
297  * Fires a text input event.
298  *
299  * @param unicode The unicode value for the text entered.
300  */
301  void text_input(const std::string& unicode);
302 
303  /**
304  * Fires a text editing event.
305  *
306  * @param unicode The unicode value for the text being edited.
307  * @param start The start position for the text being edited.
308  * @param len The selection length for the text being edited.
309  */
310  void text_editing(const std::string& unicode, int32_t start, int32_t len);
311 
312  /**
313  * Fires a keyboard event which has no parameters.
314  *
315  * This can happen for example when the mouse wheel is used.
316  *
317  * @param event The event to fire.
318  */
319  void keyboard(const ui_event event);
320 
321  /**
322  * Fires a CLOSE_WINDOW event for the window with the given ID.
323  *
324  * @param window_id The ID of the window to close.
325  */
326  void close_window(const unsigned window_id);
327 
328  /**
329  * The dispatchers.
330  *
331  * The order of the items in the list is also the z-order the front item
332  * being the one completely in the background and the back item the one
333  * completely in the foreground.
334  */
335  std::vector<dispatcher*> dispatchers_;
336 
337  /**
338  * Needed to determine which dispatcher gets the keyboard events.
339  *
340  * NOTE the keyboard events aren't really wired in yet so doesn't do much.
341  */
343  friend void capture_keyboard(dispatcher* dispatcher);
344 };
345 
347  : events::sdl_handler(false)
348  , mouse_focus(nullptr)
349  , dispatchers_()
350  , keyboard_focus_(nullptr)
351 {
352  if(SDL_WasInit(SDL_INIT_TIMER) == 0) {
353  if(SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
354  assert(false);
355  }
356  }
357 
358 // The event context is created now we join it.
359 #ifdef ENABLE
360  join();
361 #endif
362 }
363 
365 {
366 #ifdef ENABLE
367  leave();
368 #endif
369 }
370 
371 void sdl_event_handler::handle_event(const SDL_Event& event)
372 {
373  /** No dispatchers drop the event. */
374  if(dispatchers_.empty()) {
375  return;
376  }
377 
378  uint8_t button = event.button.button;
379 
380  switch(event.type) {
381  case SDL_MOUSEMOTION:
382 #ifdef MOUSE_TOUCH_EMULATION
383  // There's no finger motion when it's not down.
384  if (event.motion.state != 0)
385 #endif
386  {
387  mouse(SDL_MOUSE_MOTION, {event.motion.x, event.motion.y});
388  }
389  break;
390 
391  case SDL_MOUSEBUTTONDOWN:
392  {
393  mouse_button_down({event.button.x, event.button.y}, button);
394  }
395  break;
396 
397  case SDL_MOUSEBUTTONUP:
398  {
399  mouse_button_up({event.button.x, event.button.y}, button);
400  }
401  break;
402 
403  case SDL_MOUSEWHEEL:
404  mouse_wheel(get_mouse_position(), event.wheel.x, event.wheel.y);
405  break;
406 
407  case SHOW_HELPTIP_EVENT:
409  break;
410 
412  // remove_popup();
413  break;
414 
415  case TIMER_EVENT:
416  execute_timer(reinterpret_cast<std::size_t>(event.user.data1));
417  break;
418 
419  case CLOSE_WINDOW_EVENT:
420  close_window(event.user.code);
421  break;
422 
423  case SDL_JOYBUTTONDOWN:
424  button_down(event);
425  break;
426 
427  case SDL_JOYBUTTONUP:
428  break;
429 
430  case SDL_JOYAXISMOTION:
431  break;
432 
433  case SDL_JOYHATMOTION:
434  hat_motion(event);
435  break;
436 
437  case SDL_KEYDOWN:
438  key_down(event);
439  break;
440 
441  case SDL_WINDOWEVENT:
442  switch(event.window.event) {
443  // Always precedes SDL_WINDOWEVENT_RESIZED, but the latter does not always
444  // happen; in particular when we change the game resolution via
445  // SDL_SetWindowSize() <https://github.com/wesnoth/wesnoth/issues/7436>
446  case SDL_WINDOWEVENT_SIZE_CHANGED:
448  break;
449 
450  case SDL_WINDOWEVENT_ENTER:
451  case SDL_WINDOWEVENT_FOCUS_GAINED:
452  activate();
453  break;
454  }
455 
456  break;
457 
458  case SDL_TEXTINPUT:
459  key_down(event);
460  break;
461 
462  case SDL_TEXTEDITING:
463  text_editing(event.edit.text, event.edit.start, event.edit.length);
464  break;
465 
466  case SDL_FINGERMOTION:
467  {
469  touch_motion(
470  point(event.tfinger.x * c.x, event.tfinger.y * c.y),
471  point(event.tfinger.dx * c.x, event.tfinger.dy * c.y)
472  );
473  }
474  break;
475 
476  case SDL_FINGERUP:
477  {
479  touch_up(point(event.tfinger.x * c.x, event.tfinger.y * c.y));
480  }
481  break;
482 
483  case SDL_FINGERDOWN:
484  {
486  touch_down(point(event.tfinger.x * c.x, event.tfinger.y * c.y));
487  }
488  break;
489 
490  case SDL_MULTIGESTURE:
491  {
494  point(event.mgesture.x * c.x, event.mgesture.y * c.y),
495  event.mgesture.dTheta, event.mgesture.dDist,
496  event.mgesture.numFingers
497  );
498  }
499  break;
500 
501 #if(defined(_X11) && !defined(__APPLE__)) || defined(_WIN32)
502  case SDL_SYSWMEVENT:
503  /* DO NOTHING */
504  break;
505 #endif
506 
507  // Silently ignored events.
508  case SDL_KEYUP:
509  case DOUBLE_CLICK_EVENT:
510  break;
511 
512  default:
513 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
514  WRN_GUI_E << "Unhandled event " << static_cast<uint32_t>(event.type)
515  << ".";
516 #endif
517  break;
518  }
519 
520  raw_event(event);
521 }
522 
523 void sdl_event_handler::handle_window_event(const SDL_Event& event)
524 {
525  handle_event(event);
526 }
527 
529 {
530  assert(std::find(dispatchers_.begin(), dispatchers_.end(), dispatcher)
531  == dispatchers_.end());
532 
533  DBG_GUI_E << "adding dispatcher " << static_cast<void*>(dispatcher);
534 
535  if(dispatchers_.empty()) {
536  LOG_GUI_E << "creating new dispatcher event context";
537  event_context = std::make_unique<events::event_context>();
538  join();
539  }
540 
541  dispatchers_.push_back(dispatcher);
542 }
543 
545 {
546  /***** Validate pre conditions. *****/
547  auto itor = std::find(dispatchers_.begin(), dispatchers_.end(), disp);
548  assert(itor != dispatchers_.end());
549 
550  DBG_GUI_E << "removing dispatcher " << static_cast<void*>(disp);
551 
552  /***** Remove dispatcher. *****/
553  dispatchers_.erase(itor);
554 
555  if(disp == mouse_focus) {
556  mouse_focus = nullptr;
557  }
558  if(disp == keyboard_focus_) {
559  keyboard_focus_ = nullptr;
560  }
561 
562  // TODO: draw_manager - Why TF was this "activate"ing on "disconnect"? Seriously WTF?
563  //activate();
564 
565  /***** Validate post conditions. *****/
566  assert(std::find(dispatchers_.begin(), dispatchers_.end(), disp)
567  == dispatchers_.end());
568 
569  if(dispatchers_.empty()) {
570  LOG_GUI_E << "deleting unused dispatcher event context";
571  leave();
572  event_context = nullptr;
573  }
574 }
575 
577 {
578  for(auto dispatcher : dispatchers_)
579  {
580  dispatcher->fire(SDL_ACTIVATE, dynamic_cast<widget&>(*dispatcher), nullptr);
581  }
582 }
583 
585 {
586  DBG_GUI_E << "Firing: " << SDL_VIDEO_RESIZE << ".";
587 
588  for(auto dispatcher : dispatchers_)
589  {
590  dispatcher->fire(SDL_VIDEO_RESIZE, dynamic_cast<widget&>(*dispatcher), new_size);
591  }
592 }
593 
594 void sdl_event_handler::raw_event(const SDL_Event& event) {
595  DBG_GUI_E << "Firing raw event";
596 
597  for(auto dispatcher : dispatchers_)
598  {
599  dispatcher->fire(SDL_RAW_EVENT, dynamic_cast<widget&>(*dispatcher), event);
600  }
601 }
602 
603 void sdl_event_handler::mouse(const ui_event event, const point& position)
604 {
605  DBG_GUI_E << "Firing: " << event << ".";
606 
607  if(mouse_focus) {
608  mouse_focus->fire(event, dynamic_cast<widget&>(*mouse_focus), position);
609  return;
610  }
611 
614  dispatcher->fire(event, dynamic_cast<widget&>(*dispatcher), position);
615  break;
616  }
617 
619  continue;
620  }
621 
622  if(dispatcher->is_at(position)) {
623  dispatcher->fire(event, dynamic_cast<widget&>(*dispatcher), position);
624  break;
625  }
626  }
627 }
628 
629 void sdl_event_handler::mouse_button_up(const point& position, const uint8_t button)
630 {
631  switch(button) {
632  case SDL_BUTTON_LEFT:
633  mouse(SDL_LEFT_BUTTON_UP, position);
634  break;
635  case SDL_BUTTON_MIDDLE:
636  mouse(SDL_MIDDLE_BUTTON_UP, position);
637  break;
638  case SDL_BUTTON_RIGHT:
639  mouse(SDL_RIGHT_BUTTON_UP, position);
640  break;
641  case SDL_BUTTON_X1:
642  mouse(SDL_BACK_BUTTON_UP, position);
643  break;
644  case SDL_BUTTON_X2:
645  mouse(SDL_FORWARD_BUTTON_UP, position);
646  break;
647  default:
648 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
649  WRN_GUI_E << "Unhandled 'mouse button up' event for button "
650  << static_cast<uint32_t>(button) << ".";
651 #endif
652  break;
653  }
654 }
655 
656 void sdl_event_handler::mouse_button_down(const point& position, const uint8_t button)
657 {
658  switch(button) {
659  case SDL_BUTTON_LEFT:
660  mouse(SDL_LEFT_BUTTON_DOWN, position);
661  break;
662  case SDL_BUTTON_MIDDLE:
663  mouse(SDL_MIDDLE_BUTTON_DOWN, position);
664  break;
665  case SDL_BUTTON_RIGHT:
666  mouse(SDL_RIGHT_BUTTON_DOWN, position);
667  break;
668  case SDL_BUTTON_X1:
669  mouse(SDL_BACK_BUTTON_DOWN, position);
670  break;
671  case SDL_BUTTON_X2:
672  mouse(SDL_FORWARD_BUTTON_DOWN, position);
673  break;
674  default:
675 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
676  WRN_GUI_E << "Unhandled 'mouse button down' event for button "
677  << static_cast<uint32_t>(button) << ".";
678 #endif
679  break;
680  }
681 }
682 
683 void sdl_event_handler::mouse_wheel(const point& position, int x, int y)
684 {
685  if(x > 0) {
686  mouse(SDL_WHEEL_RIGHT, position);
687  } else if(x < 0) {
688  mouse(SDL_WHEEL_LEFT, position);
689  }
690 
691  if(y < 0) {
692  mouse(SDL_WHEEL_DOWN, position);
693  } else if(y > 0) {
694  mouse(SDL_WHEEL_UP, position);
695  }
696 }
697 
699 {
700  if(keyboard_focus_) {
701  return keyboard_focus_;
702  }
703 
706  return dispatcher;
707  }
708  }
709 
710  return nullptr;
711 }
712 
713 void sdl_event_handler::touch_motion(const point& position, const point& distance)
714 {
716  dispatcher->fire(SDL_TOUCH_MOTION , dynamic_cast<widget&>(*dispatcher), position, distance);
717  }
718 }
719 
720 void sdl_event_handler::touch_up(const point& position)
721 {
723  dispatcher->fire(SDL_TOUCH_UP, dynamic_cast<widget&>(*dispatcher), position);
724  }
725 }
726 
728 {
730  dispatcher->fire(SDL_TOUCH_DOWN, dynamic_cast<widget&>(*dispatcher), position);
731  }
732 }
733 
734 void sdl_event_handler::touch_multi_gesture(const point& center, float dTheta, float dDist, uint8_t numFingers)
735 {
737  dispatcher->fire(SDL_TOUCH_MULTI_GESTURE, dynamic_cast<widget&>(*dispatcher), center, dTheta, dDist, numFingers);
738  }
739 }
740 
741 void sdl_event_handler::hat_motion(const SDL_Event& event)
742 {
743  const hotkey::hotkey_ptr& hk = hotkey::get_hotkey(event);
744  bool done = false;
745  if(!hk->null()) {
746  done = hotkey_pressed(hk);
747  }
748  if(!done) {
749  // TODO fendrin think about handling hat motions that are not bound to a
750  // hotkey.
751  }
752 }
753 
754 void sdl_event_handler::button_down(const SDL_Event& event)
755 {
756  const hotkey::hotkey_ptr hk = hotkey::get_hotkey(event);
757  bool done = false;
758  if(!hk->null()) {
759  done = hotkey_pressed(hk);
760  }
761  if(!done) {
762  // TODO fendrin think about handling button down events that are not
763  // bound to a hotkey.
764  }
765 }
766 
767 void sdl_event_handler::key_down(const SDL_Event& event)
768 {
769  const hotkey::hotkey_ptr hk = hotkey::get_hotkey(event);
770  bool done = false;
771  if(!hk->null()) {
772  done = hotkey_pressed(hk);
773  }
774  if(!done) {
775  if(event.type == SDL_TEXTINPUT) {
776  text_input(event.text.text);
777  } else {
778  key_down(event.key.keysym.sym, static_cast<SDL_Keymod>(event.key.keysym.mod), "");
779  }
780  }
781 }
782 
783 void sdl_event_handler::text_input(const std::string& unicode)
784 {
785  key_down(SDLK_UNKNOWN, static_cast<SDL_Keymod>(0), unicode);
786 
789  dynamic_cast<widget&>(*dispatcher),
790  unicode, -1, -1);
791  }
792 }
793 
794 void sdl_event_handler::text_editing(const std::string& unicode, int32_t start, int32_t len)
795 {
798  dynamic_cast<widget&>(*dispatcher),
799  unicode, start, len);
800  }
801 }
802 
804 {
806  return dispatcher->execute_hotkey(hotkey::get_hotkey_command(key->get_command()).command);
807  }
808 
809  return false;
810 }
811 
812 void sdl_event_handler::key_down(const SDL_Keycode key,
813  const SDL_Keymod modifier,
814  const std::string& unicode)
815 {
816  DBG_GUI_E << "Firing: " << SDL_KEY_DOWN << ".";
817 
820  dynamic_cast<widget&>(*dispatcher),
821  key,
822  modifier,
823  unicode);
824  }
825 }
826 
828 {
829  DBG_GUI_E << "Firing: " << event << ".";
830 
832  dispatcher->fire(event, dynamic_cast<widget&>(*dispatcher));
833  }
834 }
835 
836 void sdl_event_handler::close_window(const unsigned window_id)
837 {
838  DBG_GUI_E << "Firing " << CLOSE_WINDOW << ".";
839 
840  window* window = window::window_instance(window_id);
841  if(window) {
843  }
844 }
845 
846 /***** manager class. *****/
847 
849 {
850  handler_.reset(new sdl_event_handler());
851 
852 #ifdef MAIN_EVENT_HANDLER
853  draw_interval = 30;
854  SDL_AddTimer(draw_interval, timer_sdl_draw_event, nullptr);
855 
856  event_poll_interval = 10;
857  SDL_AddTimer(event_poll_interval, timer_sdl_poll_events, nullptr);
858 #endif
859 }
860 
862 {
863  handler_.reset(nullptr);
864 
865 #ifdef MAIN_EVENT_HANDLER
866  draw_interval = 0;
867  event_poll_interval = 0;
868 #endif
869 }
870 
871 /***** free functions class. *****/
872 
874 {
875  assert(handler_);
876  assert(dispatcher);
877  handler_->connect(dispatcher);
878 }
879 
881 {
882  assert(handler_);
883  assert(dispatcher);
884  handler_->disconnect(dispatcher);
885 }
886 
887 std::vector<dispatcher*>& get_all_dispatchers()
888 {
889  assert(handler_);
890  return handler_->get_dispatchers();
891 }
892 
894 {
896 
897  SDL_Event event{};
898  event.type = SDL_MOUSEMOTION;
899  event.motion.type = SDL_MOUSEMOTION;
900  event.motion.x = mouse.x;
901  event.motion.y = mouse.y;
902 
903  SDL_PushEvent(&event);
904 }
905 
907 {
908  assert(handler_);
909  assert(dispatcher);
910  handler_->mouse_focus = dispatcher;
911 }
912 
914 {
915  assert(handler_);
916  assert(dispatcher);
917  if(handler_->mouse_focus == dispatcher) {
918  handler_->mouse_focus = nullptr;
919  }
920 }
921 
923 {
924  assert(handler_);
925  assert(dispatcher);
927 
928  handler_->keyboard_focus_ = dispatcher;
929 }
930 
931 std::ostream& operator<<(std::ostream& stream, const ui_event event)
932 {
933  switch(event) {
934  case DRAW:
935  stream << "draw";
936  break;
937  case CLOSE_WINDOW:
938  stream << "close window";
939  break;
940  case SDL_VIDEO_RESIZE:
941  stream << "SDL video resize";
942  break;
943  case SDL_MOUSE_MOTION:
944  stream << "SDL mouse motion";
945  break;
946  case MOUSE_ENTER:
947  stream << "mouse enter";
948  break;
949  case MOUSE_LEAVE:
950  stream << "mouse leave";
951  break;
952  case MOUSE_MOTION:
953  stream << "mouse motion";
954  break;
956  stream << "SDL left button down";
957  break;
958  case SDL_LEFT_BUTTON_UP:
959  stream << "SDL left button up";
960  break;
961  case LEFT_BUTTON_DOWN:
962  stream << "left button down";
963  break;
964  case LEFT_BUTTON_UP:
965  stream << "left button up";
966  break;
967  case LEFT_BUTTON_CLICK:
968  stream << "left button click";
969  break;
971  stream << "left button double click";
972  break;
974  stream << "SDL middle button down";
975  break;
977  stream << "SDL middle button up";
978  break;
979  case MIDDLE_BUTTON_DOWN:
980  stream << "middle button down";
981  break;
982  case MIDDLE_BUTTON_UP:
983  stream << "middle button up";
984  break;
985  case MIDDLE_BUTTON_CLICK:
986  stream << "middle button click";
987  break;
989  stream << "middle button double click";
990  break;
992  stream << "SDL right button down";
993  break;
994  case SDL_RIGHT_BUTTON_UP:
995  stream << "SDL right button up";
996  break;
997  case RIGHT_BUTTON_DOWN:
998  stream << "right button down";
999  break;
1000  case RIGHT_BUTTON_UP:
1001  stream << "right button up";
1002  break;
1003  case RIGHT_BUTTON_CLICK:
1004  stream << "right button click";
1005  break;
1007  stream << "right button double click";
1008  break;
1010  stream << "SDL forward/5 button down";
1011  break;
1012  case SDL_FORWARD_BUTTON_UP:
1013  stream << "SDL forward/5 button up";
1014  break;
1015  case FORWARD_BUTTON_DOWN:
1016  stream << "forward/5 button down";
1017  break;
1018  case FORWARD_BUTTON_UP:
1019  stream << "forward/5 button up";
1020  break;
1021  case FORWARD_BUTTON_CLICK:
1022  stream << "forward/5 button click";
1023  break;
1025  stream << "forward/5 button double click";
1026  break;
1027  case SDL_BACK_BUTTON_DOWN:
1028  stream << "SDL back/4 button down";
1029  break;
1030  case SDL_BACK_BUTTON_UP:
1031  stream << "SDL back/4 button up";
1032  break;
1033  case BACK_BUTTON_DOWN:
1034  stream << "back/4 button down";
1035  break;
1036  case BACK_BUTTON_UP:
1037  stream << "back/4 button up";
1038  break;
1039  case BACK_BUTTON_CLICK:
1040  stream << "back/4 button click";
1041  break;
1043  stream << "back/4 button double click";
1044  break;
1045  case SDL_WHEEL_LEFT:
1046  stream << "SDL wheel left";
1047  break;
1048  case SDL_WHEEL_RIGHT:
1049  stream << "SDL wheel right";
1050  break;
1051  case SDL_WHEEL_UP:
1052  stream << "SDL wheel up";
1053  break;
1054  case SDL_WHEEL_DOWN:
1055  stream << "SDL wheel down";
1056  break;
1057  case SDL_KEY_DOWN:
1058  stream << "SDL key down";
1059  break;
1060  case SDL_TEXT_INPUT:
1061  stream << "SDL text input";
1062  break;
1063  case SDL_TEXT_EDITING:
1064  stream << "SDL text editing";
1065  break;
1066 
1067  case NOTIFY_REMOVAL:
1068  stream << "notify removal";
1069  break;
1070  case NOTIFY_MODIFIED:
1071  stream << "notify modified";
1072  break;
1074  stream << "receive keyboard focus";
1075  break;
1076  case LOSE_KEYBOARD_FOCUS:
1077  stream << "lose keyboard focus";
1078  break;
1079  case SHOW_TOOLTIP:
1080  stream << "show tooltip";
1081  break;
1082  case NOTIFY_REMOVE_TOOLTIP:
1083  stream << "notify remove tooltip";
1084  break;
1085  case SDL_ACTIVATE:
1086  stream << "SDL activate";
1087  break;
1088  case MESSAGE_SHOW_TOOLTIP:
1089  stream << "message show tooltip";
1090  break;
1091  case SHOW_HELPTIP:
1092  stream << "show helptip";
1093  break;
1094  case MESSAGE_SHOW_HELPTIP:
1095  stream << "message show helptip";
1096  break;
1097  case REQUEST_PLACEMENT:
1098  stream << "request placement";
1099  break;
1100  case SDL_TOUCH_MOTION:
1101  stream << "SDL touch motion";
1102  break;
1103  case SDL_TOUCH_UP:
1104  stream << "SDL touch up";
1105  break;
1106  case SDL_TOUCH_DOWN:
1107  stream << "SDL touch down";
1108  break;
1110  stream << "SDL multi-touch gesture";
1111  break;
1112  case SDL_RAW_EVENT:
1113  stream << "SDL raw event";
1114  break;
1115  }
1116 
1117  return stream;
1118 }
1119 
1120 } // namespace event
1121 
1123 {
1124  return !event::get_all_dispatchers().empty();
1125 }
1126 
1127 } // namespace gui2
virtual void join()
Definition: events.cpp:308
virtual void leave()
Definition: events.cpp:353
Simple push button.
Definition: button.hpp:36
button(const implementation::builder_button &builder)
Definition: button.cpp:44
Base class for event handling.
Definition: dispatcher.hpp:150
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:74
virtual bool is_at(const point &coordinate) const =0
Determines whether the location is inside an active widget.
bool get_want_keyboard_input() const
Definition: dispatcher.hpp:427
bool execute_hotkey(const hotkey::HOTKEY_COMMAND id)
Executes a hotkey.
Definition: dispatcher.cpp:147
mouse_behavior get_mouse_behavior() const
Definition: dispatcher.hpp:417
This singleton class handles all events.
Definition: handler.cpp:122
void touch_down(const point &position)
Fires a touch "finger down" event.
Definition: handler.cpp:727
void keyboard(const ui_event event)
Fires a keyboard event which has no parameters.
Definition: handler.cpp:827
void activate()
Reinitializes the state of all dispatchers.
Definition: handler.cpp:576
void disconnect(dispatcher *dispatcher)
Disconnects a dispatcher.
Definition: handler.cpp:544
void mouse_button_up(const point &position, const uint8_t button)
Fires a mouse button up event.
Definition: handler.cpp:629
void close_window(const unsigned window_id)
Fires a CLOSE_WINDOW event for the window with the given ID.
Definition: handler.cpp:836
void handle_window_event(const SDL_Event &event) override
Inherited from events::sdl_handler.
Definition: handler.cpp:523
void video_resize(const point &new_size)
Fires a video resize event.
Definition: handler.cpp:584
void text_editing(const std::string &unicode, int32_t start, int32_t len)
Fires a text editing event.
Definition: handler.cpp:794
void touch_up(const point &position)
Fires a touch "finger up" event.
Definition: handler.cpp:720
std::vector< dispatcher * > & get_dispatchers()
Returns all dispatchers in the Z order.
Definition: handler.cpp:153
dispatcher * keyboard_dispatcher()
Gets the dispatcher that wants to receive the keyboard input.
Definition: handler.cpp:698
friend void capture_keyboard(dispatcher *dispatcher)
Captures the keyboard.
Definition: handler.cpp:922
void text_input(const std::string &unicode)
Fires a text input event.
Definition: handler.cpp:783
void touch_motion(const point &position, const point &distance)
Fires a touch-moved event.
Definition: handler.cpp:713
bool hotkey_pressed(const hotkey::hotkey_ptr &key)
Handles the pressing of a hotkey.
Definition: handler.cpp:803
void mouse_button_down(const point &position, const uint8_t button)
Fires a mouse button down event.
Definition: handler.cpp:656
void hat_motion(const SDL_Event &event)
Handles a hat motion event.
Definition: handler.cpp:741
dispatcher * keyboard_focus_
Needed to determine which dispatcher gets the keyboard events.
Definition: handler.cpp:342
void connect(dispatcher *dispatcher)
Connects a dispatcher.
Definition: handler.cpp:528
void key_down(const SDL_Event &event)
Fires a key down event.
Definition: handler.cpp:767
void mouse(const ui_event event, const point &position)
Fires a generic mouse event.
Definition: handler.cpp:603
void touch_multi_gesture(const point &center, float dTheta, float dDist, uint8_t numFingers)
Fires a touch gesture event.
Definition: handler.cpp:734
void mouse_wheel(const point &position, int scrollx, int scrolly)
Fires a mouse wheel event.
Definition: handler.cpp:683
std::vector< dispatcher * > dispatchers_
The dispatchers.
Definition: handler.cpp:335
void button_down(const SDL_Event &event)
Handles a joystick button down event.
Definition: handler.cpp:754
dispatcher * mouse_focus
The dispatcher that captured the mouse focus.
Definition: handler.cpp:156
void raw_event(const SDL_Event &event)
Fires a raw SDL event.
Definition: handler.cpp:594
void handle_event(const SDL_Event &event) override
Inherited from events::sdl_handler.
Definition: handler.cpp:371
Base class for all widgets.
Definition: widget.hpp:55
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:61
static window * window_instance(const unsigned handle)
Returns the instance of a window.
Definition: window.cpp:408
Type that can be thrown as an exception to quit to desktop.
Definition: video.hpp:323
#define DRAW_EVENT
Definition: events.hpp:27
#define CLOSE_WINDOW_EVENT
Definition: events.hpp:28
#define SHOW_HELPTIP_EVENT
Definition: events.hpp:29
#define DOUBLE_CLICK_EVENT
Definition: events.hpp:24
#define TIMER_EVENT
Definition: events.hpp:25
#define HOVER_REMOVE_POPUP_EVENT
Definition: events.hpp:26
Define the common log macros for the gui toolkit.
#define WRN_GUI_E
Definition: log.hpp:37
#define LOG_GUI_E
Definition: log.hpp:36
#define DBG_GUI_E
Definition: log.hpp:35
This file contains the window object, this object is a top level container which has the event manage...
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:211
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.
Handling of system events.
void pump()
Process all events currently in the queue.
Definition: events.cpp:483
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
@ MIDDLE_BUTTON_DOWN
Definition: handler.hpp:124
@ SDL_FORWARD_BUTTON_DOWN
Definition: handler.hpp:156
@ NOTIFY_REMOVE_TOOLTIP
Definition: handler.hpp:176
@ FORWARD_BUTTON_DOUBLE_CLICK
Definition: handler.hpp:141
@ FORWARD_BUTTON_CLICK
Definition: handler.hpp:140
@ RIGHT_BUTTON_UP
Definition: handler.hpp:129
@ SDL_RIGHT_BUTTON_DOWN
Definition: handler.hpp:150
@ SDL_TOUCH_DOWN
Definition: handler.hpp:166
@ MIDDLE_BUTTON_DOUBLE_CLICK
Definition: handler.hpp:127
@ BACK_BUTTON_DOWN
Definition: handler.hpp:134
@ NOTIFY_MODIFIED
Definition: handler.hpp:175
@ FORWARD_BUTTON_DOWN
Definition: handler.hpp:138
@ BACK_BUTTON_CLICK
Definition: handler.hpp:136
@ MIDDLE_BUTTON_CLICK
Definition: handler.hpp:126
@ BACK_BUTTON_UP
Definition: handler.hpp:135
@ SDL_LEFT_BUTTON_DOWN
Definition: handler.hpp:146
@ SDL_TEXT_INPUT
An SDL text input (commit) event.
Definition: handler.hpp:170
@ SDL_WHEEL_DOWN
Definition: handler.hpp:162
@ LEFT_BUTTON_UP
Definition: handler.hpp:121
@ MIDDLE_BUTTON_UP
Definition: handler.hpp:125
@ RIGHT_BUTTON_CLICK
Definition: handler.hpp:130
@ LOSE_KEYBOARD_FOCUS
Definition: handler.hpp:178
@ SDL_MOUSE_MOTION
Definition: handler.hpp:144
@ SDL_TEXT_EDITING
An SDL text editing (IME) event.
Definition: handler.hpp:171
@ LEFT_BUTTON_DOUBLE_CLICK
Definition: handler.hpp:123
@ RIGHT_BUTTON_DOWN
Definition: handler.hpp:128
@ NOTIFY_REMOVAL
Definition: handler.hpp:174
@ RECEIVE_KEYBOARD_FOCUS
Definition: handler.hpp:177
@ SDL_TOUCH_MOTION
Definition: handler.hpp:184
@ SDL_WHEEL_RIGHT
Definition: handler.hpp:160
@ SDL_VIDEO_RESIZE
Definition: handler.hpp:143
@ BACK_BUTTON_DOUBLE_CLICK
Definition: handler.hpp:137
@ LEFT_BUTTON_CLICK
Definition: handler.hpp:122
@ SDL_WHEEL_LEFT
Definition: handler.hpp:159
@ SDL_LEFT_BUTTON_UP
Definition: handler.hpp:147
@ SDL_TOUCH_MULTI_GESTURE
Definition: handler.hpp:185
@ REQUEST_PLACEMENT
Definition: handler.hpp:180
@ SDL_MIDDLE_BUTTON_UP
Definition: handler.hpp:149
@ SDL_BACK_BUTTON_DOWN
Definition: handler.hpp:154
@ SDL_BACK_BUTTON_UP
Definition: handler.hpp:155
@ FORWARD_BUTTON_UP
Definition: handler.hpp:139
@ LEFT_BUTTON_DOWN
Definition: handler.hpp:120
@ SDL_MIDDLE_BUTTON_DOWN
Definition: handler.hpp:148
@ SDL_RIGHT_BUTTON_UP
Definition: handler.hpp:151
@ RIGHT_BUTTON_DOUBLE_CLICK
Definition: handler.hpp:131
@ MESSAGE_SHOW_TOOLTIP
Definition: handler.hpp:181
@ MESSAGE_SHOW_HELPTIP
Definition: handler.hpp:182
@ SDL_FORWARD_BUTTON_UP
Definition: handler.hpp:157
void capture_mouse(dispatcher *dispatcher)
Captures the mouse.
Definition: handler.cpp:906
void release_mouse(dispatcher *dispatcher)
Releases a captured mouse.
Definition: handler.cpp:913
void disconnect_dispatcher(dispatcher *dispatcher)
Disconnects a dispatcher to the event handler.
Definition: handler.cpp:880
static std::unique_ptr< class sdl_event_handler > handler_
Definition: handler.cpp:63
void capture_keyboard(dispatcher *dispatcher)
Captures the keyboard.
Definition: handler.cpp:922
@ mouse
Callbacks with a coordinate as extra parameter.
void connect_dispatcher(dispatcher *dispatcher)
Connects a dispatcher to the event handler.
Definition: handler.cpp:873
std::vector< dispatcher * > & get_all_dispatchers()
Gets all event dispatchers in the Z order.
Definition: handler.cpp:887
std::ostream & operator<<(std::ostream &stream, const ui_event event)
Definition: handler.cpp:931
static std::unique_ptr< events::event_context > event_context
Definition: handler.cpp:64
void init_mouse_location()
Initializes the location of the mouse.
Definition: handler.cpp:893
Generic file dialog.
bool is_in_dialog()
Is a dialog open?
Definition: handler.cpp:1122
point get_mouse_position()
Returns the current mouse position.
Definition: helper.cpp:168
bool execute_timer(const std::size_t id)
Executes a timer.
Definition: timer.cpp:197
std::shared_ptr< class hotkey_base > hotkey_ptr
Definition: hotkey_item.hpp:27
const hotkey_ptr get_hotkey(const SDL_Event &event)
Iterate through the list of hotkeys and return a hotkey that matches the SDL_Event and the current ke...
const hotkey_command & get_hotkey_command(std::string_view command)
returns the hotkey_command with the given name
constexpr auto reverse
Definition: ranges.hpp:40
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:140
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
Definition: video.cpp:446
std::string_view data
Definition: picture.cpp:188
HOTKEY_COMMAND command
The command associated with this hotkey.
Holds a 2D point.
Definition: point.hpp:25
mock_char c
Contains the gui2 timer routines.