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