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