The Battle for Wesnoth  1.19.25+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 <SDL3/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(void*, SDL_TimerID, uint32_t)
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  /** Fires an event indicating the window has entered full-screen. */
181 
182  /** Fires an event indicating the window has left full-screen. */
184 
185  /**
186  * Fires a generic mouse event.
187  *
188  * @param event The event to fire.
189  * @param position The position of the mouse.
190  */
191  void mouse(const ui_event event, const point& position);
192 
193  /**
194  * Fires a mouse button up event.
195  *
196  * @param position The position of the mouse.
197  * @param button The SDL id of the button that caused the
198  * event.
199  */
200  void mouse_button_up(const point& position, const uint8_t button);
201 
202  /**
203  * Fires a mouse button down event.
204  *
205  * @param position The position of the mouse.
206  * @param button The SDL id of the button that caused the
207  * event.
208  */
209  void mouse_button_down(const point& position, const uint8_t button);
210 
211  /**
212  * Fires a mouse wheel event.
213  *
214  * @param position The position of the mouse.
215  * @param scrollx The amount of horizontal scrolling.
216  * @param scrolly The amount of vertical scrolling.
217  */
218  void mouse_wheel(const point& position, int scrollx, int scrolly);
219 
220  /**
221  * Gets the dispatcher that wants to receive the keyboard input.
222  *
223  * @returns The dispatcher.
224  * @retval nullptr No dispatcher found.
225  */
227 
228  /**
229  * Fires a touch-moved event.
230  *
231  * @param position The position touched.
232  * @param distance The distance moved.
233  */
234  void touch_motion(const point& position, const point& distance);
235 
236  /**
237  * Fires a touch "finger down" event.
238  *
239  * @param position The position touched.
240  */
241  void touch_down(const point& position);
242 
243  /**
244  * Fires a touch "finger up" event.
245  *
246  * @param position The position touched.
247  */
248  void touch_up(const point& position);
249 
250  /**
251  * Fires a touch gesture event.
252  * @param center the center of gesture
253  * @param dTheta the amount that the fingers rotated during this motion
254  * @param dDist the amount that the fingers pinched during this motion
255  * @param numFingers the number of fingers used in the gesture
256  */
257  void touch_multi_gesture(const point& center, float dTheta, float dDist, uint8_t numFingers);
258 
259  /**
260  * Handles a hat motion event.
261  *
262  * @param event The SDL joystick hat event triggered.
263  */
264  void hat_motion(const SDL_Event& event);
265 
266  /**
267  * Handles a joystick button down event.
268  *
269  * @param event The SDL joystick button event triggered.
270  */
271  void button_down(const SDL_Event& event);
272 
273  /**
274  * Fires a key down event.
275  *
276  * @param event The SDL keyboard event triggered.
277  */
278  void key_down(const SDL_Event& event);
279 
280  /**
281  * Handles the pressing of a hotkey.
282  *
283  * @param key The hotkey item pressed.
284  *
285  * @returns True if there was a valid dispatcher with
286  * which to execute the hotkey callback, false
287  * otherwise.
288  */
289  bool hotkey_pressed(const hotkey::hotkey_ptr& key);
290 
291  /**
292  * Fires a key down event.
293  *
294  * @param key The SDL key code of the key pressed.
295  * @param modifier The SDL key modifiers used.
296  * @param unicode The unicode value for the key pressed.
297  */
298  void key_down(const SDL_Keycode key,
299  const SDL_Keymod modifier,
300  const std::string& unicode);
301 
302  /**
303  * Fires a text input event.
304  *
305  * @param unicode The unicode value for the text entered.
306  */
307  void text_input(const std::string& unicode);
308 
309  /**
310  * Fires a text editing event.
311  *
312  * @param unicode The unicode value for the text being edited.
313  * @param start The start position for the text being edited.
314  * @param len The selection length for the text being edited.
315  */
316  void text_editing(const std::string& unicode, int32_t start, int32_t len);
317 
318  /**
319  * Fires a keyboard event which has no parameters.
320  *
321  * This can happen for example when the mouse wheel is used.
322  *
323  * @param event The event to fire.
324  */
325  void keyboard(const ui_event event);
326 
327  /**
328  * Fires a CLOSE_WINDOW event for the window with the given ID.
329  *
330  * @param window_id The ID of the window to close.
331  */
332  void close_window(const unsigned window_id);
333 
334  /**
335  * The dispatchers.
336  *
337  * The order of the items in the list is also the z-order the front item
338  * being the one completely in the background and the back item the one
339  * completely in the foreground.
340  */
341  std::vector<dispatcher*> dispatchers_;
342 
343  /**
344  * Needed to determine which dispatcher gets the keyboard events.
345  *
346  * NOTE the keyboard events aren't really wired in yet so doesn't do much.
347  */
349  friend void capture_keyboard(dispatcher* dispatcher);
350 };
351 
353  : events::sdl_handler(false)
354  , mouse_focus(nullptr)
355  , dispatchers_()
356  , keyboard_focus_(nullptr)
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_EVENT_MOUSE_MOTION:
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, {static_cast<int>(event.motion.x), static_cast<int>(event.motion.y)});
388  }
389  break;
390 
391  case SDL_EVENT_MOUSE_BUTTON_DOWN:
392  {
393  mouse_button_down({static_cast<int>(event.button.x), static_cast<int>(event.button.y)}, button);
394  }
395  break;
396 
397  case SDL_EVENT_MOUSE_BUTTON_UP:
398  {
399  mouse_button_up({static_cast<int>(event.button.x), static_cast<int>(event.button.y)}, button);
400  }
401  break;
402 
403  case SDL_EVENT_MOUSE_WHEEL:
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_EVENT_JOYSTICK_BUTTON_DOWN:
424  button_down(event);
425  break;
426 
427  case SDL_EVENT_JOYSTICK_BUTTON_UP:
428  break;
429 
430  case SDL_EVENT_JOYSTICK_AXIS_MOTION:
431  break;
432 
433  case SDL_EVENT_JOYSTICK_HAT_MOTION:
434  hat_motion(event);
435  break;
436 
437  case SDL_EVENT_KEY_DOWN:
438  key_down(event);
439  break;
440 
441  // Always precedes SDL_EVENT_WINDOW_RESIZED, but the latter does not always
442  // happen; in particular when we change the game resolution via
443  // SDL_SetWindowSize() <https://github.com/wesnoth/wesnoth/issues/7436>
444  case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
446  break;
447 
448  case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
450  break;
451 
452  case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
454  break;
455 
456  case SDL_EVENT_WINDOW_MOUSE_ENTER:
457  case SDL_EVENT_WINDOW_FOCUS_GAINED:
458  activate();
459  break;
460 
461  case SDL_EVENT_TEXT_INPUT:
462  key_down(event);
463  break;
464 
465  case SDL_EVENT_TEXT_EDITING:
466  text_editing(event.edit.text, event.edit.start, event.edit.length);
467  break;
468 
469  case SDL_EVENT_FINGER_MOTION:
470  {
472  touch_motion(
473  point(event.tfinger.x * c.x, event.tfinger.y * c.y),
474  point(event.tfinger.dx * c.x, event.tfinger.dy * c.y)
475  );
476  }
477  break;
478 
479  case SDL_EVENT_FINGER_UP:
480  {
482  touch_up(point(event.tfinger.x * c.x, event.tfinger.y * c.y));
483  }
484  break;
485 
486  case SDL_EVENT_FINGER_DOWN:
487  {
489  touch_down(point(event.tfinger.x * c.x, event.tfinger.y * c.y));
490  }
491  break;
492 
493  // Silently ignored events.
494  case SDL_EVENT_KEY_UP:
495  break;
496 
497  default:
498 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
499  WRN_GUI_E << "Unhandled event " << static_cast<uint32_t>(event.type)
500  << ".";
501 #endif
502  break;
503  }
504 
505  raw_event(event);
506 }
507 
508 void sdl_event_handler::handle_window_event(const SDL_Event& event)
509 {
510  handle_event(event);
511 }
512 
514 {
516  DBG_GUI_E << "adding dispatcher " << static_cast<void*>(dispatcher);
517 
518  if(dispatchers_.empty()) {
519  LOG_GUI_E << "creating new dispatcher event context";
520  event_context = std::make_unique<events::event_context>();
521  join();
522  }
523 
524  dispatchers_.push_back(dispatcher);
525 }
526 
528 {
529  /***** Validate pre conditions. *****/
530  auto itor = std::find(dispatchers_.begin(), dispatchers_.end(), disp);
531  assert(itor != dispatchers_.end());
532 
533  DBG_GUI_E << "removing dispatcher " << static_cast<void*>(disp);
534 
535  /***** Remove dispatcher. *****/
536  dispatchers_.erase(itor);
537 
538  if(disp == mouse_focus) {
539  mouse_focus = nullptr;
540  }
541  if(disp == keyboard_focus_) {
542  keyboard_focus_ = nullptr;
543  }
544 
545  // TODO: draw_manager - Why TF was this "activate"ing on "disconnect"? Seriously WTF?
546  //activate();
547 
548  /***** Validate post conditions. *****/
549  assert(!utils::contains(dispatchers_, disp));
550 
551  if(dispatchers_.empty()) {
552  LOG_GUI_E << "deleting unused dispatcher event context";
553  leave();
554  event_context = nullptr;
555  }
556 }
557 
559 {
560  for(auto dispatcher : dispatchers_)
561  {
562  dispatcher->fire(SDL_ACTIVATE, dynamic_cast<widget&>(*dispatcher), nullptr);
563  }
564 }
565 
567 {
568  for(auto dispatcher : dispatchers_)
569  {
570  dispatcher->fire(SDL_WINDOW_ENTER_FULLSCREEN, dynamic_cast<widget&>(*dispatcher), nullptr);
571  }
572 }
573 
575 {
576  for(auto dispatcher : dispatchers_)
577  {
578  dispatcher->fire(SDL_WINDOW_LEAVE_FULLSCREEN, dynamic_cast<widget&>(*dispatcher), nullptr);
579  }
580 }
581 
583 {
584  DBG_GUI_E << "Firing: " << SDL_VIDEO_RESIZE << ".";
585 
586  for(auto dispatcher : dispatchers_)
587  {
588  dispatcher->fire(SDL_VIDEO_RESIZE, dynamic_cast<widget&>(*dispatcher), new_size);
589  }
590 }
591 
592 void sdl_event_handler::raw_event(const SDL_Event& event) {
593  DBG_GUI_E << "Firing raw event";
594 
595  for(auto dispatcher : dispatchers_)
596  {
597  dispatcher->fire(SDL_RAW_EVENT, dynamic_cast<widget&>(*dispatcher), event);
598  }
599 }
600 
601 void sdl_event_handler::mouse(const ui_event event, const point& position)
602 {
603  DBG_GUI_E << "Firing: " << event << ".";
604 
605  if(mouse_focus) {
606  mouse_focus->fire(event, dynamic_cast<widget&>(*mouse_focus), position);
607  return;
608  }
609 
612  dispatcher->fire(event, dynamic_cast<widget&>(*dispatcher), position);
613  break;
614  }
615 
617  continue;
618  }
619 
620  if(dispatcher->is_at(position)) {
621  dispatcher->fire(event, dynamic_cast<widget&>(*dispatcher), position);
622  break;
623  }
624  }
625 }
626 
627 void sdl_event_handler::mouse_button_up(const point& position, const uint8_t button)
628 {
629  switch(button) {
630  case SDL_BUTTON_LEFT:
631  mouse(SDL_LEFT_BUTTON_UP, position);
632  break;
633  case SDL_BUTTON_MIDDLE:
634  mouse(SDL_MIDDLE_BUTTON_UP, position);
635  break;
636  case SDL_BUTTON_RIGHT:
637  mouse(SDL_RIGHT_BUTTON_UP, position);
638  break;
639  case SDL_BUTTON_X1:
640  mouse(SDL_BACK_BUTTON_UP, position);
641  break;
642  case SDL_BUTTON_X2:
643  mouse(SDL_FORWARD_BUTTON_UP, position);
644  break;
645  default:
646 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
647  WRN_GUI_E << "Unhandled 'mouse button up' event for button "
648  << static_cast<uint32_t>(button) << ".";
649 #endif
650  break;
651  }
652 }
653 
654 void sdl_event_handler::mouse_button_down(const point& position, const uint8_t button)
655 {
656  switch(button) {
657  case SDL_BUTTON_LEFT:
658  mouse(SDL_LEFT_BUTTON_DOWN, position);
659  break;
660  case SDL_BUTTON_MIDDLE:
661  mouse(SDL_MIDDLE_BUTTON_DOWN, position);
662  break;
663  case SDL_BUTTON_RIGHT:
664  mouse(SDL_RIGHT_BUTTON_DOWN, position);
665  break;
666  case SDL_BUTTON_X1:
667  mouse(SDL_BACK_BUTTON_DOWN, position);
668  break;
669  case SDL_BUTTON_X2:
670  mouse(SDL_FORWARD_BUTTON_DOWN, position);
671  break;
672  default:
673 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
674  WRN_GUI_E << "Unhandled 'mouse button down' event for button "
675  << static_cast<uint32_t>(button) << ".";
676 #endif
677  break;
678  }
679 }
680 
681 void sdl_event_handler::mouse_wheel(const point& position, int x, int y)
682 {
683  if(x > 0) {
684  mouse(SDL_WHEEL_RIGHT, position);
685  } else if(x < 0) {
686  mouse(SDL_WHEEL_LEFT, position);
687  }
688 
689  if(y < 0) {
690  mouse(SDL_WHEEL_DOWN, position);
691  } else if(y > 0) {
692  mouse(SDL_WHEEL_UP, position);
693  }
694 }
695 
697 {
698  if(keyboard_focus_) {
699  return keyboard_focus_;
700  }
701 
704  return dispatcher;
705  }
706  }
707 
708  return nullptr;
709 }
710 
711 void sdl_event_handler::touch_motion(const point& position, const point& distance)
712 {
714  dispatcher->fire(SDL_TOUCH_MOTION , dynamic_cast<widget&>(*dispatcher), position, distance);
715  }
716 }
717 
718 void sdl_event_handler::touch_up(const point& position)
719 {
721  dispatcher->fire(SDL_TOUCH_UP, dynamic_cast<widget&>(*dispatcher), position);
722  }
723 }
724 
726 {
728  dispatcher->fire(SDL_TOUCH_DOWN, dynamic_cast<widget&>(*dispatcher), position);
729  }
730 }
731 
732 void sdl_event_handler::touch_multi_gesture(const point& center, float dTheta, float dDist, uint8_t numFingers)
733 {
735  dispatcher->fire(SDL_TOUCH_MULTI_GESTURE, dynamic_cast<widget&>(*dispatcher), center, dTheta, dDist, numFingers);
736  }
737 }
738 
739 void sdl_event_handler::hat_motion(const SDL_Event& event)
740 {
741  const hotkey::hotkey_ptr& hk = hotkey::get_hotkey(event);
742  bool done = false;
743  if(!hk->null()) {
744  done = hotkey_pressed(hk);
745  }
746  if(!done) {
747  // TODO fendrin think about handling hat motions that are not bound to a
748  // hotkey.
749  }
750 }
751 
752 void sdl_event_handler::button_down(const SDL_Event& event)
753 {
754  const hotkey::hotkey_ptr hk = hotkey::get_hotkey(event);
755  bool done = false;
756  if(!hk->null()) {
757  done = hotkey_pressed(hk);
758  }
759  if(!done) {
760  // TODO fendrin think about handling button down events that are not
761  // bound to a hotkey.
762  }
763 }
764 
765 void sdl_event_handler::key_down(const SDL_Event& event)
766 {
767  const hotkey::hotkey_ptr hk = hotkey::get_hotkey(event);
768  bool done = false;
769  if(!hk->null()) {
770  done = hotkey_pressed(hk);
771  }
772  if(!done) {
773  if(event.type == SDL_EVENT_TEXT_INPUT) {
774  text_input(event.text.text);
775  } else {
776  key_down(event.key.key, static_cast<SDL_Keymod>(event.key.mod), "");
777  }
778  }
779 }
780 
781 void sdl_event_handler::text_input(const std::string& unicode)
782 {
783  key_down(SDLK_UNKNOWN, static_cast<SDL_Keymod>(0), unicode);
784 
787  dynamic_cast<widget&>(*dispatcher),
788  unicode, -1, -1);
789  }
790 }
791 
792 void sdl_event_handler::text_editing(const std::string& unicode, int32_t start, int32_t len)
793 {
796  dynamic_cast<widget&>(*dispatcher),
797  unicode, start, len);
798  }
799 }
800 
802 {
804  return dispatcher->execute_hotkey(hotkey::get_hotkey_command(key->get_command()).command);
805  }
806 
807  return false;
808 }
809 
810 void sdl_event_handler::key_down(const SDL_Keycode key,
811  const SDL_Keymod modifier,
812  const std::string& unicode)
813 {
814  DBG_GUI_E << "Firing: " << SDL_KEY_DOWN << ".";
815 
818  dynamic_cast<widget&>(*dispatcher),
819  key,
820  modifier,
821  unicode);
822  }
823 }
824 
826 {
827  DBG_GUI_E << "Firing: " << event << ".";
828 
830  dispatcher->fire(event, dynamic_cast<widget&>(*dispatcher));
831  }
832 }
833 
834 void sdl_event_handler::close_window(const unsigned window_id)
835 {
836  DBG_GUI_E << "Firing " << CLOSE_WINDOW << ".";
837 
838  window* window = window::window_instance(window_id);
839  if(window) {
841  }
842 }
843 
844 /***** manager class. *****/
845 
847 {
848  handler_.reset(new sdl_event_handler());
849 
850 #ifdef MAIN_EVENT_HANDLER
851  draw_interval = 30;
852  SDL_AddTimer(draw_interval, timer_sdl_draw_event, nullptr);
853 
854  event_poll_interval = 10;
855  SDL_AddTimer(event_poll_interval, timer_sdl_poll_events, nullptr);
856 #endif
857 }
858 
860 {
861  handler_.reset(nullptr);
862 
863 #ifdef MAIN_EVENT_HANDLER
864  draw_interval = 0;
865  event_poll_interval = 0;
866 #endif
867 }
868 
869 /***** free functions class. *****/
870 
872 {
873  assert(handler_);
874  assert(dispatcher);
875  handler_->connect(dispatcher);
876 }
877 
879 {
880  assert(handler_);
881  assert(dispatcher);
882  handler_->disconnect(dispatcher);
883 }
884 
885 std::vector<dispatcher*>& get_all_dispatchers()
886 {
887  assert(handler_);
888  return handler_->get_dispatchers();
889 }
890 
892 {
894 
895  SDL_Event event{};
896  event.type = SDL_EVENT_MOUSE_MOTION;
897  event.motion.type = SDL_EVENT_MOUSE_MOTION;
898  event.motion.x = mouse.x;
899  event.motion.y = mouse.y;
900 
901  SDL_PushEvent(&event);
902 }
903 
905 {
906  assert(handler_);
907  assert(dispatcher);
908  handler_->mouse_focus = dispatcher;
909 }
910 
912 {
913  assert(handler_);
914  assert(dispatcher);
915  if(handler_->mouse_focus == dispatcher) {
916  handler_->mouse_focus = nullptr;
917  }
918 }
919 
921 {
922  assert(handler_);
923  assert(dispatcher);
925 
926  handler_->keyboard_focus_ = dispatcher;
927 }
928 
929 std::ostream& operator<<(std::ostream& stream, const ui_event event)
930 {
931  switch(event) {
932  case DRAW:
933  stream << "draw";
934  break;
935  case CLOSE_WINDOW:
936  stream << "close window";
937  break;
938  case SDL_VIDEO_RESIZE:
939  stream << "SDL video resize";
940  break;
941  case SDL_MOUSE_MOTION:
942  stream << "SDL mouse motion";
943  break;
944  case MOUSE_ENTER:
945  stream << "mouse enter";
946  break;
947  case MOUSE_LEAVE:
948  stream << "mouse leave";
949  break;
950  case MOUSE_MOTION:
951  stream << "mouse motion";
952  break;
954  stream << "SDL left button down";
955  break;
956  case SDL_LEFT_BUTTON_UP:
957  stream << "SDL left button up";
958  break;
959  case LEFT_BUTTON_DOWN:
960  stream << "left button down";
961  break;
962  case LEFT_BUTTON_UP:
963  stream << "left button up";
964  break;
965  case LEFT_BUTTON_CLICK:
966  stream << "left button click";
967  break;
969  stream << "left button double click";
970  break;
972  stream << "SDL middle button down";
973  break;
975  stream << "SDL middle button up";
976  break;
977  case MIDDLE_BUTTON_DOWN:
978  stream << "middle button down";
979  break;
980  case MIDDLE_BUTTON_UP:
981  stream << "middle button up";
982  break;
983  case MIDDLE_BUTTON_CLICK:
984  stream << "middle button click";
985  break;
987  stream << "middle button double click";
988  break;
990  stream << "SDL right button down";
991  break;
992  case SDL_RIGHT_BUTTON_UP:
993  stream << "SDL right button up";
994  break;
995  case RIGHT_BUTTON_DOWN:
996  stream << "right button down";
997  break;
998  case RIGHT_BUTTON_UP:
999  stream << "right button up";
1000  break;
1001  case RIGHT_BUTTON_CLICK:
1002  stream << "right button click";
1003  break;
1005  stream << "right button double click";
1006  break;
1008  stream << "SDL forward/5 button down";
1009  break;
1010  case SDL_FORWARD_BUTTON_UP:
1011  stream << "SDL forward/5 button up";
1012  break;
1013  case FORWARD_BUTTON_DOWN:
1014  stream << "forward/5 button down";
1015  break;
1016  case FORWARD_BUTTON_UP:
1017  stream << "forward/5 button up";
1018  break;
1019  case FORWARD_BUTTON_CLICK:
1020  stream << "forward/5 button click";
1021  break;
1023  stream << "forward/5 button double click";
1024  break;
1025  case SDL_BACK_BUTTON_DOWN:
1026  stream << "SDL back/4 button down";
1027  break;
1028  case SDL_BACK_BUTTON_UP:
1029  stream << "SDL back/4 button up";
1030  break;
1031  case BACK_BUTTON_DOWN:
1032  stream << "back/4 button down";
1033  break;
1034  case BACK_BUTTON_UP:
1035  stream << "back/4 button up";
1036  break;
1037  case BACK_BUTTON_CLICK:
1038  stream << "back/4 button click";
1039  break;
1041  stream << "back/4 button double click";
1042  break;
1043  case SDL_WHEEL_LEFT:
1044  stream << "SDL wheel left";
1045  break;
1046  case SDL_WHEEL_RIGHT:
1047  stream << "SDL wheel right";
1048  break;
1049  case SDL_WHEEL_UP:
1050  stream << "SDL wheel up";
1051  break;
1052  case SDL_WHEEL_DOWN:
1053  stream << "SDL wheel down";
1054  break;
1055  case SDL_KEY_DOWN:
1056  stream << "SDL key down";
1057  break;
1058  case SDL_TEXT_INPUT:
1059  stream << "SDL text input";
1060  break;
1061  case SDL_TEXT_EDITING:
1062  stream << "SDL text editing";
1063  break;
1064 
1065  case NOTIFY_REMOVAL:
1066  stream << "notify removal";
1067  break;
1068  case NOTIFY_MODIFIED:
1069  stream << "notify modified";
1070  break;
1072  stream << "receive keyboard focus";
1073  break;
1074  case LOSE_KEYBOARD_FOCUS:
1075  stream << "lose keyboard focus";
1076  break;
1077  case SHOW_TOOLTIP:
1078  stream << "show tooltip";
1079  break;
1080  case NOTIFY_REMOVE_TOOLTIP:
1081  stream << "notify remove tooltip";
1082  break;
1083  case SDL_ACTIVATE:
1084  stream << "SDL activate";
1085  break;
1087  stream << "SDL window enters fullscreen";
1088  break;
1090  stream << "SDL window leaves fullscreen";
1091  break;
1092  case MESSAGE_SHOW_TOOLTIP:
1093  stream << "message show tooltip";
1094  break;
1095  case SHOW_HELPTIP:
1096  stream << "show helptip";
1097  break;
1098  case MESSAGE_SHOW_HELPTIP:
1099  stream << "message show helptip";
1100  break;
1101  case REQUEST_PLACEMENT:
1102  stream << "request placement";
1103  break;
1104  case SDL_TOUCH_MOTION:
1105  stream << "SDL touch motion";
1106  break;
1107  case SDL_TOUCH_UP:
1108  stream << "SDL touch up";
1109  break;
1110  case SDL_TOUCH_DOWN:
1111  stream << "SDL touch down";
1112  break;
1114  stream << "SDL multi-touch gesture";
1115  break;
1116  case SDL_RAW_EVENT:
1117  stream << "SDL raw event";
1118  break;
1119  }
1120 
1121  return stream;
1122 }
1123 
1124 } // namespace event
1125 
1127 {
1128  return !event::get_all_dispatchers().empty();
1129 }
1130 
1131 } // namespace gui2
virtual void join()
Definition: events.cpp:305
virtual void leave()
Definition: events.cpp:350
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:725
void keyboard(const ui_event event)
Fires a keyboard event which has no parameters.
Definition: handler.cpp:825
void activate()
Reinitializes the state of all dispatchers.
Definition: handler.cpp:558
void disconnect(dispatcher *dispatcher)
Disconnects a dispatcher.
Definition: handler.cpp:527
void mouse_button_up(const point &position, const uint8_t button)
Fires a mouse button up event.
Definition: handler.cpp:627
void close_window(const unsigned window_id)
Fires a CLOSE_WINDOW event for the window with the given ID.
Definition: handler.cpp:834
void handle_window_event(const SDL_Event &event) override
Inherited from events::sdl_handler.
Definition: handler.cpp:508
void video_resize(const point &new_size)
Fires a video resize event.
Definition: handler.cpp:582
void text_editing(const std::string &unicode, int32_t start, int32_t len)
Fires a text editing event.
Definition: handler.cpp:792
void touch_up(const point &position)
Fires a touch "finger up" event.
Definition: handler.cpp:718
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:696
friend void capture_keyboard(dispatcher *dispatcher)
Captures the keyboard.
Definition: handler.cpp:920
void text_input(const std::string &unicode)
Fires a text input event.
Definition: handler.cpp:781
void touch_motion(const point &position, const point &distance)
Fires a touch-moved event.
Definition: handler.cpp:711
bool hotkey_pressed(const hotkey::hotkey_ptr &key)
Handles the pressing of a hotkey.
Definition: handler.cpp:801
void mouse_button_down(const point &position, const uint8_t button)
Fires a mouse button down event.
Definition: handler.cpp:654
void hat_motion(const SDL_Event &event)
Handles a hat motion event.
Definition: handler.cpp:739
dispatcher * keyboard_focus_
Needed to determine which dispatcher gets the keyboard events.
Definition: handler.cpp:348
void window_leave_fullscreen()
Fires an event indicating the window has left full-screen.
Definition: handler.cpp:574
void connect(dispatcher *dispatcher)
Connects a dispatcher.
Definition: handler.cpp:513
void key_down(const SDL_Event &event)
Fires a key down event.
Definition: handler.cpp:765
void mouse(const ui_event event, const point &position)
Fires a generic mouse event.
Definition: handler.cpp:601
void touch_multi_gesture(const point &center, float dTheta, float dDist, uint8_t numFingers)
Fires a touch gesture event.
Definition: handler.cpp:732
void mouse_wheel(const point &position, int scrollx, int scrolly)
Fires a mouse wheel event.
Definition: handler.cpp:681
std::vector< dispatcher * > dispatchers_
The dispatchers.
Definition: handler.cpp:341
void window_enter_fullscreen()
Fires an event indicating the window has entered full-screen.
Definition: handler.cpp:566
void button_down(const SDL_Event &event)
Handles a joystick button down event.
Definition: handler.cpp:752
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:592
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:59
static window * window_instance(const unsigned handle)
Returns the instance of a window.
Definition: window.cpp:407
Type that can be thrown as an exception to quit to desktop.
Definition: video.hpp:328
#define DRAW_EVENT
Definition: events.hpp:31
#define CLOSE_WINDOW_EVENT
Definition: events.hpp:32
#define SHOW_HELPTIP_EVENT
Definition: events.hpp:33
#define TIMER_EVENT
Definition: events.hpp:29
#define HOVER_REMOVE_POPUP_EVENT
Definition: events.hpp:30
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:228
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:480
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:186
@ 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:187
@ REQUEST_PLACEMENT
Definition: handler.hpp:182
@ 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
@ SDL_WINDOW_ENTER_FULLSCREEN
Definition: handler.hpp:179
@ 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:183
@ MESSAGE_SHOW_HELPTIP
Definition: handler.hpp:184
@ SDL_FORWARD_BUTTON_UP
Definition: handler.hpp:157
@ SDL_WINDOW_LEAVE_FULLSCREEN
Definition: handler.hpp:180
void capture_mouse(dispatcher *dispatcher)
Captures the mouse.
Definition: handler.cpp:904
void release_mouse(dispatcher *dispatcher)
Releases a captured mouse.
Definition: handler.cpp:911
void disconnect_dispatcher(dispatcher *dispatcher)
Disconnects a dispatcher to the event handler.
Definition: handler.cpp:878
static std::unique_ptr< class sdl_event_handler > handler_
Definition: handler.cpp:63
void capture_keyboard(dispatcher *dispatcher)
Captures the keyboard.
Definition: handler.cpp:920
@ mouse
Callbacks with a coordinate as extra parameter.
void connect_dispatcher(dispatcher *dispatcher)
Connects a dispatcher to the event handler.
Definition: handler.cpp:871
std::vector< dispatcher * > & get_all_dispatchers()
Gets all event dispatchers in the Z order.
Definition: handler.cpp:885
std::ostream & operator<<(std::ostream &stream, const ui_event event)
Definition: handler.cpp:929
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:891
Generic file dialog.
bool is_in_dialog()
Is a dialog open?
Definition: handler.cpp:1126
point get_mouse_position()
Returns the current mouse position.
Definition: helper.cpp:167
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 id.
constexpr auto reverse
Definition: ranges.hpp:44
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition: general.hpp:87
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:141
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
Definition: video.cpp:432
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.