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/widgets/window.h"
60 #include "guichan/exception.h"
61 #include "guichan/mouseinput.h"
62 
63 namespace gcn
64 {
Window()65     Window::Window()
66     {
67         mContent = nullptr;
68         mMouseDrag = false;
69         setBorderSize(1);
70         setPadding(2);
71         setTitleBarHeight(16);
72         setAlignment(Graphics::CENTER);
73         addMouseListener(this);
74         setMovable(true);
75         setOpaque(true);
76     }
77 
Window(const std::string & caption)78     Window::Window(const std::string& caption)
79     {
80         mContent = nullptr;
81         mMouseDrag = false;
82         setCaption(caption);
83         setBorderSize(1);
84         setPadding(2);
85         setTitleBarHeight(16);
86         setAlignment(Graphics::CENTER);
87         addMouseListener(this);
88         setMovable(true);
89         setOpaque(true);
90     }
91 
Window(Widget * content,const std::string & caption)92     Window::Window(Widget* content, const std::string& caption)
93     {
94         mContent = nullptr;
95         mMouseDrag = false;
96         setContent(content);
97         setCaption(caption);
98         setBorderSize(1);
99         setPadding(2);
100         setTitleBarHeight(16);
101         setAlignment(Graphics::CENTER);
102         addMouseListener(this);
103         setMovable(true);
104         setOpaque(true);
105     }
106 
~Window()107     Window::~Window()
108     {
109         setContent(nullptr);
110     }
111 
setPadding(unsigned int padding)112     void Window::setPadding(unsigned int padding)
113     {
114         mPadding = padding;
115         repositionContent();
116     }
117 
getPadding() const118     unsigned int Window::getPadding() const
119     {
120         return mPadding;
121     }
122 
setTitleBarHeight(unsigned int height)123     void Window::setTitleBarHeight(unsigned int height)
124     {
125         mTitleBarHeight = height;
126         repositionContent();
127     }
128 
getTitleBarHeight()129     unsigned int Window::getTitleBarHeight()
130     {
131         return mTitleBarHeight;
132     }
133 
_announceDeath(Widget *)134     void Window:: _announceDeath(Widget *)
135     {
136         mContent = nullptr;
137     }
138 
setContent(Widget * widget)139     void Window::setContent(Widget* widget)
140     {
141         if (getContent() != nullptr)
142         {
143             getContent()->_setParent(nullptr);
144             getContent()->_setFocusHandler(nullptr);
145         }
146 
147         if (widget != nullptr)
148         {
149             widget->_setParent(this);
150             widget->_setFocusHandler(_getFocusHandler());
151         }
152 
153         mContent = widget;
154         repositionContent();
155     }
156 
getContent() const157     Widget* Window::getContent() const
158     {
159         return mContent;
160     }
161 
setCaption(const std::string & caption)162     void Window::setCaption(const std::string& caption)
163     {
164         mCaption = caption;
165         setDirty(true);
166     }
167 
getCaption() const168     const std::string& Window::getCaption() const
169     {
170         return mCaption;
171     }
172 
setAlignment(unsigned int alignment)173     void Window::setAlignment(unsigned int alignment)
174     {
175         mAlignment = alignment;
176     }
177 
getAlignment() const178     unsigned int Window::getAlignment() const
179     {
180         return mAlignment;
181     }
182 
draw(Graphics * graphics)183     void Window::draw(Graphics* graphics)
184     {
185         Color faceColor = getBaseColor();
186         Color highlightColor, shadowColor;
187         int alpha = getBaseColor().a;
188 
189         highlightColor = faceColor + 0x303030;
190         highlightColor.a = alpha;
191         shadowColor = faceColor - 0x303030;
192         shadowColor.a = alpha;
193 
194         Rectangle d = getContentDimension();
195 
196         // Fill the background around the content
197         graphics->setColor(faceColor);
198         // Fill top
199         graphics->fillRectangle(Rectangle(0,0,getWidth(),d.y - 1));
200         // Fill left
201         graphics->fillRectangle(Rectangle(0,d.y - 1, d.x - 1, getHeight() - d.y + 1));
202         // Fill right
203         graphics->fillRectangle(Rectangle(d.x + d.width + 1,
204                                           d.y - 1,
205                                           getWidth() - d.x - d.width - 1,
206                                           getHeight() - d.y + 1));
207         // Fill bottom
208         graphics->fillRectangle(Rectangle(d.x - 1,
209                                           d.y + d.height + 1,
210                                           d.width + 2,
211                                           getHeight() - d.height - d.y - 1));
212 
213         if (isOpaque())
214         {
215             graphics->fillRectangle(d);
216         }
217 
218         // Construct a rectangle one pixel bigger than the content
219         d.x -= 1;
220         d.y -= 1;
221         d.width += 2;
222         d.height += 2;
223 
224         // Draw a border around the content
225         graphics->setColor(shadowColor);
226         // Top line
227         graphics->drawLine(d.x,
228                            d.y,
229                            d.x + d.width - 2,
230                            d.y);
231 
232         // Left line
233         graphics->drawLine(d.x,
234                            d.y + 1,
235                            d.x,
236                            d.y + d.height - 1);
237 
238         graphics->setColor(highlightColor);
239         // Right line
240         graphics->drawLine(d.x + d.width - 1,
241                            d.y,
242                            d.x + d.width - 1,
243                            d.y + d.height - 2);
244         // Bottom line
245         graphics->drawLine(d.x + 1,
246                            d.y + d.height - 1,
247                            d.x + d.width - 1,
248                            d.y + d.height - 1);
249 
250         drawContent(graphics);
251 
252         int textX = 0;
253         int textY;
254         textY = ((int)getTitleBarHeight() - getFont()->getHeight()) / 2;
255         switch (getAlignment())
256         {
257           case Graphics::LEFT:
258               textX = 4;
259               break;
260           case Graphics::CENTER:
261               textX = getWidth() / 2;
262               break;
263           case Graphics::RIGHT:
264               textX = getWidth() - 4;
265               break;
266           default:
267               //throw GCN_EXCEPTION("Unknown alignment.");
268               assert(!"Unknown alignment.");
269         }
270 
271         graphics->setColor(getForegroundColor());
272         graphics->setFont(getFont());
273         graphics->drawText(getCaption(), textX, textY, getAlignment());
274     }
275 
drawBorder(Graphics * graphics)276     void Window::drawBorder(Graphics* graphics)
277     {
278         Color faceColor = getBaseColor();
279         Color highlightColor, shadowColor;
280         int alpha = getBaseColor().a;
281         int width = getWidth() + getBorderSize() * 2 - 1;
282         int height = getHeight() + getBorderSize() * 2 - 1;
283         highlightColor = faceColor + 0x303030;
284         highlightColor.a = alpha;
285         shadowColor = faceColor - 0x303030;
286         shadowColor.a = alpha;
287 
288         unsigned int i;
289         for (i = 0; i < getBorderSize(); ++i)
290         {
291             graphics->setColor(highlightColor);
292             graphics->drawLine(i,i, width - i, i);
293             graphics->drawLine(i,i + 1, i, height - i - 1);
294             graphics->setColor(shadowColor);
295             graphics->drawLine(width - i,i + 1, width - i, height - i);
296             graphics->drawLine(i,height - i, width - i - 1, height - i);
297         }
298     }
299 
drawContent(Graphics * graphics)300     void Window::drawContent(Graphics* graphics)
301     {
302         if (getContent() != nullptr)
303         {
304             graphics->pushClipArea(getContentDimension());
305             graphics->pushClipArea(Rectangle(0, 0, getContent()->getWidth(),
306                                              getContent()->getHeight()));
307             getContent()->draw(graphics);
308             graphics->popClipArea();
309             graphics->popClipArea();
310         }
311     }
312 
mousePress(int x,int y,int button)313     void Window::mousePress(int x, int y, int button)
314     {
315         if (getParent() != nullptr)
316         {
317             getParent()->moveToTop(this);
318         }
319 
320         if (isMovable() && hasMouse()
321             && y < (int)(getTitleBarHeight() + getPadding()) && button == 1)
322         {
323             mMouseDrag = true;
324             mMouseXOffset = x;
325             mMouseYOffset = y;
326         }
327     }
328 
mouseRelease(int,int,int button)329     void Window::mouseRelease(int, int, int button)
330     {
331         if (button == 1)
332         {
333             mMouseDrag = false;
334         }
335     }
336 
mouseMotion(int x,int y)337     void Window::mouseMotion(int x, int y)
338     {
339         if (mMouseDrag && isMovable())
340         {
341             setPosition(x - mMouseXOffset + getX(),
342                         y - mMouseYOffset + getY());
343 			setDirty(true);
344         }
345     }
346 
moveToTop(Widget * widget)347     void Window::moveToTop(Widget* widget)
348     {
349         if (widget != getContent())
350         {
351             //throw GCN_EXCEPTION("Widget is not content of window.");
352             assert(!"Widget is not content of window.");
353         }
354     }
355 
moveToBottom(Widget * widget)356     void Window::moveToBottom(Widget* widget)
357     {
358         if (widget != getContent())
359         {
360             //throw GCN_EXCEPTION("Widget is not content of window");
361             assert(!"Widget is not content of window.");
362         }
363     }
364 
getDrawSize(int & width,int & height,Widget * widget)365     void Window::getDrawSize(int& width, int& height, Widget* widget)
366     {
367         if (widget != getContent())
368         {
369             //throw GCN_EXCEPTION("Widget is not content of window");
370             assert(!"Widget is not content of window.");
371         }
372 
373         Rectangle d = getContentDimension();
374         width = d.width;
375         height = d.height;
376     }
377 
repositionContent()378     void Window::repositionContent()
379     {
380         if (getContent() == nullptr)
381         {
382             return;
383         }
384 
385         Rectangle d = getContentDimension();
386         mContent->setPosition(d.x, d.y);
387     }
388 
getContentDimension()389     Rectangle Window::getContentDimension()
390     {
391         return Rectangle(getPadding(),
392                          getTitleBarHeight(),
393                          getWidth() - getPadding() * 2,
394                          getHeight() - getPadding() - getTitleBarHeight());
395     }
396 
setMovable(bool movable)397     void Window::setMovable(bool movable)
398     {
399         mMovable = movable;
400     }
401 
isMovable() const402     bool Window::isMovable() const
403     {
404         return mMovable;
405     }
406 
resizeToContent()407     void Window::resizeToContent()
408     {
409         if (getContent() != nullptr)
410         {
411             setSize(getContent()->getWidth() + 2*getPadding(),
412                     getContent()->getHeight() + getPadding()
413                     + getTitleBarHeight());
414         }
415     }
416 
_mouseInputMessage(const MouseInput & mouseInput)417     void Window::_mouseInputMessage(const MouseInput &mouseInput)
418     {
419         BasicContainer::_mouseInputMessage(mouseInput);
420 
421         if (getContent() != nullptr)
422         {
423             if (getContentDimension().isPointInRect(mouseInput.x, mouseInput.y) &&
424                 getContent()->getDimension().isPointInRect(mouseInput.x, mouseInput.y))
425             {
426                 if (!getContent()->hasMouse())
427                 {
428                     getContent()->_mouseInMessage();
429                 }
430 
431                 MouseInput mi = mouseInput;
432                 mi.x -= getContent()->getX();
433                 mi.y -= getContent()->getY();
434                 getContent()->_mouseInputMessage(mi);
435             }
436             else if (getContent()->hasMouse())
437             {
438                 getContent()->_mouseOutMessage();
439             }
440         }
441     }
442 
_mouseOutMessage()443     void Window::_mouseOutMessage()
444     {
445         BasicContainer::_mouseOutMessage();
446 
447         if (getContent() != nullptr && getContent()->hasMouse())
448         {
449             getContent()->_mouseOutMessage();
450         }
451     }
452 
_setFocusHandler(FocusHandler * focusHandler)453     void Window::_setFocusHandler(FocusHandler *focusHandler)
454     {
455         if (getContent() != nullptr)
456         {
457             getContent()->_setFocusHandler(focusHandler);
458         }
459 
460         BasicContainer::_setFocusHandler(focusHandler);
461     }
462 
setOpaque(bool opaque)463     void Window::setOpaque(bool opaque)
464     {
465         mOpaque = opaque;
466     }
467 
isOpaque()468     bool Window::isOpaque()
469     {
470         return mOpaque;
471     }
472 
logic()473     void Window::logic()
474     {
475         if (getContent() != nullptr)
476         {
477             getContent()->logic();
478         }
479     }
480 
setDirty(bool dirty)481 	void Window::setDirty(bool dirty)
482 	{
483 		if (mContent != nullptr)
484 		{
485 			mContent->setDirty(dirty);
486 		}
487 		mDirty = dirty;
488 	}
489 
getDirty() const490 	bool Window::getDirty() const
491 	{
492 		if (mDirty == true)
493 		{
494 			return true;
495 		}
496 
497 		if (mContent != nullptr && mContent->getDirty())
498 		{
499 			return true;
500 		}
501 
502 		return false;
503 	}
504 }
505