1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

root/trunk/source/game/widgets/widget_window.cpp @ 944

Revision 944, 11.1 KB (checked in by silnarm, 3 years ago)
  • merge 0.3.x => trunk
  • Property svn:eol-style set to native
Line 
1// ==============================================================
2//      This file is part of The Glest Advanced Engine
3//
4//      Copyright (C) 2010      James McCulloch <silnarm at gmail>
5//
6//  GPL V3, see source/licence.txt
7// ==============================================================
8
9#include "pch.h"
10#include <stack>
11
12#include "window_gl.h"
13#include "sigslot.h"
14
15#include "widgets_base.h"
16#include "widget_window.h"
17
18#include "metrics.h"
19#include "renderer.h"
20#include "core_data.h"
21#include "texture_gl.h"
22
23#include "leak_dumper.h"
24
25using Shared::Platform::WindowGl;
26using Shared::Graphics::Gl::Texture2DGl;
27using namespace Glest::Global;
28using Glest::Graphics::Renderer;
29
30namespace Glest { namespace Widgets {
31using Global::CoreData;
32
33// =====================================================
34// class WidgetWindow
35// =====================================================
36
37WidgetWindow* WidgetWindow::instance;
38
39WidgetWindow::WidgetWindow()
40                : Container(this)
41                , MouseWidget(this)
42                , KeyboardWidget(this)
43                , floatingWidget(0)
44                , anim(0.f), slowAnim(0.f), mouseIcon(0) {
45        size.x = Metrics::getInstance().getScreenW();
46        size.y = Metrics::getInstance().getScreenH();
47       
48        mouseOverStack.push(this);
49
50        foreach_enum (MouseButton, btn) {
51                mouseDownWidgets[btn] = 0;
52        }
53        lastMouseDownWidget = 0;
54        lastKeyDownWidget = 0;
55        keyboardFocused = keyboardWidget;
56
57        textRendererFT = g_renderer.getFreeTypeRenderer();
58}
59
60WidgetWindow::~WidgetWindow() {
61        clear();
62}
63
64void WidgetWindow::clear() {
65        //_PROFILE_FUNCTION();
66        while (mouseOverStack.top() != this) {
67                mouseOverStack.pop();
68        }
69        keyboardFocused = keyboardWidget;
70        lastKeyDownWidget = 0;
71        foreach_enum (MouseButton, btn) {
72                mouseDownWidgets[btn] = 0;
73        }
74        lastMouseDownWidget = 0;
75       
76        if (floatingWidget) {
77                delete floatingWidget;
78                floatingWidget = 0;
79        }
80        Container::clear();
81}
82
83void WidgetWindow::render() {
84        //_PROFILE_FUNCTION();
85        Container::render();
86        if (floatingWidget) {
87                floatingWidget->render();
88        }
89        renderMouseCursor();
90}
91
92void WidgetWindow::aquireKeyboardFocus(KeyboardWidget* widget) {
93        assert(widget);
94        if (keyboardFocused != widget) {
95                if (keyboardFocused != keyboardWidget) {
96                        keyboardFocused->lostKeyboardFocus();
97                }
98                keyboardFocused = widget;
99        }
100}
101
102void WidgetWindow::releaseKeyboardFocus(KeyboardWidget* widget) {
103        if (keyboardFocused == widget) {
104                keyboardFocused->lostKeyboardFocus();
105                keyboardFocused = keyboardWidget;
106        }
107}
108
109void WidgetWindow::unwindMouseOverStack(Widget* newTop) {
110        while (mouseOverStack.top() != newTop) {
111                MouseWidget* mw = mouseOverStack.top()->asMouseWidget();
112                if (mw) {
113                        mw->mouseOut();
114                }
115                mouseOverStack.pop();
116        }
117}
118
119void WidgetWindow::unwindMouseOverStack() {
120        unwindMouseOverStack(this);
121}
122
123Widget* WidgetWindow::findCommonAncestor(Widget* widget1, Widget* widget2) {
124        Widget* tmp1 = widget1;
125        while (tmp1 != this) {
126                Widget* tmp2 = widget2;
127                while (tmp1 != tmp2 && tmp2 != this) {
128                        tmp2 = tmp2->getParent();
129                }
130                if (tmp1 == tmp2) {
131                        return tmp1;
132                }
133                tmp1 = tmp1->getParent();
134        }
135        return this;
136}
137
138void WidgetWindow::doMouseInto(Widget* widget) {
139        if (widget != mouseOverStack.top()) {
140                Widget* ancestor = findCommonAncestor(widget, mouseOverStack.top());
141                RUNTIME_CHECK(ancestor != 0);
142                unwindMouseOverStack(ancestor);
143                std::stack<Widget*> tmpStack;
144                while (widget != ancestor) {
145                        tmpStack.push(widget);
146                        widget = widget->getParent();
147                        RUNTIME_CHECK(widget != 0);
148                }
149                while (!tmpStack.empty()) {
150                        MouseWidget* mw = tmpStack.top()->asMouseWidget();
151                        if (mw) {
152                                mw->mouseIn();
153                        }
154                        mouseOverStack.push(tmpStack.top());
155                        tmpStack.pop();
156                }
157        }
158}
159
160void WidgetWindow::setFloatingWidget(Widget* floater, bool modal) {
161        delete floatingWidget;
162        floatingWidget = floater;
163        floatingWidget->setParent(this);
164        unwindMouseOverStack(this);
165        modalFloater = modal;
166}
167
168void WidgetWindow::removeFloatingWidget(Widget* floater) {
169        if (floater != floatingWidget) {
170                throw runtime_error("WidgetWindow::removeFloatingWidget() passed bad argument.");
171        }
172        keyboardFocused = keyboardWidget;
173        lastKeyDownWidget = 0;
174
175        toClean.push_back(floatingWidget);
176        floatingWidget = 0;
177        while (mouseOverStack.top() != this) {
178                mouseOverStack.pop();
179        }
180        doMouseInto(getWidgetAt(mousePos));
181}
182
183void WidgetWindow::registerUpdate(Widget* widget) {
184        // only register for updating once, if the widget is already in the container do nothing
185        if (std::find(updateList.begin(), updateList.end(), widget) == updateList.end()) {
186        updateList.push_back(widget);
187        }
188        ///@todo it might be better to use a set instead of a vector to achieve the desired behaviour
189}
190
191void WidgetWindow::unregisterUpdate(Widget* widget) {
192        WidgetList::iterator it = std::find(updateList.begin(), updateList.end(), widget);
193        if (it != updateList.end()) {
194        updateList.erase(it);
195        }
196}
197
198void WidgetWindow::update() {
199        const float animSpeed = 0.02f;
200        anim += animSpeed;
201        if (anim > 1.f) {
202                anim -= 1.f;
203        }
204        slowAnim += animSpeed / 3.f;
205        if (slowAnim > 1.f) {
206                slowAnim -= 1.f;
207        }
208        if (!toClean.empty()) {
209                foreach (WidgetList, it, toClean) {
210                        delete *it;
211                }
212                toClean.clear();
213        }
214        foreach (WidgetList, it, updateList) {
215                (*it)->update();
216        }
217}
218
219void WidgetWindow::destroyFloater() {
220        // destroy floater
221        delete floatingWidget;
222        floatingWidget = 0;
223        while (mouseOverStack.top() != this) {
224                mouseOverStack.pop();
225        }
226        doMouseInto(getWidgetAt(mousePos));
227        if (lastMouseDownWidget) {
228                lastMouseDownWidget = 0;
229                mouseDownWidgets[lastMouseDownButton] = 0;
230        }
231}
232
233void WidgetWindow::eventMouseDown(int x, int y, MouseButton msBtn) {
234        WIDGET_LOG( __FUNCTION__ << "( " << x << ", " << y << ", " << MouseButtonNames[msBtn] << " )");
235        mousePos.x = x;
236        mousePos.y = getH() - y;
237        Widget* widget = 0;
238        if (floatingWidget) {
239                if (floatingWidget->isInside(mousePos)) {
240                        widget = floatingWidget->getWidgetAt(mousePos);
241                } else {
242                        if (!modalFloater) {
243                                destroyFloater();
244                        }
245                        return;
246                }
247        } else {
248                widget = getWidgetAt(mousePos);
249        }
250        if (lastMouseDownWidget && lastMouseDownWidget != widget->asMouseWidget()) {
251                Widget* ancestor = findCommonAncestor(lastMouseDownWidget->me, widget);
252                unwindMouseOverStack(ancestor);
253                doMouseInto(widget);
254        }
255        if (keyboardFocused != keyboardWidget && keyboardFocused != widget->asKeyboardWidget()) {
256                keyboardFocused->lostKeyboardFocus();
257                keyboardFocused = keyboardWidget;
258        }
259        while (widget) {
260                MouseWidget* mw = widget->asMouseWidget();
261                if (mw && mw->mouseDown(msBtn, mousePos)) {
262                        if (lastMouseDownWidget) {
263                                mouseDownWidgets[lastMouseDownButton] = 0;
264                        }
265                        mouseDownWidgets[msBtn] = lastMouseDownWidget = mw;
266                        lastMouseDownButton = msBtn;
267                        return;
268                }
269                widget = widget->getParent();
270        }
271        mouseDownWidgets[msBtn] = lastMouseDownWidget = 0;
272}
273
274void WidgetWindow::eventMouseUp(int x, int y, MouseButton msBtn) {
275        WIDGET_LOG( __FUNCTION__ << "( " << x << ", " << y << ", " << MouseButtonNames[msBtn] << " )");
276        mousePos.x = x;
277        mousePos.y = getH() - y;
278        MouseWidget* downWidget = mouseDownWidgets[msBtn];
279        if (downWidget) {
280                downWidget->mouseUp(msBtn, mousePos);
281                mouseDownWidgets[msBtn] = 0;
282        }
283        if (lastMouseDownWidget == downWidget) {
284                lastMouseDownWidget = 0;
285                if (floatingWidget) {
286                        doMouseInto(floatingWidget->getWidgetAt(mousePos));
287                } else {
288                        doMouseInto(getWidgetAt(mousePos));
289                }
290        }
291}
292
293void WidgetWindow::eventMouseMove(int x, int y, const MouseState &ms) {
294        WIDGET_LOG( __FUNCTION__ << "( " << x << ", " << y << " )");
295        assert(!mouseOverStack.empty());
296        mousePos.x = x;
297        mousePos.y = getH() - y;
298
299        Widget* widget = 0;
300        if (floatingWidget) {
301                if (floatingWidget->isInside(mousePos)) {
302                        widget = floatingWidget->getWidgetAt(mousePos);
303                }
304        } else {
305                if (isInside(mousePos)) {
306                        widget = getWidgetAt(mousePos);
307                }
308        }
309        if (!widget) {
310                widget = this;
311        }
312        assert(widget);
313        if (lastMouseDownWidget) {
314                lastMouseDownWidget->mouseMove(mousePos);
315        } else {
316                doMouseInto(widget);
317                while (widget) {
318                        if (widget->asMouseWidget()) {
319                                if (widget->asMouseWidget()->mouseMove(mousePos)) {
320                                        return;
321                                }
322                        }
323                        widget = widget->getParent();
324                }
325        }
326}
327
328void WidgetWindow::eventMouseDoubleClick(int x, int y, MouseButton msBtn) {
329        WIDGET_LOG( __FUNCTION__ << "( " << x << ", " << y << ", " << MouseButtonNames[msBtn] << " )");
330        mousePos.x = x;
331        mousePos.y = getH() - y;
332        Widget* widget = 0;
333        if (floatingWidget) {
334                if (floatingWidget->isInside(mousePos)) {
335                        widget = floatingWidget->getWidgetAt(mousePos);
336                } else {
337                        if (!modalFloater) {
338                                destroyFloater();
339                        }
340                        return;
341                }
342        } else {
343                widget = getWidgetAt(mousePos);
344        }
345        while (widget) {
346                MouseWidget *mw = widget->asMouseWidget();
347                if (mw && mw->mouseDoubleClick(msBtn, mousePos)) {
348                        if (lastMouseDownWidget) {
349                                mouseDownWidgets[lastMouseDownButton] = 0;
350                        }
351                        mouseDownWidgets[msBtn] = lastMouseDownWidget = mw;
352                        lastMouseDownButton = msBtn;
353                        return;
354                }
355                widget = widget->getParent();
356        }
357}
358
359void WidgetWindow::eventMouseWheel(int x, int y, int zDelta) {
360        WIDGET_LOG( __FUNCTION__ << "( " << x << ", " << y << ", " << zDelta << " )");
361
362        Widget* widget = 0;
363        if (floatingWidget) {
364                if (floatingWidget->isInside(mousePos)) {
365                        widget = floatingWidget->getWidgetAt(mousePos);
366                }
367        } else {
368                widget = getWidgetAt(mousePos);
369        }
370        while (widget) {
371                if (widget->asMouseWidget()
372                && widget->asMouseWidget()->mouseWheel(mousePos, zDelta)) {
373                        return;
374                }
375                widget = widget->getParent();
376        }
377}
378
379void WidgetWindow::eventKeyDown(const Key &key) {
380        WIDGET_LOG( __FUNCTION__ << "( " << Key::getName(KeyCode(key)) << " )");
381        lastKeyDownWidget = keyboardFocused;
382        keyboardFocused->keyDown(key);
383}
384
385void WidgetWindow::eventKeyUp(const Key &key) {
386        WIDGET_LOG( __FUNCTION__ << "( " << Key::getName(KeyCode(key)) << " )");
387        if (keyboardFocused == lastKeyDownWidget) {
388                keyboardFocused->keyUp(key);
389        }
390}
391
392void WidgetWindow::eventKeyPress(char c) {
393        WIDGET_LOG( __FUNCTION__ << "( '" << c << "' )");
394        if (keyboardFocused == lastKeyDownWidget) {
395                keyboardFocused->keyPress(c);
396        }
397}
398
399void WidgetWindow::renderMouseCursor() {
400        float color1, color2;
401        Vec2i points[4];
402        points[0] = mousePos;
403        points[1] = mousePos + Vec2i(20, -10);
404        points[2] = mousePos + Vec2i(10, -20);
405
406        int numPoints;
407        if (mouseIcon) {
408                numPoints = 4;
409                points[3] = points[2];
410                points[2] = mousePos + Vec2i(10, -10);
411        } else {
412                numPoints = 3;
413        }
414
415        int mAnim = int(slowAnim * 200) - 100;
416        color2 = float(abs(mAnim)) / 100.f / 2.f + 0.4f;
417        color1 = float(abs(mAnim)) / 100.f / 2.f + 0.8f;
418
419        glPushAttrib(GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT);
420                glEnable(GL_BLEND);
421
422                //inside
423                glColor4f(0.4f, 0.2f, 0.2f, 0.5f);
424                glBegin(GL_TRIANGLE_FAN);
425                for (int i=0; i < numPoints; ++i) {
426                        glVertex2iv(points[i].ptr());
427                }
428                glEnd();
429
430                //border
431                glLineWidth(2);
432                glBegin(GL_LINE_LOOP);
433                        glColor4f(1.f, 0.2f, 0, color1);
434                        glVertex2iv(points[0].ptr());
435                        glColor4f(1.f, 0.4f, 0, color2);
436                        for (int i=1; i < numPoints; ++i) {
437                                glVertex2iv(points[i].ptr());
438                        }
439                glEnd();
440
441                if (mouseIcon) {
442                        int x1 = points[2].x + 1;
443                        int y2 = points[2].y - 1;
444                        int x2 = x1 + 32;
445                        int y1 = y2 - 32;
446                        glEnable(GL_TEXTURE_2D);
447                        glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(mouseIcon)->getHandle());
448                        glColor4f(1.f, 1.f, 1.f, 0.5f);
449                        glBegin(GL_TRIANGLE_STRIP);
450                                glTexCoord2i(0, 1);
451                                glVertex2i(x1, y2);
452                                glTexCoord2i(0, 0);
453                                glVertex2i(x1, y1);
454                                glTexCoord2i(1, 1);
455                                glVertex2i(x2, y2);
456                                glTexCoord2i(1, 0);
457                                glVertex2i(x2, y1);
458                        glEnd();
459                }
460        glPopAttrib();
461}
462
463}}
464
Note: See TracBrowser for help on using the browser.