1 /*
2  * Copyright (C) 2011-2012 Me and My Shadow
3  *
4  * This file is part of Me and My Shadow.
5  *
6  * Me and My Shadow 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 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Me and My Shadow is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Me and My Shadow.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef GUIOBJECT_H
21 #define GUIOBJECT_H
22 
23 #include "FileManager.h"
24 #include "ImageManager.h"
25 #include "Render.h"
26 #include <string>
27 #include <vector>
28 #include <list>
29 
30 //Widget gravity properties
31 enum GUIGravityMode {
32 	GUIGravityLeft,
33 	GUIGravityCenter,
34 	GUIGravityRight,
35 };
36 
37 //The event id's.
38 enum GUIEventId {
39 	//A click event used for e.g. buttons.
40 	GUIEventClick,
41 	//A change event used for e.g. textboxes.
42 	GUIEventChange,
43 };
44 
45 //A boolean variable used to skip next mouse up event for GUI (temporary workaround).
46 //This is used in level editor and addon screen which will open a new window when user clicks an item in a list box.
47 //However, the click event in the newly created window may triggered since they can receive a mouse up event.
48 //NOTE: This will be reset to false when GUIObjectHandleEvents() receives a mouse down event.
49 //This is OK since it may be set to true only after this point.
50 extern bool GUISkipNextMouseUpEvent;
51 
52 struct SDL_Renderer;
53 class GUIObject;
54 
55 //Class that is used as event callback.
56 class GUIEventCallback{
57 public:
58 	//This method is called when an event is fired.
59 	//name: The name of the event.
60 	//obj: Pointer to the GUIObject which caused this event.
61 	//eventType: The type of event as defined above.
62     virtual void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType)=0;
63 };
64 
65 //Class containing the
66 class GUIObject{
67 public:
68 	//The relative x location of the GUIObject.
69 	int left;
70 	//The relative y location of the GUIObject.
71 	int top;
72 	//The width of the GUIObject.
73 	int width;
74 	//The height of the GUIObject.
75 	int height;
76 
77 	//The type of the GUIObject.
78 	int type;
79 	//The value of the GUIObject.
80 	//It depends on the type of GUIObject what it means.
81 	int value;
82 
83 	//The name of the GUIObject.
84 	std::string name;
85 	//The caption of the GUIObject.
86 	//It depends on the type of GUIObject what it is.
87 	std::string caption;
88 
89 	//Boolean if the GUIObject is enabled.
90 	bool enabled;
91 	//Boolean if the GUIObject is visible.
92 	bool visible;
93 
94 	//Vector containing the children of the GUIObject.
95 	std::vector<GUIObject*> childControls;
96 
97 	//Event callback used to invoke events.
98 	GUIEventCallback* eventCallback;
99 
100 	int gravityX;
101 
102 	//Widget's gravity to centering
103 	char gravity;
104 	bool autoWidth;
105 
106 	//Widget's gravity for positioning.
107 	//NOTE: Currently this is only used in GUIWindow::resize().
108 	char gravityLeft, gravityTop, gravityRight, gravityBottom;
109 
110 	//Is the parent widget a dialog?
111 	bool inDialog;
112 
113 	//The state of the GUIObject.
114 	//It depends on the type of GUIObject where it's used for.
115 	int state;
116 
117 protected:
118     //Texture containing different gui images.
119     SharedTexture bmGuiTex;
120 
121 	//Surface that can be used to cache rendered text.
122     TexturePtr cacheTex;
123 	//String containing the old caption to detect if it changed.
124 	std::string cachedCaption;
125 	//Boolean containing the previous enabled state.
126 	bool cachedEnabled;
127 public:
128 	//Constructor.
129 	//left: The relative x location of the GUIObject.
130 	//top: The relative y location of the GUIObject.
131 	//witdh: The width of the GUIObject.
132 	//height: The height of the GUIObject.
133 	//caption: The text on the GUIObject.
134 	//value: The value of the GUIObject.
135 	//enabled: Boolean if the GUIObject is enabled or not.
136 	//visible: Boolean if the GUIObject is visisble or not.
137 	//gravity: The way the GUIObject needs to be aligned.
138 	GUIObject(ImageManager& imageManager, SDL_Renderer& renderer, int left = 0, int top = 0, int width = 0, int height = 0,
139 		const char* caption = NULL, int value = 0,
140 		bool enabled = true, bool visible = true, int gravity = 0);
141 
142 	//Destructor.
143 	virtual ~GUIObject();
144 
145 	//Method used to handle mouse and/or key events.
146 	//x: The x mouse location.
147 	//y: The y mouse location.
148 	//enabled: Boolean if the parent is enabled or not.
149 	//visible: Boolean if the parent is visible or not.
150 	//processed: Boolean if the event has been processed (by the parent) or not.
151 	//Returns: Boolean if the event is processed by the child.
152     virtual bool handleEvents(SDL_Renderer&renderer, int x=0, int y=0, bool enabled=true, bool visible=true, bool processed=false);
153 
154 	//Method that will render the GUIObject.
155 	//x: The x location to draw the GUIObject. (x+left)
156 	//y: The y location to draw the GUIObject. (y+top)
157 	//draw: Draw widget or just update it without drawing
158     virtual void render(SDL_Renderer& renderer, int x=0,int y=0,bool draw=true);
159 
160 	//Method used to reposition subwidgets after a resize.
161 	//NOTE: Currently only the GUIWindow call this function for its subwidgets automatically.
162 	virtual void onResize();
163 
164 	void addChild(GUIObject* obj);
165 
166 	//Method for getting a child from a GUIObject.
167 	//NOTE: This method doesn't search recursively.
168 	//name: The name of the child to return.
169 	//Returns: Pointer to the requested child, NULL otherwise.
170 	GUIObject* getChild(const std::string& name);
171 
172     //Check if the caption or status has changed, or if the width is <0 and
173     //recreate the cached texture if so.
174     void refreshCache(bool enabled);
175 
176 	//Experimental function to get the index of selected child control in keyboard only mode.
177 	//Return value: the index of selected child control. -1 means nothing selected.
178 	int getSelectedControl();
179 
180 	//Experimental function to set the index of selected child control in keyboard only mode.
181 	void setSelectedControl(int index);
182 
183 	//Experimental function to move the focus in keyboard only mode.
184 	//direction: the move direction, 1 or -1.
185 	//selected: currently selected control (optional). Default value means obtain currently selected control automatically.
186 	//Return value: the index of newly selected child control. -1 means nothing selected.
187 	int selectNextControl(int direction, int selected = 0x80000000);
188 
189 	//Experimental function to process keyboard navigation events.
190 	//NOTE: This function need to be called manually.
191 	//keyboardNavigationMode: see the enum KeyboardNavigationMode.
192 	//Return value: if this event is processed.
193 	bool handleKeyboardNavigationEvents(ImageManager& imageManager, SDL_Renderer& renderer, int keyboardNavigationMode);
194 };
195 
196 // A bit-field flags describing keyboard navigation mode.
197 enum KeyboardNavigationMode {
198 	LeftRightFocus = 1, // left/right for focus movement
199 	UpDownFocus = 2, // up/down for focus movement
200 	TabFocus = 4, // tab/shift+tab for focus movement
201 	ReturnControls = 8, // return for individual controls
202 	LeftRightControls = 16, // left/right for individual controls
203 };
204 
205 //Method used to handle the GUIEvents from the GUIEventQueue.
206 //kill: Boolean if an SDL_QUIT event may kill the GUIObjectRoot.
207 void GUIObjectHandleEvents(ImageManager &imageManager, SDL_Renderer &renderer, bool kill=false);
208 
209 //A structure containing the needed variables to call an event.
210 struct GUIEvent{
211 	//Event callback used to invoke the event.
212 	GUIEventCallback* eventCallback;
213 	//The name of the event.
214 	std::string name;
215 	//Pointer to the object which invoked the event.
216 	GUIObject* obj;
217 	//The type of event.
218 	int eventType;
219 };
220 
221 //List used to queue the gui events.
222 extern std::list<GUIEvent> GUIEventQueue;
223 
224 class GUIButton:public GUIObject{
225 public:
226     GUIButton(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
227 		const char* caption=NULL,int value=0,
228 		bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity)229         GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity),
230         smallFont(false){ }
231 	//Method used to handle mouse and/or key events.
232 	//x: The x mouse location.
233 	//y: The y mouse location.
234 	//enabled: Boolean if the parent is enabled or not.
235 	//visible: Boolean if the parent is visible or not.
236 	//processed: Boolean if the event has been processed (by the parent) or not.
237 	//Returns: Boolean if the event is processed by the child.
238     virtual bool handleEvents(SDL_Renderer&renderer, int x=0, int y=0, bool enabled=true, bool visible=true, bool processed=false);
239 	//Method that will render the GUIScrollBar.
240 	//x: The x location to draw the GUIObject. (x+left)
241 	//y: The y location to draw the GUIObject. (y+top)
242 	//draw: Whether displey the widget or not.
243     virtual void render(SDL_Renderer& renderer, int x=0,int y=0,bool draw=true);
244 
245 	//Boolean if small font is used.
246 	bool smallFont;
247 };
248 
249 class GUICheckBox:public GUIObject{
250 public:
251     GUICheckBox(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
252 		const char* caption=NULL,int value=0,
253 		bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity)254         GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity){}
255     //Method used to handle mouse and/or key events.
256 	//x: The x mouse location.
257 	//y: The y mouse location.
258 	//enabled: Boolean if the parent is enabled or not.
259 	//visible: Boolean if the parent is visible or not.
260 	//processed: Boolean if the event has been processed (by the parent) or not.
261 	//Returns: Boolean if the event is processed by the child.
262 	virtual bool handleEvents(SDL_Renderer&,int x=0,int y=0,bool enabled=true,bool visible=true,bool processed=false);
263 	//Method that will render the GUIScrollBar.
264 	//x: The x location to draw the GUIObject. (x+left)
265 	//y: The y location to draw the GUIObject. (y+top)
266 	//draw: Whether displey the widget or not.
267     virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
268 };
269 
270 class GUILabel:public GUIObject{
271 public:
272     GUILabel(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
273 		const char* caption=NULL,int value=0,
274 		bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity)275         GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity){}
276 	//Method used to handle mouse and/or key events.
277 	//x: The x mouse location.
278 	//y: The y mouse location.
279 	//enabled: Boolean if the parent is enabled or not.
280 	//visible: Boolean if the parent is visible or not.
281 	//processed: Boolean if the event has been processed (by the parent) or not.
282 	//Returns: Boolean if the event is processed by the child.
283     virtual bool handleEvents(SDL_Renderer&,int =0, int =0, bool =true, bool =true, bool processed=false);
284 	//Method that will render the GUIScrollBar.
285 	//x: The x location to draw the GUIObject. (x+left)
286 	//y: The y location to draw the GUIObject. (y+top)
287 	//draw: Whether displey the widget or not.
288     virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
289 };
290 
291 class GUITextBox:public GUIObject{
292 public:
293     GUITextBox(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
294 		const char* caption=NULL,int value=0,
295 		bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity)296         GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity),
297         highlightStart(0),highlightEnd(0),highlightStartX(0),highlightEndX(0),tick(15){}
298 	//Method used to handle mouse and/or key events.
299 	//x: The x mouse location.
300 	//y: The y mouse location.
301 	//enabled: Boolean if the parent is enabled or not.
302 	//visible: Boolean if the parent is visible or not.
303 	//processed: Boolean if the event has been processed (by the parent) or not.
304 	//Returns: Boolean if the event is processed by the child.
305 	virtual bool handleEvents(SDL_Renderer&,int x=0,int y=0,bool enabled=true,bool visible=true,bool processed=false);
306 	//Method that will render the GUIScrollBar.
307 	//x: The x location to draw the GUIObject. (x+left)
308 	//y: The y location to draw the GUIObject. (y+top)
309 	//draw: Whether displey the widget or not.
310     virtual void render(SDL_Renderer& renderer, int x=0,int y=0,bool draw=true);
311 
312 	//Method used to update text. This will also reset the selection.
313 	void updateText(const std::string& text);
314 
315 	//Method used to update selection.
316 	void updateSelection(int start, int end);
317 	void blur();
318 private:
319 	//Text highlights.
320 	int highlightStart;
321 	int highlightEnd;
322 
323 	int highlightStartX;
324 	int highlightEndX;
325 
326 	//Carrot ticking.
327 	int tick;
328 
329 	//Functions for modifying the text.
330 	void backspaceChar();
331 	void deleteChar();
332 	void inputText(const char* s);
333 
334 	//Functions for moving the carrot.
335 	void moveCarrotLeft();
336 	void moveCarrotRight();
337 };
338 
339 class GUIFrame:public GUIObject{
340 public:
341     GUIFrame(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
342 		const char* caption=NULL,int value=0,
343 		bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity)344         GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity){
345 		inDialog=true;
346     }
347 	//Method used to handle mouse and/or key events.
348 	//x: The x mouse location.
349 	//y: The y mouse location.
350 	//enabled: Boolean if the parent is enabled or not.
351 	//visible: Boolean if the parent is visible or not.
352 	//processed: Boolean if the event has been processed (by the parent) or not.
353 	//Returns: Boolean if the event is processed by the child.
354     virtual bool handleEvents(SDL_Renderer&renderer, int x=0, int y=0, bool enabled=true, bool visible=true, bool processed=false);
355 	//Method that will render the GUIScrollBar.
356 	//x: The x location to draw the GUIObject. (x+left)
357 	//y: The y location to draw the GUIObject. (y+top)
358 	//draw: Whether displey the widget or not.
359     virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
360 };
361 
362 //A GUIObject that holds an shared_ptr to a Texture for rendering.
363 class GUIImage:public GUIObject{
364 public:
365     GUIImage(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
366 		SharedTexture image = nullptr, SDL_Rect clip = SDL_Rect{0,0,0,0},
367         bool enabled=true,bool visible=true):
368         GUIObject(imageManager,renderer,left,top,width,height,NULL,0,enabled,visible,0),
369         image(image),clip(clip){ }
370 	//Destructor.
371 	~GUIImage();
372 	//Method used to handle mouse and/or key events.
373 	//x: The x mouse location.
374 	//y: The y mouse location.
375 	//enabled: Boolean if the parent is enabled or not.
376 	//visible: Boolean if the parent is visible or not.
377 	//processed: Boolean if the event has been processed (by the parent) or not.
378 	//Returns: Boolean if the event is processed by the child.
379     virtual bool handleEvents(SDL_Renderer&,int =0, int =0, bool =true, bool =true, bool processed=false);
380 	//Method that will render the GUIScrollBar.
381 	//x: The x location to draw the GUIObject. (x+left)
382 	//y: The y location to draw the GUIObject. (y+top)
383     //draw: Whether display the widget or not.
384     virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
385 
386 	//Method that will change the dimensions of the GUIImage so that the full image is shown.
387 	//OR in case of a clip rect that the selected section of the image is shown.
388 	void fitToImage();
389 
390 	//Method for setting the image of the widget.
391     //image: SharedTexture containing the image.
setImage(SharedTexture texture)392     void setImage(SharedTexture texture){
393         image=texture;
394 	}
395 
396 	//Method for setting the clip rectangle for the GUIImager.
397 	//rect: The new clip rectangle.
setClipRect(SDL_Rect rect)398 	void setClipRect(SDL_Rect rect){
399 		clip=rect;
400 	}
401 private:
402     //Pointer to the SDL_Texture to draw.
403     //MAY BE NULL!!
404     SharedTexture image;
405     //Optional rectangle for defining the section of the texture that should be drawn.
406 	//NOTE: This doesn't have to correspond with the dimensions of the GUIObject.
407 	SDL_Rect clip;
408 };
409 
410 #endif
411