1 /* 2 Copyright (C) 2003 - 2018 by David White <dave@whitevine.net> 3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/ 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY. 11 12 See the COPYING file for more details. 13 */ 14 15 #pragma once 16 17 #include <SDL2/SDL_events.h> 18 #include <vector> 19 #include <list> 20 #include <functional> 21 22 //our user-defined double-click event type 23 #define DOUBLE_CLICK_EVENT SDL_USEREVENT 24 #define TIMER_EVENT (SDL_USEREVENT + 1) 25 #define HOVER_REMOVE_POPUP_EVENT (SDL_USEREVENT + 2) 26 #define DRAW_EVENT (SDL_USEREVENT + 3) 27 #define CLOSE_WINDOW_EVENT (SDL_USEREVENT + 4) 28 #define SHOW_HELPTIP_EVENT (SDL_USEREVENT + 5) 29 #define DRAW_ALL_EVENT (SDL_USEREVENT + 6) 30 #define INVOKE_FUNCTION_EVENT (SDL_USEREVENT + 7) 31 32 namespace events 33 { 34 35 class sdl_handler; 36 37 typedef std::list<sdl_handler*> handler_list; 38 39 class context 40 { 41 public: context()42 context() : 43 handlers(), 44 focused_handler(handlers.end()), 45 staging_handlers() 46 { 47 } 48 49 ~context(); 50 51 context(const context&) = delete; 52 53 void add_handler(sdl_handler* ptr); 54 /** Returns true if @a ptr is found in either the handlers or staging_handlers lists */ 55 bool has_handler(const sdl_handler* ptr) const; 56 bool remove_handler(sdl_handler* ptr); 57 void cycle_focus(); 58 void set_focus(const sdl_handler* ptr); 59 void add_staging_handlers(); 60 61 handler_list handlers; 62 handler_list::iterator focused_handler; 63 std::vector<sdl_handler*> staging_handlers; 64 }; 65 66 //any classes that derive from this class will automatically 67 //receive sdl events through the handle function for their lifetime, 68 //while the event context they were created in is active. 69 // 70 //NOTE: an event_context object must be initialized before a handler object 71 //can be initialized, and the event_context must be destroyed after 72 //the handler is destroyed. 73 class sdl_handler 74 { 75 friend class context; 76 public: 77 virtual void handle_event(const SDL_Event& event) = 0; 78 virtual void handle_window_event(const SDL_Event& event) = 0; process_event()79 virtual void process_event() {} draw()80 virtual void draw() {} 81 volatile_draw()82 virtual void volatile_draw() {} volatile_undraw()83 virtual void volatile_undraw() {} 84 requires_event_focus(const SDL_Event * =nullptr) const85 virtual bool requires_event_focus(const SDL_Event * = nullptr) const { return false; } 86 process_help_string(int,int)87 virtual void process_help_string(int /*mousex*/, int /*mousey*/) {} process_tooltip_string(int,int)88 virtual void process_tooltip_string(int /*mousex*/, int /*mousey*/) {} 89 90 virtual void join(); /*joins the current event context*/ 91 virtual void join(context &c); /*joins the specified event context*/ 92 virtual void join_same(sdl_handler* parent); /*joins the same event context as the parent is already associated with */ 93 virtual void leave(); /*leave the event context*/ 94 95 virtual void join_global(); /*join the global event context*/ 96 virtual void leave_global(); /*leave the global event context*/ 97 has_joined()98 virtual bool has_joined() { return has_joined_;} has_joined_global()99 virtual bool has_joined_global() { return has_joined_global_;} 100 101 /** 102 * Moving would require two instances' context membership to be handled, 103 * it's simpler to delete these and require the two instances to be 104 * separately constructed / destructed. 105 */ 106 sdl_handler &operator=(sdl_handler &&) = delete; 107 sdl_handler(sdl_handler &&) = delete; 108 109 protected: 110 sdl_handler(const bool auto_join=true); 111 sdl_handler(const sdl_handler &); 112 sdl_handler &operator=(const sdl_handler &); 113 virtual ~sdl_handler(); handler_members()114 virtual std::vector<sdl_handler*> handler_members() 115 { 116 return std::vector<sdl_handler*>(); 117 } 118 119 private: 120 bool has_joined_; 121 bool has_joined_global_; 122 }; 123 124 void focus_handler(const sdl_handler* ptr); 125 126 bool has_focus(const sdl_handler* ptr, const SDL_Event* event); 127 128 void call_in_main_thread(const std::function<void (void)>& f); 129 130 //event_context objects control the handler objects that SDL events are sent 131 //to. When an event_context is created, it will become the current event context. 132 //event_context objects MUST be created in LIFO ordering in relation to each other, 133 //and in relation to handler objects. That is, all event_context objects should be 134 //created as automatic/stack variables. 135 // 136 //handler objects need not be created as automatic variables (e.g. you could put 137 //them in a vector) however you must guarantee that handler objects are destroyed 138 //before their context is destroyed 139 struct event_context 140 { 141 event_context(); 142 ~event_context(); 143 }; 144 145 //causes events to be dispatched to all handler objects. 146 void pump(); 147 148 //look for resize events and update references to the screen area 149 void peek_for_resize(); 150 151 struct pump_info { pump_infoevents::pump_info152 pump_info() : resize_dimensions(), ticks_(0) {} 153 std::pair<int,int> resize_dimensions; 154 int ticks(unsigned *refresh_counter=nullptr, unsigned refresh_rate=1); 155 private: 156 int ticks_; //0 if not calculated 157 }; 158 159 class pump_monitor { 160 //pump_monitors receive notification after an events::pump() occurs 161 public: 162 pump_monitor(); 163 virtual ~pump_monitor(); 164 virtual void process(pump_info& info) = 0; 165 }; 166 167 void raise_process_event(); 168 void raise_resize_event(); 169 void raise_draw_event(); 170 void raise_draw_all_event(); 171 void raise_volatile_draw_event(); 172 void raise_volatile_draw_all_event(); 173 void raise_volatile_undraw_event(); 174 void raise_help_string_event(int mousex, int mousey); 175 176 177 /** 178 * Is the event an input event? 179 * 180 * @returns Whether or not the event is an input event. 181 */ 182 bool is_input(const SDL_Event& event); 183 184 /** Discards all input events. */ 185 void discard_input(); 186 187 } 188 189 typedef std::vector<events::sdl_handler*> sdl_handler_vector; 190