1 /*      _______   __   __   __   ______   __   __   _______   __   __
2  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
3  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
4  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
5  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
6  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
7  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
8  *
9  * Copyright (c) 2004 - 2008 Olof Naess�n and Per Larsson
10  *
11  *
12  * Per Larsson a.k.a finalman
13  * Olof Naess�n a.k.a jansem/yakslem
14  *
15  * Visit: http://guichan.sourceforge.net
16  *
17  * License: (BSD)
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in
25  *    the documentation and/or other materials provided with the
26  *    distribution.
27  * 3. Neither the name of Guichan nor the names of its contributors may
28  *    be used to endorse or promote products derived from this software
29  *    without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
37  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
38  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  */
43 
44 /*
45  * For comments regarding functions please see the header file.
46  */
47 
48 #include "guichan/widget.hpp"
49 
50 #include "guichan/actionevent.hpp"
51 #include "guichan/actionlistener.hpp"
52 #include "guichan/basiccontainer.hpp"
53 #include "guichan/deathlistener.hpp"
54 #include "guichan/defaultfont.hpp"
55 #include "guichan/event.hpp"
56 #include "guichan/exception.hpp"
57 #include "guichan/focushandler.hpp"
58 #include "guichan/graphics.hpp"
59 #include "guichan/keyinput.hpp"
60 #include "guichan/keylistener.hpp"
61 #include "guichan/mouseinput.hpp"
62 #include "guichan/mouselistener.hpp"
63 #include "guichan/widgetlistener.hpp"
64 
65 namespace gcn
66 {
67     Font* Widget::mGlobalFont = NULL;
68     DefaultFont Widget::mDefaultFont;
69     std::list<Widget*> Widget::mWidgets;
70 
Widget()71     Widget::Widget()
72             : mForegroundColor(0x000000),
73               mBackgroundColor(0xffffff),
74               mBaseColor(0x808090),
75               mSelectionColor(0xc3d9ff),
76               mFocusHandler(NULL),
77               mInternalFocusHandler(NULL),
78               mParent(NULL),
79               mFrameSize(0),
80               mFocusable(false),
81               mVisible(true),
82               mTabIn(true),
83               mTabOut(true),
84               mEnabled(true),
85               mCurrentFont(NULL)
86     {
87         mWidgets.push_back(this);
88     }
89 
~Widget()90     Widget::~Widget()
91     {
92         DeathListenerIterator iter;
93 
94         for (iter = mDeathListeners.begin(); iter != mDeathListeners.end(); ++iter)
95         {
96             Event event(this);
97             (*iter)->death(event);
98         }
99 
100         _setFocusHandler(NULL);
101 
102         mWidgets.remove(this);
103     }
104 
drawFrame(Graphics * graphics)105     void Widget::drawFrame(Graphics* graphics)
106     {
107         Color faceColor = getBaseColor();
108         Color highlightColor, shadowColor;
109         int alpha = getBaseColor().a;
110         int width = getWidth() + getFrameSize() * 2 - 1;
111         int height = getHeight() + getFrameSize() * 2 - 1;
112         highlightColor = faceColor + 0x303030;
113         highlightColor.a = alpha;
114         shadowColor = faceColor - 0x303030;
115         shadowColor.a = alpha;
116 
117         unsigned int i;
118         for (i = 0; i < getFrameSize(); ++i)
119         {
120             graphics->setColor(shadowColor);
121             graphics->drawLine(i,i, width - i, i);
122             graphics->drawLine(i,i + 1, i, height - i - 1);
123             graphics->setColor(highlightColor);
124             graphics->drawLine(width - i,i + 1, width - i, height - i);
125             graphics->drawLine(i,height - i, width - i - 1, height - i);
126         }
127     }
128 
_setParent(Widget * parent)129     void Widget::_setParent(Widget* parent)
130     {
131         mParent = parent;
132     }
133 
getParent() const134     Widget* Widget::getParent() const
135     {
136         return mParent;
137     }
138 
setWidth(int width)139     void Widget::setWidth(int width)
140     {
141         Rectangle newDimension = mDimension;
142         newDimension.width = width;
143 
144         setDimension(newDimension);
145     }
146 
getWidth() const147     int Widget::getWidth() const
148     {
149         return mDimension.width;
150     }
151 
setHeight(int height)152     void Widget::setHeight(int height)
153     {
154         Rectangle newDimension = mDimension;
155         newDimension.height = height;
156 
157         setDimension(newDimension);
158     }
159 
getHeight() const160     int Widget::getHeight() const
161     {
162         return mDimension.height;
163     }
164 
setX(int x)165     void Widget::setX(int x)
166     {
167         Rectangle newDimension = mDimension;
168         newDimension.x = x;
169 
170         setDimension(newDimension);
171     }
172 
getX() const173     int Widget::getX() const
174     {
175         return mDimension.x;
176     }
177 
setY(int y)178     void Widget::setY(int y)
179     {
180         Rectangle newDimension = mDimension;
181         newDimension.y = y;
182 
183         setDimension(newDimension);
184     }
185 
getY() const186     int Widget::getY() const
187     {
188         return mDimension.y;
189     }
190 
setPosition(int x,int y)191     void Widget::setPosition(int x, int y)
192     {
193         Rectangle newDimension = mDimension;
194         newDimension.x = x;
195         newDimension.y = y;
196 
197         setDimension(newDimension);
198     }
199 
setDimension(const Rectangle & dimension)200     void Widget::setDimension(const Rectangle& dimension)
201     {
202         Rectangle oldDimension = mDimension;
203         mDimension = dimension;
204 
205         if (mDimension.width != oldDimension.width
206             || mDimension.height != oldDimension.height)
207         {
208             distributeResizedEvent();
209         }
210 
211         if (mDimension.x != oldDimension.x
212             || mDimension.y != oldDimension.y)
213         {
214             distributeMovedEvent();
215         }
216     }
217 
setFrameSize(unsigned int frameSize)218     void Widget::setFrameSize(unsigned int frameSize)
219     {
220         mFrameSize = frameSize;
221     }
222 
getFrameSize() const223     unsigned int Widget::getFrameSize() const
224     {
225         return mFrameSize;
226     }
227 
getDimension() const228     const Rectangle& Widget::getDimension() const
229     {
230         return mDimension;
231     }
232 
getActionEventId() const233     const std::string& Widget::getActionEventId() const
234     {
235         return mActionEventId;
236     }
237 
setActionEventId(const std::string & actionEventId)238     void Widget::setActionEventId(const std::string& actionEventId)
239     {
240         mActionEventId = actionEventId;
241     }
242 
isFocused() const243     bool Widget::isFocused() const
244     {
245         if (!mFocusHandler)
246         {
247             return false;
248         }
249 
250         return (mFocusHandler->isFocused(this));
251     }
252 
setFocusable(bool focusable)253     void Widget::setFocusable(bool focusable)
254     {
255         if (!focusable && isFocused())
256         {
257             mFocusHandler->focusNone();
258         }
259 
260         mFocusable = focusable;
261     }
262 
isFocusable() const263     bool Widget::isFocusable() const
264     {
265         return mFocusable && isVisible() && isEnabled();
266     }
267 
requestFocus()268     void Widget::requestFocus()
269     {
270         if (mFocusHandler == NULL)
271         {
272             throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
273         }
274 
275         if (isFocusable())
276         {
277             mFocusHandler->requestFocus(this);
278         }
279     }
280 
requestMoveToTop()281     void Widget::requestMoveToTop()
282     {
283         if (mParent)
284         {
285             mParent->moveToTop(this);
286         }
287     }
288 
requestMoveToBottom()289     void Widget::requestMoveToBottom()
290     {
291         if (mParent)
292         {
293             mParent->moveToBottom(this);
294         }
295     }
296 
setVisible(bool visible)297     void Widget::setVisible(bool visible)
298     {
299         if (!visible && isFocused())
300         {
301             mFocusHandler->focusNone();
302         }
303 
304         if (visible)
305         {
306             distributeShownEvent();
307         }
308         else if(!visible)
309         {
310             distributeHiddenEvent();
311         }
312 
313         mVisible = visible;
314     }
315 
isVisible() const316     bool Widget::isVisible() const
317     {
318         if (getParent() == NULL)
319         {
320             return mVisible;
321         }
322         else
323         {
324             return mVisible && getParent()->isVisible();
325         }
326     }
327 
setBaseColor(const Color & color)328     void Widget::setBaseColor(const Color& color)
329     {
330         mBaseColor = color;
331     }
332 
getBaseColor() const333     const Color& Widget::getBaseColor() const
334     {
335         return mBaseColor;
336     }
337 
setForegroundColor(const Color & color)338     void Widget::setForegroundColor(const Color& color)
339     {
340         mForegroundColor = color;
341     }
342 
getForegroundColor() const343     const Color& Widget::getForegroundColor() const
344     {
345         return mForegroundColor;
346     }
347 
setBackgroundColor(const Color & color)348     void Widget::setBackgroundColor(const Color& color)
349     {
350         mBackgroundColor = color;
351     }
352 
getBackgroundColor() const353     const Color& Widget::getBackgroundColor() const
354     {
355         return mBackgroundColor;
356     }
357 
setSelectionColor(const Color & color)358     void Widget::setSelectionColor(const Color& color)
359     {
360         mSelectionColor = color;
361     }
362 
getSelectionColor() const363     const Color& Widget::getSelectionColor() const
364     {
365         return mSelectionColor;
366     }
367 
_setFocusHandler(FocusHandler * focusHandler)368     void Widget::_setFocusHandler(FocusHandler* focusHandler)
369     {
370         if (mFocusHandler)
371         {
372             releaseModalFocus();
373             mFocusHandler->remove(this);
374         }
375 
376         if (focusHandler)
377         {
378             focusHandler->add(this);
379         }
380 
381         mFocusHandler = focusHandler;
382     }
383 
_getFocusHandler()384     FocusHandler* Widget::_getFocusHandler()
385     {
386         return mFocusHandler;
387     }
388 
addActionListener(ActionListener * actionListener)389     void Widget::addActionListener(ActionListener* actionListener)
390     {
391         mActionListeners.push_back(actionListener);
392     }
393 
removeActionListener(ActionListener * actionListener)394     void Widget::removeActionListener(ActionListener* actionListener)
395     {
396         mActionListeners.remove(actionListener);
397     }
398 
addDeathListener(DeathListener * deathListener)399     void Widget::addDeathListener(DeathListener* deathListener)
400     {
401         mDeathListeners.push_back(deathListener);
402     }
403 
removeDeathListener(DeathListener * deathListener)404     void Widget::removeDeathListener(DeathListener* deathListener)
405     {
406         mDeathListeners.remove(deathListener);
407     }
408 
addKeyListener(KeyListener * keyListener)409     void Widget::addKeyListener(KeyListener* keyListener)
410     {
411         mKeyListeners.push_back(keyListener);
412     }
413 
removeKeyListener(KeyListener * keyListener)414     void Widget::removeKeyListener(KeyListener* keyListener)
415     {
416         mKeyListeners.remove(keyListener);
417     }
418 
addFocusListener(FocusListener * focusListener)419     void Widget::addFocusListener(FocusListener* focusListener)
420     {
421         mFocusListeners.push_back(focusListener);
422     }
423 
removeFocusListener(FocusListener * focusListener)424     void Widget::removeFocusListener(FocusListener* focusListener)
425     {
426         mFocusListeners.remove(focusListener);
427     }
428 
addMouseListener(MouseListener * mouseListener)429     void Widget::addMouseListener(MouseListener* mouseListener)
430     {
431         mMouseListeners.push_back(mouseListener);
432     }
433 
removeMouseListener(MouseListener * mouseListener)434     void Widget::removeMouseListener(MouseListener* mouseListener)
435     {
436         mMouseListeners.remove(mouseListener);
437     }
438 
addWidgetListener(WidgetListener * widgetListener)439     void Widget::addWidgetListener(WidgetListener* widgetListener)
440     {
441         mWidgetListeners.push_back(widgetListener);
442     }
443 
removeWidgetListener(WidgetListener * widgetListener)444     void Widget::removeWidgetListener(WidgetListener* widgetListener)
445     {
446         mWidgetListeners.remove(widgetListener);
447     }
448 
getAbsolutePosition(int & x,int & y) const449     void Widget::getAbsolutePosition(int& x, int& y) const
450     {
451         if (getParent() == NULL)
452         {
453             x = mDimension.x;
454             y = mDimension.y;
455             return;
456         }
457 
458         int parentX;
459         int parentY;
460 
461         getParent()->getAbsolutePosition(parentX, parentY);
462 
463         x = parentX + mDimension.x + getParent()->getChildrenArea().x;
464         y = parentY + mDimension.y + getParent()->getChildrenArea().y;
465     }
466 
getFont() const467     Font* Widget::getFont() const
468     {
469         if (mCurrentFont == NULL)
470         {
471             if (mGlobalFont == NULL)
472             {
473                 return &mDefaultFont;
474             }
475 
476             return mGlobalFont;
477         }
478 
479         return mCurrentFont;
480     }
481 
setGlobalFont(Font * font)482     void Widget::setGlobalFont(Font* font)
483     {
484         mGlobalFont = font;
485 
486         std::list<Widget*>::iterator iter;
487         for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter)
488         {
489             if ((*iter)->mCurrentFont == NULL)
490             {
491                 (*iter)->fontChanged();
492             }
493         }
494     }
495 
setFont(Font * font)496     void Widget::setFont(Font* font)
497     {
498         mCurrentFont = font;
499         fontChanged();
500     }
501 
widgetExists(const Widget * widget)502     bool Widget::widgetExists(const Widget* widget)
503     {
504         bool result = false;
505 
506         std::list<Widget*>::iterator iter;
507         for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter)
508         {
509             if (*iter == widget)
510             {
511                 return true;
512             }
513         }
514 
515         return result;
516     }
517 
isTabInEnabled() const518     bool Widget::isTabInEnabled() const
519     {
520         return mTabIn;
521     }
522 
setTabInEnabled(bool enabled)523     void Widget::setTabInEnabled(bool enabled)
524     {
525         mTabIn = enabled;
526     }
527 
isTabOutEnabled() const528     bool Widget::isTabOutEnabled() const
529     {
530         return mTabOut;
531     }
532 
setTabOutEnabled(bool enabled)533     void Widget::setTabOutEnabled(bool enabled)
534     {
535         mTabOut = enabled;
536     }
537 
setSize(int width,int height)538     void Widget::setSize(int width, int height)
539     {
540         Rectangle newDimension = mDimension;
541         newDimension.width = width;
542         newDimension.height = height;
543 
544         setDimension(newDimension);
545     }
546 
setEnabled(bool enabled)547     void Widget::setEnabled(bool enabled)
548     {
549         mEnabled = enabled;
550     }
551 
isEnabled() const552     bool Widget::isEnabled() const
553     {
554         return mEnabled && isVisible();
555     }
556 
requestModalFocus()557     void Widget::requestModalFocus()
558     {
559         if (mFocusHandler == NULL)
560         {
561             throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
562         }
563 
564         mFocusHandler->requestModalFocus(this);
565     }
566 
requestModalMouseInputFocus()567     void Widget::requestModalMouseInputFocus()
568     {
569         if (mFocusHandler == NULL)
570         {
571             throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
572         }
573 
574         mFocusHandler->requestModalMouseInputFocus(this);
575     }
576 
releaseModalFocus()577     void Widget::releaseModalFocus()
578     {
579         if (mFocusHandler == NULL)
580         {
581             return;
582         }
583 
584         mFocusHandler->releaseModalFocus(this);
585     }
586 
releaseModalMouseInputFocus()587     void Widget::releaseModalMouseInputFocus()
588     {
589         if (mFocusHandler == NULL)
590         {
591             return;
592         }
593 
594         mFocusHandler->releaseModalMouseInputFocus(this);
595     }
596 
isModalFocused() const597     bool Widget::isModalFocused() const
598     {
599         if (mFocusHandler == NULL)
600         {
601             throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
602         }
603 
604         if (getParent() != NULL)
605         {
606             return (mFocusHandler->getModalFocused() == this)
607                 || getParent()->isModalFocused();
608         }
609 
610         return mFocusHandler->getModalFocused() == this;
611     }
612 
isModalMouseInputFocused() const613     bool Widget::isModalMouseInputFocused() const
614     {
615         if (mFocusHandler == NULL)
616         {
617             throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?).");
618         }
619 
620         if (getParent() != NULL)
621         {
622             return (mFocusHandler->getModalMouseInputFocused() == this)
623                 || getParent()->isModalMouseInputFocused();
624         }
625 
626         return mFocusHandler->getModalMouseInputFocused() == this;
627     }
628 
getWidgetAt(int x,int y)629     Widget *Widget::getWidgetAt(int x, int y)
630     {
631         return NULL;
632     }
633 
_getMouseListeners()634     const std::list<MouseListener*>& Widget::_getMouseListeners()
635     {
636         return mMouseListeners;
637     }
638 
_getKeyListeners()639     const std::list<KeyListener*>& Widget::_getKeyListeners()
640     {
641         return mKeyListeners;
642     }
643 
_getFocusListeners()644     const std::list<FocusListener*>& Widget::_getFocusListeners()
645     {
646         return mFocusListeners;
647     }
648 
getChildrenArea()649     Rectangle Widget::getChildrenArea()
650     {
651         return Rectangle(0, 0, 0, 0);
652     }
653 
_getInternalFocusHandler()654     FocusHandler* Widget::_getInternalFocusHandler()
655     {
656         return mInternalFocusHandler;
657     }
658 
setInternalFocusHandler(FocusHandler * focusHandler)659     void Widget::setInternalFocusHandler(FocusHandler* focusHandler)
660     {
661         mInternalFocusHandler = focusHandler;
662     }
663 
setId(const std::string & id)664     void Widget::setId(const std::string& id)
665     {
666         mId = id;
667     }
668 
getId()669     const std::string& Widget::getId()
670     {
671         return mId;
672     }
673 
distributeResizedEvent()674     void Widget::distributeResizedEvent()
675     {
676         WidgetListenerIterator iter;
677 
678         for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter)
679         {
680             Event event(this);
681             (*iter)->widgetResized(event);
682         }
683     }
684 
distributeMovedEvent()685     void Widget::distributeMovedEvent()
686     {
687         WidgetListenerIterator iter;
688 
689         for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter)
690         {
691             Event event(this);
692             (*iter)->widgetMoved(event);
693         }
694     }
695 
distributeHiddenEvent()696     void Widget::distributeHiddenEvent()
697     {
698         WidgetListenerIterator iter;
699 
700         for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter)
701         {
702             Event event(this);
703             (*iter)->widgetHidden(event);
704         }
705     }
706 
distributeActionEvent()707     void Widget::distributeActionEvent()
708     {
709         ActionListenerIterator iter;
710         for (iter = mActionListeners.begin(); iter != mActionListeners.end(); ++iter)
711         {
712             ActionEvent actionEvent(this, mActionEventId);
713             (*iter)->action(actionEvent);
714         }
715     }
716 
distributeShownEvent()717     void Widget::distributeShownEvent()
718     {
719         WidgetListenerIterator iter;
720 
721         for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter)
722         {
723             Event event(this);
724             (*iter)->widgetShown(event);
725         }
726     }
727 
showPart(Rectangle rectangle)728     void Widget::showPart(Rectangle rectangle)
729     {
730         if (mParent != NULL)
731         {
732             mParent->showWidgetPart(this, rectangle);
733         }
734     }
735 }
736