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