1 /*      _______   __   __   __   ______   __   __   _______   __   __
2  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
3  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
4  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
5  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
6  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
7  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
8  *
9  * Copyright (c) 2004, 2005 darkbits                        Js_./
10  * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
11  * Olof Naess�n a.k.a jansem/yakslem                _asww7!uY`>  )\a//
12  *                                                 _Qhm`] _f "'c  1!5m
13  * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
14  *                                               .)j(] .d_/ '-(  P .   S
15  * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
16  * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
17  * binary forms, with or without                 )4d[#7r, .   '     )d`)[
18  * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
19  * that the following conditions are met:       j<<WP+k/);.        _W=j f
20  * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
21  *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
22  *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
23  *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
24  * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
25  *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
26  *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
27  *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
28  *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
29  *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
30  * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
31  *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
32  *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
33  *    from this software without specific        (js, \[QQW$QWW#?!V"".
34  *    prior written permission.                    ]y:.<\..          .
35  *                                                 -]n w/ '         [.
36  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
37  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
38  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
39  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
40  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
41  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
42  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
43  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
44  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
45  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
46  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
47  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
49  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
51  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
52  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 /*
56  * For comments regarding functions please see the header file.
57  */
58 #include <assert.h>
59 #include "guichan/exception.h"
60 #include "guichan/focushandler.h"
61 #include "guichan/gui.h"
62 #include "guichan/key.h"
63 
64 namespace gcn
65 {
Gui()66     Gui::Gui()
67     {
68         mTop = NULL;
69         mInput = NULL;
70         mGraphics = NULL;
71         mFocusHandler = new FocusHandler();
72         mTopHasMouse = false;
73         mTabbing = true;
74 		mUseDirtyDrawing = true;
75     }
76 
~Gui()77     Gui::~Gui()
78     {
79         if (Widget::widgetExists(mTop))
80         {
81             setTop(NULL);
82         }
83 
84         delete mFocusHandler;
85     }
86 
setTop(Widget * top)87     void Gui::setTop(Widget* top)
88     {
89         if (mTop)
90         {
91             mTop->_setFocusHandler(NULL);
92         }
93         if (top)
94         {
95             top->_setFocusHandler(mFocusHandler);
96             top->setDirty(true);
97         }
98 
99         mTop = top;
100     }
101 
getTop() const102     Widget* Gui::getTop() const
103     {
104         return mTop;
105     }
106 
setGraphics(Graphics * graphics)107     void Gui::setGraphics(Graphics* graphics)
108     {
109         mGraphics = graphics;
110     }
111 
getGraphics() const112     Graphics* Gui::getGraphics() const
113     {
114         return mGraphics;
115     }
116 
setInput(Input * input)117     void Gui::setInput(Input* input)
118     {
119         mInput = input;
120     }
121 
getInput() const122     Input* Gui::getInput() const
123     {
124         return mInput;
125     }
126 
logic()127     void Gui::logic()
128     {
129         if (!mTop)
130         {
131         	assert(!"No top widget set");
132             //throw GCN_EXCEPTION("No top widget set");
133         }
134 
135         if (mInput)
136         {
137             mInput->_pollInput();
138 
139             while (!mInput->isMouseQueueEmpty())
140             {
141                 MouseInput mi = mInput->dequeueMouseInput();
142 
143                 // Send mouse input to every widget that has the mouse.
144                 if (mi.x > 0 && mi.y > 0
145                     && mTop->getDimension().isPointInRect(mi.x, mi.y))
146                 {
147                     if (!mTop->hasMouse())
148                     {
149                         mTop->_mouseInMessage();
150                     }
151 
152                     MouseInput mio = mi;
153                     mio.x -= mTop->getX();
154                     mio.y -= mTop->getY();
155                     mTop->_mouseInputMessage(mio);
156                 }
157                 else if (mTop->hasMouse())
158                 {
159                     mTop->_mouseOutMessage();
160                 }
161 
162                 Widget* f = mFocusHandler->getFocused();
163                 Widget* d = mFocusHandler->getDragged();
164 
165                 // If the focused widget doesn't have the mouse,
166                 // send the mouse input to the focused widget.
167                 if (f != NULL && !f->hasMouse())
168                 {
169                     int xOffset, yOffset;
170                     f->getAbsolutePosition(xOffset, yOffset);
171 
172                     MouseInput mio = mi;
173                     mio.x -= xOffset;
174                     mio.y -= yOffset;
175 
176                     f->_mouseInputMessage(mio);
177                 }
178 
179                 // If the dragged widget is different from the focused
180                 // widget, send the mouse input to the dragged widget.
181                 if (d != NULL && d != f && !d->hasMouse())
182                 {
183                     int xOffset, yOffset;
184                     d->getAbsolutePosition(xOffset, yOffset);
185 
186                     MouseInput mio = mi;
187                     mio.x -= xOffset;
188                     mio.y -= yOffset;
189 
190                     d->_mouseInputMessage(mio);
191                 }
192 
193                 mFocusHandler->applyChanges();
194 
195             } // end while
196 
197             while (!mInput->isKeyQueueEmpty())
198             {
199                 KeyInput ki = mInput->dequeueKeyInput();
200 
201                 if (mTabbing
202                     && ki.getKey().getValue() == Key::K_TAB
203                     && ki.getType() == KeyInput::PRESS)
204                 {
205                     if (ki.getKey().isShiftPressed())
206                     {
207                         mFocusHandler->tabPrevious();
208                     }
209                     else
210                     {
211                         mFocusHandler->tabNext();
212                     }
213                 }
214                 else
215                 {
216                     bool keyProcessed = false;
217 
218                     // Send key inputs to the focused widgets
219                     if (mFocusHandler->getFocused())
220                     {
221                         if (mFocusHandler->getFocused()->isFocusable())
222                         {
223                             keyProcessed = mFocusHandler->getFocused()->_keyInputMessage(ki);
224                         }
225                         else
226                         {
227                             mFocusHandler->focusNone();
228                         }
229                     }
230 
231                     if (!keyProcessed)
232                     {
233                         mFocusHandler->checkHotKey(ki);
234                     }
235                 }
236 
237                 mFocusHandler->applyChanges();
238 
239             } // end while
240 
241         } // end if
242 
243         mTop->logic();
244     }
245 
draw(Widget * top)246     void Gui::draw(Widget* top)
247     {
248         if (!top)
249         {
250         	assert(!"No top widget set");
251             //throw GCN_EXCEPTION("No top widget set");
252         }
253         if (!mGraphics)
254         {
255         	assert(!"No graphics set");
256             //throw GCN_EXCEPTION("No graphics set");
257         }
258 
259         if (!mUseDirtyDrawing || top->getDirty())
260         {
261             mGraphics->_beginDraw();
262 
263             // If top has a border,
264             // draw it before drawing top
265             if (top->getBorderSize() > 0)
266             {
267                 Rectangle rec = top->getDimension();
268                 rec.x -= top->getBorderSize();
269                 rec.y -= top->getBorderSize();
270                 rec.width += 2 * top->getBorderSize();
271                 rec.height += 2 * top->getBorderSize();
272                 mGraphics->pushClipArea(rec);
273                 top->drawBorder(mGraphics);
274                 mGraphics->popClipArea();
275             }
276 
277             mGraphics->pushClipArea(top->getDimension());
278             top->draw(mGraphics);
279             top->setDirty(false);
280             mGraphics->popClipArea();
281 
282             mGraphics->_endDraw();
283         }
284     }
285 
draw()286     void Gui::draw()
287     {
288         draw(mTop);
289     }
290 
focusNone()291     void Gui::focusNone()
292     {
293         mFocusHandler->focusNone();
294     }
295 
setTabbingEnabled(bool tabbing)296     void Gui::setTabbingEnabled(bool tabbing)
297     {
298         mTabbing = tabbing;
299     }
300 
isTabbingEnabled()301     bool Gui::isTabbingEnabled()
302     {
303         return mTabbing;
304     }
305 
setUseDirtyDrawing(bool useDirtyDrawing)306 	void Gui::setUseDirtyDrawing(bool useDirtyDrawing)
307 	{
308 		mUseDirtyDrawing = useDirtyDrawing;
309 	}
310 }
311