1 /*
2  *  This file is part of Dune Legacy.
3  *
4  *  Dune Legacy is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Dune Legacy is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Dune Legacy.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <GUI/Window.h>
19 #include <GUI/GUIStyle.h>
20 #include <misc/draw_util.h>
21 #include <globals.h>
22 
Window(Uint32 x,Uint32 y,Uint32 w,Uint32 h)23 Window::Window(Uint32 x, Uint32 y, Uint32 w, Uint32 h) : Widget(), position(x,y) {
24     closeChildWindowCounter = 0;
25     pChildWindow = nullptr;
26     pChildWindowAlreadyClosed = false;
27     pWindowWidget = nullptr;
28 
29     bTransparentBackground = false;
30     pBackground = nullptr;
31     bFreeBackground = false;
32     bSelfGeneratedBackground = true;
33 
34     Widget::resize(w,h);
35 }
36 
~Window()37 Window::~Window() {
38     if(pChildWindow != nullptr) {
39         closeChildWindow();
40         processChildWindowOpenCloses();
41     }
42 
43     if(pWindowWidget != nullptr) {
44         pWindowWidget->destroy();
45     }
46 
47     if(((bSelfGeneratedBackground == true) || (bFreeBackground == true)) && (pBackground != nullptr)) {
48         SDL_DestroyTexture(pBackground);
49         pBackground = nullptr;
50     }
51 }
52 
openWindow(Window * pChildWindow)53 void Window::openWindow(Window* pChildWindow) {
54     if(pChildWindow == nullptr) {
55         return;
56     }
57 
58     if(this->pChildWindow != nullptr) {
59         queuedChildWindows.push(pChildWindow);
60         closeChildWindow();
61     } else {
62         this->pChildWindow = pChildWindow;
63         this->pChildWindow->setParent(this);
64         pChildWindowAlreadyClosed = false;
65     }
66 }
67 
closeChildWindow()68 void Window::closeChildWindow() {
69     if(pChildWindow != nullptr && !pChildWindowAlreadyClosed) {
70         closeChildWindowCounter++;
71         pChildWindow->setEnabled(false);
72         pChildWindow->setVisible(false);
73         pChildWindowAlreadyClosed = true;
74     }
75 }
76 
setCurrentPosition(Uint32 x,Uint32 y,Uint32 w,Uint32 h)77 void Window::setCurrentPosition(Uint32 x, Uint32 y, Uint32 w, Uint32 h) {
78     position.x = x; position.y = y;
79     resize(w,h);
80 }
81 
processChildWindowOpenCloses()82 bool Window::processChildWindowOpenCloses() {
83     bool bClosed = false;
84 
85     while(closeChildWindowCounter > 0) {
86         onChildWindowClose(pChildWindow);
87         pChildWindow->destroy();
88         closeChildWindowCounter--;
89         bClosed = true;
90 
91         if(!queuedChildWindows.empty()) {
92             pChildWindow = queuedChildWindows.front();
93             queuedChildWindows.pop();
94             pChildWindow->setParent(this);
95             pChildWindowAlreadyClosed = false;
96         } else {
97             pChildWindow = nullptr;
98         }
99 
100     }
101 
102     return bClosed;
103 }
104 
handleInput(SDL_Event & event)105 void Window::handleInput(SDL_Event& event) {
106     if(pChildWindow != nullptr) {
107         pChildWindow->handleInput(event);
108 
109         if(processChildWindowOpenCloses()) {
110             // Small hack: simulate mouse movement to get rid of tooltips
111             handleMouseMovement(0, 0);
112         }
113 
114         return;
115     }
116 
117     switch(event.type) {
118         case SDL_KEYDOWN: {
119             handleKeyPress(event.key);
120         } break;
121 
122         case SDL_TEXTINPUT: {
123             handleTextInput(event.text);
124         } break;
125 
126         case SDL_MOUSEMOTION: {
127             handleMouseMovement(event.motion.x,event.motion.y);
128         } break;
129 
130         case SDL_MOUSEBUTTONDOWN: {
131             switch(event.button.button) {
132                 case SDL_BUTTON_LEFT: {
133                     handleMouseLeft(event.button.x,event.button.y,true);
134                 } break;
135 
136                 case SDL_BUTTON_RIGHT: {
137                     handleMouseRight(event.button.x,event.button.y,true);
138                 } break;
139             }
140         } break;
141 
142         case SDL_MOUSEWHEEL: {
143             if(event.wheel.y != 0) {
144                 handleMouseWheel(drawnMouseX,drawnMouseY,(event.wheel.y > 0));
145             }
146         } break;
147 
148         case SDL_MOUSEBUTTONUP: {
149             switch(event.button.button) {
150                 case SDL_BUTTON_LEFT: {
151                     handleMouseLeft(event.button.x,event.button.y,false);
152                 } break;
153 
154                 case SDL_BUTTON_RIGHT: {
155                     handleMouseRight(event.button.x,event.button.y,false);
156                 } break;
157 
158             }
159         } break;
160     }
161 }
162 
handleMouseMovement(Sint32 x,Sint32 y,bool insideOverlay)163 void Window::handleMouseMovement(Sint32 x, Sint32 y, bool insideOverlay) {
164     if(pChildWindow != nullptr) {
165         pChildWindow->handleMouseMovement(x, y);
166         return;
167     }
168 
169     if(isEnabled() && (pWindowWidget != nullptr)) {
170         bool insideOverlay = pWindowWidget->handleMouseMovementOverlay(x - getPosition().x, y - getPosition().y);
171         pWindowWidget->handleMouseMovement(x - getPosition().x, y - getPosition().y, insideOverlay);
172     }
173 }
174 
handleMouseLeft(Sint32 x,Sint32 y,bool pressed)175 bool Window::handleMouseLeft(Sint32 x, Sint32 y, bool pressed) {
176     if(pChildWindow != nullptr) {
177         return pChildWindow->handleMouseLeft(x, y, pressed);
178     }
179 
180     if(isEnabled() && (pWindowWidget != nullptr)) {
181         bool bProcessed = pWindowWidget->handleMouseLeftOverlay(x - getPosition().x, y - getPosition().y, pressed)
182                             || pWindowWidget->handleMouseLeft(x - getPosition().x, y - getPosition().y, pressed);
183         if(pressed && (bProcessed == false)) {
184             pWindowWidget->setActive(false);
185             pWindowWidget->setActive(true);
186         }
187         return bProcessed;
188     } else {
189         return false;
190     }
191 }
192 
handleMouseRight(Sint32 x,Sint32 y,bool pressed)193 bool Window::handleMouseRight(Sint32 x, Sint32 y, bool pressed) {
194     if(pChildWindow != nullptr) {
195         return pChildWindow->handleMouseRight(x, y, pressed);
196     }
197 
198     if(isEnabled() && (pWindowWidget != nullptr)) {
199         return pWindowWidget->handleMouseRightOverlay(x - getPosition().x, y - getPosition().y, pressed)
200                 || pWindowWidget->handleMouseRight(x - getPosition().x, y - getPosition().y, pressed);
201     } else {
202         return false;
203     }
204 }
205 
handleMouseWheel(Sint32 x,Sint32 y,bool up)206 bool Window::handleMouseWheel(Sint32 x, Sint32 y, bool up)  {
207     if(pChildWindow != nullptr) {
208         return pChildWindow->handleMouseWheel(x, y, up);
209     }
210 
211     if(isEnabled() && (pWindowWidget != nullptr)) {
212         return pWindowWidget->handleMouseWheelOverlay(x - getPosition().x, y - getPosition().y, up)
213                 || pWindowWidget->handleMouseWheel(x - getPosition().x, y - getPosition().y, up);
214     } else {
215         return false;
216     }
217 }
218 
handleKeyPress(SDL_KeyboardEvent & key)219 bool Window::handleKeyPress(SDL_KeyboardEvent& key) {
220     if(pChildWindow != nullptr) {
221         return pChildWindow->handleKeyPress(key);
222     }
223 
224     if(isEnabled() && (pWindowWidget != nullptr)) {
225         return pWindowWidget->handleKeyPressOverlay(key) || pWindowWidget->handleKeyPress(key);
226     } else {
227         return false;
228     }
229 }
230 
handleTextInput(SDL_TextInputEvent & textInput)231 bool Window::handleTextInput(SDL_TextInputEvent& textInput) {
232     if(pChildWindow != nullptr) {
233         return pChildWindow->handleTextInput(textInput);
234     }
235 
236     if(isEnabled() && (pWindowWidget != nullptr)) {
237         return pWindowWidget->handleTextInputOverlay(textInput) || pWindowWidget->handleTextInput(textInput);
238     } else {
239         return false;
240     }
241 }
242 
draw(Point position)243 void Window::draw(Point position) {
244     if(isVisible()) {
245         if(bTransparentBackground == false) {
246 
247             if((bSelfGeneratedBackground == true) && (pBackground == nullptr)) {
248                 pBackground = convertSurfaceToTexture(GUIStyle::getInstance().createBackground(getSize().x,getSize().y), true);
249             }
250 
251             if(pBackground != nullptr) {
252                 // Draw background
253                 SDL_Rect dest = calcDrawingRect(pBackground, getPosition().x + getSize().x/2, getPosition().y + getSize().y/2, HAlign::Center, VAlign::Center);
254                 SDL_RenderCopy(renderer, pBackground, nullptr, &dest);
255             }
256         }
257 
258         if(pWindowWidget != nullptr) {
259             pWindowWidget->draw(Point(position.x+getPosition().x,position.y+getPosition().y));
260         }
261     }
262 
263     if(pChildWindow != nullptr) {
264         pChildWindow->draw();
265     }
266 }
267 
drawOverlay(Point position)268 void Window::drawOverlay(Point position) {
269     if(pChildWindow != nullptr) {
270         pChildWindow->drawOverlay();
271     } else if(isVisible() && (pWindowWidget != nullptr)) {
272         pWindowWidget->drawOverlay(Point(position.x+getPosition().x,position.y+getPosition().y));
273     }
274 }
275 
resize(Uint32 width,Uint32 height)276 void Window::resize(Uint32 width, Uint32 height) {
277     Widget::resize(width,height);
278     if(pWindowWidget != nullptr) {
279         pWindowWidget->resize(width,height);
280     }
281 
282     if(bSelfGeneratedBackground == true) {
283         if(pBackground != nullptr) {
284             SDL_DestroyTexture(pBackground);
285             pBackground = nullptr;
286         }
287 
288         // the new background is created when the window is drawn next time
289     }
290 }
291 
setBackground(SDL_Surface * pBackground,bool bFreeBackground)292 void Window::setBackground(SDL_Surface* pBackground, bool bFreeBackground) {
293     if(pBackground == nullptr) {
294         setBackground((SDL_Texture*) nullptr);
295     } else {
296         setBackground(convertSurfaceToTexture(pBackground, bFreeBackground), true);
297     }
298 }
299 
setBackground(SDL_Texture * pBackground,bool bFreeBackground)300 void Window::setBackground(SDL_Texture* pBackground, bool bFreeBackground) {
301     if(((bSelfGeneratedBackground == true) || (this->bFreeBackground == true)) && (this->pBackground != nullptr)) {
302         SDL_DestroyTexture(this->pBackground);
303         this->pBackground = nullptr;
304     }
305 
306     if(pBackground == nullptr) {
307         bSelfGeneratedBackground = true;
308         this->bFreeBackground = false;
309         this->pBackground = nullptr;
310     } else {
311         bSelfGeneratedBackground = false;
312         this->pBackground = pBackground;
313         this->bFreeBackground = bFreeBackground;
314     }
315 }
316 
setTransparentBackground(bool bTransparent)317 void Window::setTransparentBackground(bool bTransparent) {
318     bTransparentBackground = bTransparent;
319 }
320