00001 /* _______ __ __ __ ______ __ __ _______ __ __ 00002 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ 00003 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / 00004 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / 00005 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / 00006 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / 00007 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ 00008 * 00009 * Copyright (c) 2004, 2005, 2006 Olof Naessén and Per Larsson 00010 * 00011 * Js_./ 00012 * Per Larsson a.k.a finalman _RqZ{a<^_aa 00013 * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a// 00014 * _Qhm`] _f "'c 1!5m 00015 * Visit: http://guichan.darkbits.org )Qk<P ` _: :+' .' "{[ 00016 * .)j(] .d_/ '-( P . S 00017 * License: (BSD) <Td/Z <fP"5(\"??"\a. .L 00018 * Redistribution and use in source and _dV>ws?a-?' ._/L #' 00019 * binary forms, with or without )4d[#7r, . ' )d`)[ 00020 * modification, are permitted provided _Q-5'5W..j/?' -?!\)cam' 00021 * that the following conditions are met: j<<WP+k/);. _W=j f 00022 * 1. Redistributions of source code must .$%w\/]Q . ."' . mj$ 00023 * retain the above copyright notice, ]E.pYY(Q]>. a J@\ 00024 * this list of conditions and the j(]1u<sE"L,. . ./^ ]{a 00025 * following disclaimer. 4'_uomm\. )L);-4 (3= 00026 * 2. Redistributions in binary form must )_]X{Z('a_"a7'<a"a, ]"[ 00027 * reproduce the above copyright notice, #}<]m7`Za??4,P-"'7. ).m 00028 * this list of conditions and the ]d2e)Q(<Q( ?94 b- LQ/ 00029 * following disclaimer in the <B!</]C)d_, '(<' .f. =C+m 00030 * documentation and/or other materials .Z!=J ]e []('-4f _ ) -.)m]' 00031 * provided with the distribution. .w[5]' _[ /.)_-"+? _/ <W" 00032 * 3. Neither the name of Guichan nor the :$we` _! + _/ . j? 00033 * names of its contributors may be used =3)= _f (_yQmWW$#( " 00034 * to endorse or promote products derived - W, sQQQQmZQ#Wwa].. 00035 * from this software without specific (js, \[QQW$QWW#?!V"". 00036 * prior written permission. ]y:.<\.. . 00037 * -]n w/ ' [. 00038 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT )/ )/ ! 00039 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY < (; sac , ' 00040 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ]^ .- % 00041 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF c < r 00042 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR aga< <La 00043 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 5% )P'-3L 00044 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR _bQf` y`..)a 00045 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ,J?4P'.P"_(\?d'., 00046 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES _Pa,)!f/<[]/ ?" 00047 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT _2-..:. .r+_,.. . 00048 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ?a.<%"' " -'.a_ _, 00049 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ^ 00050 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00051 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00052 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00053 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00054 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00055 */ 00056 00057 /* 00058 * For comments regarding functions please see the header file. 00059 */ 00060 00061 #include "guichan/gui.hpp" 00062 00063 #include "guichan/exception.hpp" 00064 #include "guichan/focushandler.hpp" 00065 #include "guichan/graphics.hpp" 00066 #include "guichan/input.hpp" 00067 #include "guichan/keyinput.hpp" 00068 #include "guichan/keylistener.hpp" 00069 #include "guichan/mouseinput.hpp" 00070 #include "guichan/widget.hpp" 00071 00072 namespace gcn 00073 { 00074 Gui::Gui() 00075 { 00076 mTop = NULL; 00077 mInput = NULL; 00078 mGraphics = NULL; 00079 mFocusHandler = new FocusHandler(); 00080 mTopHasMouse = false; 00081 mTabbing = true; 00082 } 00083 00084 Gui::~Gui() 00085 { 00086 if (Widget::widgetExists(mTop)) 00087 { 00088 setTop(NULL); 00089 } 00090 00091 delete mFocusHandler; 00092 } 00093 00094 void Gui::setTop(Widget* top) 00095 { 00096 if (mTop) 00097 { 00098 mTop->_setFocusHandler(NULL); 00099 } 00100 if (top) 00101 { 00102 top->_setFocusHandler(mFocusHandler); 00103 } 00104 00105 mTop = top; 00106 } 00107 00108 Widget* Gui::getTop() const 00109 { 00110 return mTop; 00111 } 00112 00113 void Gui::setGraphics(Graphics* graphics) 00114 { 00115 mGraphics = graphics; 00116 } 00117 00118 Graphics* Gui::getGraphics() const 00119 { 00120 return mGraphics; 00121 } 00122 00123 void Gui::setInput(Input* input) 00124 { 00125 mInput = input; 00126 } 00127 00128 Input* Gui::getInput() const 00129 { 00130 return mInput; 00131 } 00132 00133 void Gui::logic() 00134 { 00135 if (!mTop) 00136 { 00137 throw GCN_EXCEPTION("No top widget set"); 00138 } 00139 00140 mFocusHandler->applyChanges(); 00141 00142 if(mInput) 00143 { 00144 mInput->_pollInput(); 00145 00146 while (!mInput->isMouseQueueEmpty()) 00147 { 00148 MouseInput mi = mInput->dequeueMouseInput(); 00149 00150 // Send mouse input to every widget that has the mouse. 00151 if (mi.x > 0 && mi.y > 0 00152 && mTop->getDimension().isPointInRect(mi.x, mi.y)) 00153 { 00154 if (!mTop->hasMouse()) 00155 { 00156 mTop->_mouseInMessage(); 00157 } 00158 00159 MouseInput mio = mi; 00160 mio.x -= mTop->getX(); 00161 mio.y -= mTop->getY(); 00162 mTop->_mouseInputMessage(mio); 00163 } 00164 else if (mTop->hasMouse()) 00165 { 00166 mTop->_mouseOutMessage(); 00167 } 00168 00169 Widget* f = mFocusHandler->getFocused(); 00170 Widget* d = mFocusHandler->getDragged(); 00171 00172 // If the focused widget doesn't have the mouse, 00173 // send the mouse input to the focused widget. 00174 if (f != NULL && !f->hasMouse()) 00175 { 00176 int xOffset, yOffset; 00177 f->getAbsolutePosition(xOffset, yOffset); 00178 00179 MouseInput mio = mi; 00180 mio.x -= xOffset; 00181 mio.y -= yOffset; 00182 00183 f->_mouseInputMessage(mio); 00184 } 00185 00186 // If the dragged widget is different from the focused 00187 // widget, send the mouse input to the dragged widget. 00188 if (d != NULL && d != f && !d->hasMouse()) 00189 { 00190 int xOffset, yOffset; 00191 d->getAbsolutePosition(xOffset, yOffset); 00192 00193 MouseInput mio = mi; 00194 mio.x -= xOffset; 00195 mio.y -= yOffset; 00196 00197 d->_mouseInputMessage(mio); 00198 } 00199 00200 mFocusHandler->applyChanges(); 00201 00202 } // end while 00203 00204 while (!mInput->isKeyQueueEmpty()) 00205 { 00206 KeyInput ki = mInput->dequeueKeyInput(); 00207 00208 KeyListenerListIterator it; 00209 00210 // Propagate key input to global KeyListeners 00211 switch(ki.getType()) 00212 { 00213 case KeyInput::PRESS: 00214 for (it = mKeyListeners.begin(); it != mKeyListeners.end(); ++it) 00215 { 00216 (*it)->keyPress(ki.getKey()); 00217 } 00218 break; 00219 00220 case KeyInput::RELEASE: 00221 for (it = mKeyListeners.begin(); it != mKeyListeners.end(); ++it) 00222 { 00223 (*it)->keyRelease(ki.getKey()); 00224 } 00225 break; 00226 } 00227 00228 if (mTabbing 00229 && ki.getKey().getValue() == Key::TAB 00230 && ki.getType() == KeyInput::PRESS) 00231 { 00232 if (ki.getKey().isShiftPressed()) 00233 { 00234 mFocusHandler->tabPrevious(); 00235 } 00236 else 00237 { 00238 mFocusHandler->tabNext(); 00239 } 00240 } 00241 else 00242 { 00243 // Send key inputs to the focused widgets 00244 if (mFocusHandler->getFocused()) 00245 { 00246 if (mFocusHandler->getFocused()->isFocusable()) 00247 { 00248 mFocusHandler->getFocused()->_keyInputMessage(ki); 00249 } 00250 else 00251 { 00252 mFocusHandler->focusNone(); 00253 } 00254 } 00255 } 00256 00257 mFocusHandler->applyChanges(); 00258 00259 } // end while 00260 00261 // Apply changes even if no input has been processed. 00262 // A widget might has asked for focus. 00263 mFocusHandler->applyChanges(); 00264 00265 } // end if 00266 00267 mTop->logic(); 00268 } 00269 00270 void Gui::draw() 00271 { 00272 if (!mTop) 00273 { 00274 throw GCN_EXCEPTION("No top widget set"); 00275 } 00276 if (!mGraphics) 00277 { 00278 throw GCN_EXCEPTION("No graphics set"); 00279 } 00280 00281 if (!mTop->isVisible()) 00282 { 00283 return; 00284 } 00285 00286 mGraphics->_beginDraw(); 00287 00288 // If top has a border, 00289 // draw it before drawing top 00290 if (mTop->getBorderSize() > 0) 00291 { 00292 Rectangle rec = mTop->getDimension(); 00293 rec.x -= mTop->getBorderSize(); 00294 rec.y -= mTop->getBorderSize(); 00295 rec.width += 2 * mTop->getBorderSize(); 00296 rec.height += 2 * mTop->getBorderSize(); 00297 mGraphics->pushClipArea(rec); 00298 mTop->drawBorder(mGraphics); 00299 mGraphics->popClipArea(); 00300 } 00301 00302 mGraphics->pushClipArea(mTop->getDimension()); 00303 mTop->draw(mGraphics); 00304 mGraphics->popClipArea(); 00305 00306 00307 mGraphics->_endDraw(); 00308 } 00309 00310 void Gui::focusNone() 00311 { 00312 mFocusHandler->focusNone(); 00313 } 00314 00315 void Gui::setTabbingEnabled(bool tabbing) 00316 { 00317 mTabbing = tabbing; 00318 } 00319 00320 bool Gui::isTabbingEnabled() 00321 { 00322 return mTabbing; 00323 } 00324 00325 void Gui::addGlobalKeyListener(KeyListener* keyListener) 00326 { 00327 mKeyListeners.push_back(keyListener); 00328 } 00329 00330 void Gui::removeGlobalKeyListener(KeyListener* keyListener) 00331 { 00332 mKeyListeners.remove(keyListener); 00333 } 00334 }