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