1 /*
2  * Copyright (C) 2012-2013 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 #include "Functions.h"
21 #include "GameState.h"
22 #include "Globals.h"
23 #include "GUIOverlay.h"
24 #include "InputManager.h"
25 #include "GUIObject.h"
26 #include "GUITextArea.h"
27 #include "StatisticsManager.h"
28 
29 #include <assert.h>
30 
31 using namespace std;
32 
GUIOverlay(SDL_Renderer & renderer,GUIObject * root,bool dim)33 GUIOverlay::GUIOverlay(SDL_Renderer& renderer, GUIObject* root,bool dim)
34 	: dim(dim), keyboardNavigationMode(0)
35 {
36 	//First keep the pointer to the current GUIObjectRoot and currentState.
37 	parentState=currentState;
38 	tempGUIObjectRoot=GUIObjectRoot;
39 
40 	//Now set the GUIObject root to the new root.
41 	currentState=this;
42 	GUIObjectRoot=root;
43 
44 	//Dim the background.
45 	if(dim){
46         dimScreen(renderer);
47 	}
48 }
49 
~GUIOverlay()50 GUIOverlay::~GUIOverlay(){
51 	//We need to place everything back.
52 	currentState=parentState;
53 	parentState=NULL;
54 
55 	//Delete the GUI if present.
56 	if(GUIObjectRoot)
57 		delete GUIObjectRoot;
58 
59 	//Now put back the parent gui.
60 	GUIObjectRoot=tempGUIObjectRoot;
61 	tempGUIObjectRoot=NULL;
62 }
63 
enterLoop(ImageManager & imageManager,SDL_Renderer & renderer,bool skipByEscape,bool skipByReturn)64 void GUIOverlay::enterLoop(ImageManager& imageManager, SDL_Renderer& renderer, bool skipByEscape, bool skipByReturn){
65 	//Keep the last resize event, this is to only process one.
66 	SDL_Event lastResize = {};
67 
68 	while (GUIObjectRoot){
69 		while(SDL_PollEvent(&event)){
70 			//Check for a resize event.
71 			if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
72 				lastResize = event;
73 				continue;
74 			}
75 
76 			//Check if it's mouse event. If it's true then we quit the keyboard-only mode.
77 			if (event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) {
78 				isKeyboardOnly = false;
79 			}
80 
81 			//Set the cursor type to the default one, the GUI can change that if needed.
82 			currentCursor = CURSOR_POINTER;
83 
84 			//Let the input manager handle the events.
85 			inputMgr.updateState(true);
86 
87 			//Let the currentState handle the events. (???)
88 			currentState->handleEvents(imageManager, renderer);
89 
90 			//Also pass the events to the GUI.
91 			GUIObjectHandleEvents(imageManager, renderer, true);
92 
93 			//Also check for the escape/return button.
94 			if ((skipByEscape && inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)) || (skipByReturn && inputMgr.isKeyDownEvent(INPUTMGR_SELECT))) {
95 				delete GUIObjectRoot;
96 				GUIObjectRoot=NULL;
97 			}
98 		}
99 
100 		//Process the resize event.
101 		if (lastResize.type == SDL_WINDOWEVENT){
102 			//TODO - used to be SDL_VIDEORESIZE
103 			// so this may trigger on more events than intended
104 			event = lastResize;
105 			onVideoResize(imageManager, renderer);
106 
107 			//After resize we erase the event type
108 			//TODO - used to be SDL_NOEVENT
109 			lastResize.type = SDL_FIRSTEVENT;
110 		}
111 
112 		//update input state (??)
113 		inputMgr.updateState(false);
114 
115 		//Render the gui.
116 		render(imageManager,renderer);
117 
118 		//draw new achievements (if any)
119 		statsMgr.render(imageManager, renderer);
120 
121 		//display it
122         flipScreen(renderer);
123 		SDL_Delay(1000/FPS);
124 	}
125 
126 	//We broke out so clean up.
127 	delete this;
128 }
129 
handleEvents(ImageManager & imageManager,SDL_Renderer & renderer)130 void GUIOverlay::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer){
131 	//Check if we need to quit, if so we enter the exit state.
132 	if(event.type==SDL_QUIT){
133 		setNextState(STATE_EXIT);
134 	}
135 
136 	//Experimental code for keyboard navigation.
137 	if (GUIObjectRoot && keyboardNavigationMode) {
138 		GUIObjectRoot->handleKeyboardNavigationEvents(imageManager, renderer, keyboardNavigationMode);
139 	}
140 }
141 
142 //Nothing to do here
logic(ImageManager &,SDL_Renderer &)143 void GUIOverlay::logic(ImageManager&, SDL_Renderer&){
144 	//Check if the GUIObjectRoot (of the overlay) is deleted.
145 	if(!GUIObjectRoot)
146 		delete this;
147 }
148 
render(ImageManager & imageManager,SDL_Renderer & renderer)149 void GUIOverlay::render(ImageManager& imageManager, SDL_Renderer& renderer) {
150 	//Render the parentState in full, including GUI
151 	{
152 		// backup some variables
153 		GameState *backupState = currentState;
154 		GUIObject *backupGUI = GUIObjectRoot;
155 
156 		// in case of some code are accessing the global varaibles "currentState" and "GUIObjectRoot"
157 		currentState = parentState;
158 		GUIObjectRoot = tempGUIObjectRoot;
159 
160 		currentState->render(imageManager, renderer);
161 		if (GUIObjectRoot) {
162 			GUIObjectRoot->render(renderer);
163 		}
164 
165 		// sanity check - the currentState and GUIObjectRoot should be unchanged
166 		assert(currentState == parentState && GUIObjectRoot == tempGUIObjectRoot);
167 
168 		// restore them
169 		currentState = backupState;
170 		GUIObjectRoot = backupGUI;
171 	}
172 
173 	//Draw the overlay on top
174 	if(dim) {
175 		dimScreen(renderer);
176 	}
177 	if(GUIObjectRoot) {
178 		GUIObjectRoot->render(renderer);
179 	}
180 }
181 
resize(ImageManager & imageManager,SDL_Renderer & renderer)182 void GUIOverlay::resize(ImageManager& imageManager, SDL_Renderer& renderer){
183 	// backup some variables
184 	GameState *backupState = currentState;
185 	GUIObject *backupGUI = GUIObjectRoot;
186 
187 	//We recenter the GUI.
188 	GUIObjectRoot->left=(SCREEN_WIDTH-GUIObjectRoot->width)/2;
189 	GUIObjectRoot->top=(SCREEN_HEIGHT-GUIObjectRoot->height)/2;
190 
191 	// in case of some code are accessing the global varaibles "currentState" and "GUIObjectRoot"
192 	currentState = parentState;
193 	GUIObjectRoot = tempGUIObjectRoot;
194 
195 	//Now let the parent state resize.
196 	currentState->resize(imageManager, renderer);
197 
198 	//NOTE: After the resize it's likely that the GUIObjectRoot is new so we need to update our tempGUIObjectRoot pointer.
199 	tempGUIObjectRoot=GUIObjectRoot;
200 
201 	// sanity check - the currentState should be unchanged
202 	assert(currentState == parentState);
203 
204 	//And set the currentState back to ourself, GUIObjectRoot back to the overlay gui.
205 	currentState = backupState;
206 	GUIObjectRoot = backupGUI;
207 }
208 
AddonOverlay(SDL_Renderer & renderer,GUIObject * root,GUIButton * cancelButton,GUITextArea * textArea,int keyboardNavigationMode)209 AddonOverlay::AddonOverlay(SDL_Renderer &renderer, GUIObject* root, GUIButton *cancelButton, GUITextArea *textArea, int keyboardNavigationMode)
210 	: GUIOverlay(renderer, root), cancelButton(cancelButton), textArea(textArea)
211 {
212 	this->keyboardNavigationMode = keyboardNavigationMode;
213 }
214 
handleEvents(ImageManager & imageManager,SDL_Renderer & renderer)215 void AddonOverlay::handleEvents(ImageManager& imageManager, SDL_Renderer& renderer) {
216 	GUIOverlay::handleEvents(imageManager, renderer);
217 
218 	//Do our own stuff.
219 
220 	//Scroll the text area.
221 	if (textArea) {
222 		if (inputMgr.isKeyDownEvent(INPUTMGR_RIGHT)){
223 			isKeyboardOnly = true;
224 			textArea->scrollScrollbar(20, 0);
225 		} else if (inputMgr.isKeyDownEvent(INPUTMGR_LEFT)){
226 			isKeyboardOnly = true;
227 			textArea->scrollScrollbar(-20, 0);
228 		} else if (inputMgr.isKeyDownEvent(INPUTMGR_UP)){
229 			isKeyboardOnly = true;
230 			textArea->scrollScrollbar(0, -1);
231 		} else if (inputMgr.isKeyDownEvent(INPUTMGR_DOWN)){
232 			isKeyboardOnly = true;
233 			textArea->scrollScrollbar(0, 1);
234 		}
235 	}
236 
237 	//Check escape key.
238 	if (cancelButton && cancelButton->eventCallback && inputMgr.isKeyDownEvent(INPUTMGR_ESCAPE)){
239 		cancelButton->eventCallback->GUIEventCallback_OnEvent(imageManager, renderer, cancelButton->name, cancelButton, GUIEventClick);
240 		return;
241 	}
242 }
243