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