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/widgets/window.hpp"
49 
50 #include "guichan/exception.hpp"
51 #include "guichan/font.hpp"
52 #include "guichan/graphics.hpp"
53 #include "guichan/mouseinput.hpp"
54 
55 namespace gcn
56 {
Window()57     Window::Window()
58             :mMoved(false)
59     {
60         setFrameSize(1);
61         setPadding(2);
62         setTitleBarHeight(16);
63         setAlignment(Graphics::CENTER);
64         addMouseListener(this);
65         setMovable(true);
66         setOpaque(true);
67     }
68 
Window(const std::string & caption)69     Window::Window(const std::string& caption)
70             :mMoved(false)
71     {
72         setCaption(caption);
73         setFrameSize(1);
74         setPadding(2);
75         setTitleBarHeight(16);
76         setAlignment(Graphics::CENTER);
77         addMouseListener(this);
78         setMovable(true);
79         setOpaque(true);
80     }
81 
~Window()82     Window::~Window()
83     {
84     }
85 
setPadding(unsigned int padding)86     void Window::setPadding(unsigned int padding)
87     {
88         mPadding = padding;
89     }
90 
getPadding() const91     unsigned int Window::getPadding() const
92     {
93         return mPadding;
94     }
95 
setTitleBarHeight(unsigned int height)96     void Window::setTitleBarHeight(unsigned int height)
97     {
98         mTitleBarHeight = height;
99     }
100 
getTitleBarHeight()101     unsigned int Window::getTitleBarHeight()
102     {
103         return mTitleBarHeight;
104     }
105 
setCaption(const std::string & caption)106     void Window::setCaption(const std::string& caption)
107     {
108         mCaption = caption;
109     }
110 
getCaption() const111     const std::string& Window::getCaption() const
112     {
113         return mCaption;
114     }
115 
setAlignment(Graphics::Alignment alignment)116     void Window::setAlignment(Graphics::Alignment alignment)
117     {
118         mAlignment = alignment;
119     }
120 
getAlignment() const121     Graphics::Alignment Window::getAlignment() const
122     {
123         return mAlignment;
124     }
125 
draw(Graphics * graphics)126     void Window::draw(Graphics* graphics)
127     {
128         const Color &faceColor = getBaseColor();
129         Color highlightColor, shadowColor;
130         const int alpha = getBaseColor().a;
131         highlightColor = faceColor + 0x303030;
132         highlightColor.a = alpha;
133         shadowColor = faceColor - 0x303030;
134         shadowColor.a = alpha;
135 
136         Rectangle d = getChildrenArea();
137 
138         // Fill the background around the content
139         graphics->setColor(faceColor);
140         // Fill top
141         graphics->fillRectangle(Rectangle(0,0,getWidth(),d.y - 1));
142         // Fill left
143         graphics->fillRectangle(Rectangle(0,d.y - 1, d.x - 1, getHeight() - d.y + 1));
144         // Fill right
145         graphics->fillRectangle(Rectangle(d.x + d.width + 1,
146                                           d.y - 1,
147                                           getWidth() - d.x - d.width - 1,
148                                           getHeight() - d.y + 1));
149         // Fill bottom
150         graphics->fillRectangle(Rectangle(d.x - 1,
151                                           d.y + d.height + 1,
152                                           d.width + 2,
153                                           getHeight() - d.height - d.y - 1));
154 
155         if (isOpaque())
156         {
157             graphics->fillRectangle(d);
158         }
159 
160         // Construct a rectangle one pixel bigger than the content
161         d.x -= 1;
162         d.y -= 1;
163         d.width += 2;
164         d.height += 2;
165 
166         // Draw a border around the content
167         graphics->setColor(shadowColor);
168         // Top line
169         graphics->drawLine(d.x,
170                            d.y,
171                            d.x + d.width - 2,
172                            d.y);
173 
174         // Left line
175         graphics->drawLine(d.x,
176                            d.y + 1,
177                            d.x,
178                            d.y + d.height - 1);
179 
180         graphics->setColor(highlightColor);
181         // Right line
182         graphics->drawLine(d.x + d.width - 1,
183                            d.y,
184                            d.x + d.width - 1,
185                            d.y + d.height - 2);
186         // Bottom line
187         graphics->drawLine(d.x + 1,
188                            d.y + d.height - 1,
189                            d.x + d.width - 1,
190                            d.y + d.height - 1);
191 
192         drawChildren(graphics);
193 
194         int textX;
195         int textY;
196 
197         textY = ((int)getTitleBarHeight() - getFont()->getHeight()) / 2;
198 
199         switch (getAlignment())
200         {
201           case Graphics::LEFT:
202               textX = 4;
203               break;
204           case Graphics::CENTER:
205               textX = getWidth() / 2;
206               break;
207           case Graphics::RIGHT:
208               textX = getWidth() - 4;
209               break;
210           default:
211               throw GCN_EXCEPTION("Unknown alignment.");
212         }
213 
214         graphics->setColor(getForegroundColor());
215         graphics->setFont(getFont());
216         graphics->pushClipArea(Rectangle(0, 0, getWidth(), getTitleBarHeight() - 1));
217         graphics->drawText(getCaption(), textX, textY, getAlignment());
218         graphics->popClipArea();
219     }
220 
mousePressed(MouseEvent & mouseEvent)221     void Window::mousePressed(MouseEvent& mouseEvent)
222     {
223         if (mouseEvent.getSource() != this)
224         {
225             return;
226         }
227 
228         if (getParent() != NULL)
229         {
230             getParent()->moveToTop(this);
231         }
232 
233         mDragOffsetX = mouseEvent.getX();
234         mDragOffsetY = mouseEvent.getY();
235 
236         mMoved = mouseEvent.getY() <= (int)mTitleBarHeight;
237     }
238 
mouseReleased(MouseEvent & mouseEvent)239     void Window::mouseReleased(MouseEvent& mouseEvent)
240     {
241         mMoved = false;
242     }
243 
mouseDragged(MouseEvent & mouseEvent)244     void Window::mouseDragged(MouseEvent& mouseEvent)
245     {
246         if (mouseEvent.isConsumed() || mouseEvent.getSource() != this)
247         {
248             return;
249         }
250 
251         if (isMovable() && mMoved)
252         {
253             setPosition(mouseEvent.getX() - mDragOffsetX + getX(),
254                         mouseEvent.getY() - mDragOffsetY + getY());
255         }
256 
257         mouseEvent.consume();
258     }
259 
getChildrenArea()260     Rectangle Window::getChildrenArea()
261     {
262         return Rectangle(getPadding(),
263                          getTitleBarHeight(),
264                          getWidth() - getPadding() * 2,
265                          getHeight() - getPadding() - getTitleBarHeight());
266     }
267 
setMovable(bool movable)268     void Window::setMovable(bool movable)
269     {
270         mMovable = movable;
271     }
272 
isMovable() const273     bool Window::isMovable() const
274     {
275         return mMovable;
276     }
277 
setOpaque(bool opaque)278     void Window::setOpaque(bool opaque)
279     {
280         mOpaque = opaque;
281     }
282 
isOpaque()283     bool Window::isOpaque()
284     {
285         return mOpaque;
286     }
287 
resizeToContent()288     void Window::resizeToContent()
289     {
290         WidgetListIterator it;
291 
292         int w = 0, h = 0;
293         for (it = mWidgets.begin(); it != mWidgets.end(); it++)
294         {
295             if ((*it)->getX() + (*it)->getWidth() > w)
296             {
297                 w = (*it)->getX() + (*it)->getWidth();
298             }
299 
300             if ((*it)->getY() + (*it)->getHeight() > h)
301             {
302                 h = (*it)->getY() + (*it)->getHeight();
303             }
304         }
305 
306         setSize(w + 2* getPadding(), h + getPadding() + getTitleBarHeight());
307     }
308 }
309