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 
59 #include "guichan/basiccontainer.h"
60 #include "guichan/exception.h"
61 #include "guichan/focushandler.h"
62 #include "guichan/widget.h"
63 
64 #include <iostream>
65 #include <assert.h>
66 
67 #include "guichan/sdl/sdlinput.h"
68 #include "SDL.h"
69 extern int Str2SdlKey(const char *str);
70 
convertKey(const char * key)71 int convertKey(const char *key)
72 {
73 	SDL_Keysym keysym;
74 	memset(&keysym, 0, sizeof(keysym));
75 	keysym.sym = (SDL_Keycode)Str2SdlKey(key);
76 	gcn::Key k = gcn::SDLInput::convertKeyCharacter(keysym);
77 	return k.getValue();
78 }
79 
80 namespace gcn
81 {
82     Font* Widget::mGlobalFont = NULL;
83     DefaultFont Widget::mDefaultFont;
84     std::list<Widget*> Widget::mWidgets;
85 
Widget()86     Widget::Widget()
87     {
88         mParent = NULL;
89         mForegroundColor = Color(0x000000);
90         mBackgroundColor = Color(0xffffff);
91         mBaseColor = Color(0x808090);
92         mBorderSize = 0;
93         mFocusHandler = NULL;
94         mFocusable = false;
95         mClickTimeStamp = 0;
96         mClickCount = 0;
97         mHasMouse = false;
98         mVisible = true;
99         mTabIn = true;
100         mTabOut = true;
101         mEnabled = true;
102         mClickButton = 0;
103         mHotKey = 0;
104 
105         mCurrentFont = NULL;
106         mWidgets.push_back(this);
107         mDirty = true;
108     }
109 
~Widget()110     Widget::~Widget()
111     {
112         if (getParent() != NULL)
113         {
114             getParent()->_announceDeath(this);
115         }
116 
117         _setFocusHandler(NULL);
118 
119         mWidgets.remove(this);
120     }
121 
_setParent(BasicContainer * parent)122     void Widget::_setParent(BasicContainer* parent)
123     {
124         mParent = parent;
125     }
126 
getParent() const127     BasicContainer* Widget::getParent() const
128     {
129         return mParent;
130     }
131 
setWidth(int width)132     void Widget::setWidth(int width)
133     {
134         mDimension.width = width;
135     }
136 
getWidth() const137     int Widget::getWidth() const
138     {
139         return mDimension.width;
140     }
141 
setHeight(int height)142     void Widget::setHeight(int height)
143     {
144         mDimension.height = height;
145     }
146 
getHeight() const147     int Widget::getHeight() const
148     {
149         return mDimension.height;
150     }
151 
setX(int x)152     void Widget::setX(int x)
153     {
154         mDimension.x = x;
155     }
156 
getX() const157     int Widget::getX() const
158     {
159         return mDimension.x;
160     }
161 
setY(int y)162     void Widget::setY(int y)
163     {
164         mDimension.y = y;
165     }
166 
getY() const167     int Widget::getY() const
168     {
169         return mDimension.y;
170     }
171 
setPosition(int x,int y)172     void Widget::setPosition(int x, int y)
173     {
174         mDimension.x = x;
175         mDimension.y = y;
176     }
177 
setDimension(const Rectangle & dimension)178     void Widget::setDimension(const Rectangle& dimension)
179     {
180         mDimension = dimension;
181     }
182 
setBorderSize(unsigned int borderSize)183     void Widget::setBorderSize(unsigned int borderSize)
184     {
185         mBorderSize = borderSize;
186     }
187 
getBorderSize() const188     unsigned int Widget::getBorderSize() const
189     {
190         return mBorderSize;
191     }
192 
getDimension() const193     const Rectangle& Widget::getDimension() const
194     {
195         return mDimension;
196     }
197 
getEventId() const198     const std::string& Widget::getEventId() const
199     {
200         return mEventId;
201     }
202 
setEventId(const std::string & eventId)203     void Widget::setEventId(const std::string& eventId)
204     {
205         mEventId = eventId;
206     }
207 
hasFocus() const208     bool Widget::hasFocus() const
209     {
210         if (!mFocusHandler)
211         {
212             return false;
213         }
214 
215         return (mFocusHandler->hasFocus(this));
216     }
217 
hasMouse() const218     bool Widget::hasMouse() const
219     {
220         return mHasMouse;
221     }
222 
setFocusable(bool focusable)223     void Widget::setFocusable(bool focusable)
224     {
225         if (!focusable && hasFocus())
226         {
227             mFocusHandler->focusNone();
228         }
229 
230         mFocusable = focusable;
231     }
232 
isFocusable() const233     bool Widget::isFocusable() const
234     {
235         return mFocusable && isVisible() && isEnabled();
236     }
237 
requestFocus()238     void Widget::requestFocus()
239     {
240         if (mFocusHandler == NULL)
241         {
242             //throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
243             assert(!"No focushandler set (did you add the widget to the gui?).");
244         }
245 
246         if (isFocusable())
247         {
248             mFocusHandler->requestFocus(this);
249         }
250     }
251 
requestMoveToTop()252     void Widget::requestMoveToTop()
253     {
254         if (mParent)
255         {
256             mParent->moveToTop(this);
257         }
258     }
259 
requestMoveToBottom()260     void Widget::requestMoveToBottom()
261     {
262         if (mParent)
263         {
264             mParent->moveToBottom(this);
265         }
266     }
267 
setVisible(bool visible)268     void Widget::setVisible(bool visible)
269     {
270         if (!visible && hasFocus())
271         {
272             mFocusHandler->focusNone();
273         }
274         mVisible = visible;
275     }
276 
isVisible() const277     bool Widget::isVisible() const
278     {
279         if (getParent() == NULL)
280         {
281             return mVisible;
282         }
283         else
284         {
285             return mVisible && getParent()->isVisible();
286         }
287     }
288 
setBaseColor(const Color & color)289     void Widget::setBaseColor(const Color& color)
290     {
291         mBaseColor = color;
292     }
293 
getBaseColor() const294     const Color& Widget::getBaseColor() const
295     {
296         return mBaseColor;
297     }
298 
setForegroundColor(const Color & color)299     void Widget::setForegroundColor(const Color& color)
300     {
301         mForegroundColor = color;
302     }
303 
getForegroundColor() const304     const Color& Widget::getForegroundColor() const
305     {
306         return mForegroundColor;
307     }
308 
setBackgroundColor(const Color & color)309     void Widget::setBackgroundColor(const Color& color)
310     {
311         mBackgroundColor = color;
312     }
313 
getBackgroundColor() const314     const Color& Widget::getBackgroundColor() const
315     {
316         return mBackgroundColor;
317     }
318 
setDisabledColor(const Color & color)319     void Widget::setDisabledColor(const Color& color)
320     {
321         mDisabledColor = color;
322     }
323 
getDisabledColor() const324     const Color& Widget::getDisabledColor() const
325     {
326         return mDisabledColor;
327     }
328 
_setFocusHandler(FocusHandler * focusHandler)329     void Widget::_setFocusHandler(FocusHandler* focusHandler)
330     {
331         if (mFocusHandler)
332         {
333             releaseModalFocus();
334             mFocusHandler->remove(this);
335         }
336 
337         if (focusHandler)
338         {
339             focusHandler->add(this);
340         }
341 
342         mFocusHandler = focusHandler;
343     }
344 
_getFocusHandler()345     FocusHandler* Widget::_getFocusHandler()
346     {
347         return mFocusHandler;
348     }
349 
addActionListener(ActionListener * actionListener)350     void Widget::addActionListener(ActionListener* actionListener)
351     {
352         mActionListeners.push_back(actionListener);
353     }
354 
removeActionListener(ActionListener * actionListener)355     void Widget::removeActionListener(ActionListener* actionListener)
356     {
357         mActionListeners.remove(actionListener);
358     }
359 
addKeyListener(KeyListener * keyListener)360     void Widget::addKeyListener(KeyListener* keyListener)
361     {
362         mKeyListeners.push_back(keyListener);
363     }
364 
removeKeyListener(KeyListener * keyListener)365     void Widget::removeKeyListener(KeyListener* keyListener)
366     {
367         mKeyListeners.remove(keyListener);
368     }
369 
addMouseListener(MouseListener * mouseListener)370     void Widget::addMouseListener(MouseListener* mouseListener)
371     {
372         mMouseListeners.push_back(mouseListener);
373     }
374 
removeMouseListener(MouseListener * mouseListener)375     void Widget::removeMouseListener(MouseListener* mouseListener)
376     {
377         mMouseListeners.remove(mouseListener);
378     }
379 
_mouseInputMessage(const MouseInput & mouseInput)380     void Widget::_mouseInputMessage(const MouseInput& mouseInput)
381     {
382         if (mFocusHandler == NULL)
383         {
384             //throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
385             // assert(!"No focushandler set (did you add the widget to the gui?).");
386             return;
387         }
388 
389         if (!mEnabled || (mFocusHandler->getModalFocused() != NULL &&
390                           !hasModalFocus()))
391         {
392             return;
393         }
394 
395         int x = mouseInput.x;
396         int y = mouseInput.y;
397         int b = mouseInput.getButton();
398         int ts = mouseInput.getTimeStamp();
399 
400         MouseListenerIterator iter;
401 
402         switch(mouseInput.getType())
403         {
404           case MouseInput::MOTION:
405               for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
406               {
407                   (*iter)->mouseMotion(x, y);
408               }
409               break;
410 
411           case MouseInput::PRESS:
412               if (hasMouse())
413               {
414                   requestFocus();
415                   if (b != MouseInput::WHEEL_UP && b != MouseInput::WHEEL_DOWN)
416                       mFocusHandler->requestDrag(this);
417               }
418 
419               if (b != MouseInput::WHEEL_UP && b != MouseInput::WHEEL_DOWN)
420               {
421 
422                   for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
423                   {
424                       (*iter)->mousePress(x, y, b);
425                   }
426 
427                   if (hasMouse())
428                   {
429                       if (ts - mClickTimeStamp < 300 && mClickButton == b)
430                       {
431                           mClickCount++;
432                       }
433                       else
434                       {
435                           mClickCount = 0;
436                       }
437                       mClickButton = b;
438                       mClickTimeStamp = ts;
439                   }
440                   else
441                   {
442                       mClickButton = 0;
443                   }
444               }
445               setDirty(true);
446               break;
447 
448           case MouseInput::RELEASE:
449               if (isDragged())
450               {
451                   mFocusHandler->dragNone();
452               }
453 
454               if (b != MouseInput::WHEEL_UP && b != MouseInput::WHEEL_DOWN)
455               {
456                   for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
457                   {
458                       (*iter)->mouseRelease(x, y, b);
459                   }
460               }
461 
462               if (mHasMouse)
463               {
464                   if (b == mClickButton)
465                   {
466                       for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
467                       {
468                           (*iter)->mouseClick(x, y, b, mClickCount + 1);
469                       }
470                   }
471                   else
472                   {
473                       mClickButton = 0;
474                       mClickCount = 0;
475                   }
476               }
477               else
478               {
479                   mClickCount = 0;
480                   mClickTimeStamp = 0;
481               }
482               setDirty(true);
483               break;
484 
485           case MouseInput::WHEEL_UP:
486               for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
487               {
488                   (*iter)->mouseWheelUp(x, y);
489               }
490               setDirty(true);
491               break;
492 
493           case MouseInput::WHEEL_DOWN:
494               for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
495               {
496                   (*iter)->mouseWheelDown(x, y);
497               }
498               setDirty(true);
499               break;
500         }
501     }
502 
_keyInputMessage(const KeyInput & keyInput)503     bool Widget::_keyInputMessage(const KeyInput& keyInput)
504     {
505         if (mFocusHandler == NULL)
506         {
507             //throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
508             assert(!"No focushandler set (did you add the widget to the gui?).");
509         }
510 
511         if (!mEnabled || (mFocusHandler->getModalFocused() != NULL &&
512                           !hasModalFocus()))
513         {
514             return false;
515         }
516 
517         KeyListenerIterator iter;
518         bool keyProcessed = false;
519 
520         switch(keyInput.getType())
521         {
522           case KeyInput::PRESS:
523               for (iter = mKeyListeners.begin(); iter != mKeyListeners.end(); ++iter)
524               {
525                   if ((*iter)->keyPress(keyInput.getKey()))
526                   {
527                       keyProcessed = true;
528                   }
529               }
530               break;
531 
532           case KeyInput::RELEASE:
533               for (iter = mKeyListeners.begin(); iter != mKeyListeners.end(); ++iter)
534               {
535                   if ((*iter)->keyRelease(keyInput.getKey()))
536                   {
537                       keyProcessed = true;
538                   }
539               }
540               break;
541         }
542 
543         return keyProcessed;
544     }
545 
_mouseInMessage()546     void Widget::_mouseInMessage()
547     {
548         if (!mEnabled)
549         {
550             return;
551         }
552 
553         mHasMouse = true;
554 		setDirty(true);
555 
556         MouseListenerIterator iter;
557         for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
558         {
559             (*iter)->mouseIn();
560         }
561     }
562 
_mouseOutMessage()563     void Widget::_mouseOutMessage()
564     {
565         mHasMouse = false;
566 		setDirty(true);
567 
568         MouseListenerIterator iter;
569         for (iter = mMouseListeners.begin(); iter != mMouseListeners.end(); ++iter)
570         {
571             (*iter)->mouseOut();
572         }
573     }
574 
getAbsolutePosition(int & x,int & y) const575     void Widget::getAbsolutePosition(int& x, int& y) const
576     {
577         if (getParent() == NULL)
578         {
579             x = mDimension.x;
580             y = mDimension.y;
581             return;
582         }
583 
584         int parentX;
585         int parentY;
586 
587         getParent()->getAbsolutePosition(parentX, parentY);
588 
589         x = parentX + mDimension.x;
590         y = parentY + mDimension.y;
591     }
592 
generateAction()593     void Widget::generateAction()
594     {
595         ActionListenerIterator iter;
596         for (iter = mActionListeners.begin(); iter != mActionListeners.end(); ++iter)
597         {
598             (*iter)->action(mEventId);
599         }
600     }
601 
getFont() const602     Font* Widget::getFont() const
603     {
604         if (mCurrentFont == NULL)
605         {
606             if (mGlobalFont == NULL)
607             {
608                 return &mDefaultFont;
609             }
610 
611             return mGlobalFont;
612         }
613 
614         return mCurrentFont;
615     }
616 
setGlobalFont(Font * font)617     void Widget::setGlobalFont(Font* font)
618     {
619         mGlobalFont = font;
620 
621         std::list<Widget*>::iterator iter;
622         for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter)
623         {
624             if ((*iter)->mCurrentFont == NULL)
625             {
626                 (*iter)->fontChanged();
627             }
628         }
629     }
630 
setFont(Font * font)631     void Widget::setFont(Font* font)
632     {
633         mCurrentFont = font;
634         fontChanged();
635     }
636 
setHotKey(const int key)637     void Widget::setHotKey(const int key)
638     {
639         if (isascii(key))
640         {
641             mHotKey = tolower(key);
642         }
643         else
644         {
645             mHotKey = key;
646         }
647     }
648 
setHotKey(const char * key)649     void Widget::setHotKey(const char *key)
650     {
651         if (key)
652         {
653 			mHotKey = ::convertKey(key);
654             if (mHotKey == 0)
655             {
656                 //throw GCN_EXCEPTION("Could not parse hot key");
657                 assert(!"Could not parse hot key");
658             }
659         }
660     }
661 
widgetExists(const Widget * widget)662     bool Widget::widgetExists(const Widget* widget)
663     {
664         bool result = false;
665 
666         std::list<Widget*>::iterator iter;
667         for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter)
668         {
669             if (*iter == widget)
670             {
671                 return true;
672             }
673         }
674 
675         return result;
676     }
677 
isTabInEnabled() const678     bool Widget::isTabInEnabled() const
679     {
680         return mTabIn;
681     }
682 
setTabInEnabled(bool enabled)683     void Widget::setTabInEnabled(bool enabled)
684     {
685         mTabIn = enabled;
686     }
687 
isTabOutEnabled() const688     bool Widget::isTabOutEnabled() const
689     {
690         return mTabOut;
691     }
692 
setTabOutEnabled(bool enabled)693     void Widget::setTabOutEnabled(bool enabled)
694     {
695         mTabOut = enabled;
696     }
697 
setSize(int width,int height)698     void Widget::setSize(int width, int height)
699     {
700         setWidth(width);
701         setHeight(height);
702     }
703 
setEnabled(bool enabled)704     void Widget::setEnabled(bool enabled)
705     {
706         mEnabled = enabled;
707     }
708 
isEnabled() const709     bool Widget::isEnabled() const
710     {
711         return mEnabled && isVisible();
712     }
713 
isDragged() const714     bool Widget::isDragged() const
715     {
716         if (mFocusHandler == NULL)
717         {
718         	assert(!"No focushandler set (did you add the widget to the gui?).");
719             //throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
720         }
721 
722         return mFocusHandler->isDragged(this);
723     }
724 
requestModalFocus()725     void Widget::requestModalFocus()
726     {
727         if (mFocusHandler == NULL)
728         {
729         	assert(!"No focushandler set (did you add the widget to the gui?).");
730             //throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
731         }
732 
733         mFocusHandler->requestModalFocus(this);
734     }
735 
releaseModalFocus()736     void Widget::releaseModalFocus()
737     {
738         if (mFocusHandler == NULL)
739         {
740             return;
741         }
742 
743         mFocusHandler->releaseModalFocus(this);
744     }
745 
hasModalFocus() const746     bool Widget::hasModalFocus() const
747     {
748         if (mFocusHandler == NULL)
749         {
750             //throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
751             assert(!"No focushandler set (did you add the widget to the gui?).");
752         }
753 
754         if (getParent() != NULL)
755         {
756             return (mFocusHandler->getModalFocused() == this) || getParent()->hasModalFocus();
757         }
758 
759         return mFocusHandler->getModalFocused() == this;
760     }
761 
setDirty(bool dirty)762     void Widget::setDirty(bool dirty)
763     {
764         mDirty = dirty;
765     }
766 
getDirty() const767     bool Widget::getDirty() const
768     {
769         return mDirty;
770     }
771 }
772 
773