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         Color faceColor = getBaseColor();
129         Color highlightColor, shadowColor;
130         int alpha = getBaseColor().a;
131         int width = getWidth() + getFrameSize() * 2 - 1;
132         int height = getHeight() + getFrameSize() * 2 - 1;
133         highlightColor = faceColor + 0x303030;
134         highlightColor.a = alpha;
135         shadowColor = faceColor - 0x303030;
136         shadowColor.a = alpha;
137 
138         Rectangle d = getChildrenArea();
139 
140         // Fill the background around the content
141         graphics->setColor(faceColor);
142         // Fill top
143         graphics->fillRectangle(Rectangle(0,0,getWidth(),d.y - 1));
144         // Fill left
145         graphics->fillRectangle(Rectangle(0,d.y - 1, d.x - 1, getHeight() - d.y + 1));
146         // Fill right
147         graphics->fillRectangle(Rectangle(d.x + d.width + 1,
148                                           d.y - 1,
149                                           getWidth() - d.x - d.width - 1,
150                                           getHeight() - d.y + 1));
151         // Fill bottom
152         graphics->fillRectangle(Rectangle(d.x - 1,
153                                           d.y + d.height + 1,
154                                           d.width + 2,
155                                           getHeight() - d.height - d.y - 1));
156 
157         if (isOpaque())
158         {
159             graphics->fillRectangle(d);
160         }
161 
162         // Construct a rectangle one pixel bigger than the content
163         d.x -= 1;
164         d.y -= 1;
165         d.width += 2;
166         d.height += 2;
167 
168         // Draw a border around the content
169         graphics->setColor(shadowColor);
170         // Top line
171         graphics->drawLine(d.x,
172                            d.y,
173                            d.x + d.width - 2,
174                            d.y);
175 
176         // Left line
177         graphics->drawLine(d.x,
178                            d.y + 1,
179                            d.x,
180                            d.y + d.height - 1);
181 
182         graphics->setColor(highlightColor);
183         // Right line
184         graphics->drawLine(d.x + d.width - 1,
185                            d.y,
186                            d.x + d.width - 1,
187                            d.y + d.height - 2);
188         // Bottom line
189         graphics->drawLine(d.x + 1,
190                            d.y + d.height - 1,
191                            d.x + d.width - 1,
192                            d.y + d.height - 1);
193 
194         drawChildren(graphics);
195 
196         int textX;
197         int textY;
198 
199         textY = ((int)getTitleBarHeight() - getFont()->getHeight()) / 2;
200 
201         switch (getAlignment())
202         {
203           case Graphics::LEFT:
204               textX = 4;
205               break;
206           case Graphics::CENTER:
207               textX = getWidth() / 2;
208               break;
209           case Graphics::RIGHT:
210               textX = getWidth() - 4;
211               break;
212           default:
213               throw GCN_EXCEPTION("Unknown alignment.");
214         }
215 
216         graphics->setColor(getForegroundColor());
217         graphics->setFont(getFont());
218         graphics->pushClipArea(Rectangle(0, 0, getWidth(), getTitleBarHeight() - 1));
219         graphics->drawText(getCaption(), textX, textY, getAlignment());
220         graphics->popClipArea();
221     }
222 
mousePressed(MouseEvent & mouseEvent)223     void Window::mousePressed(MouseEvent& mouseEvent)
224     {
225         if (mouseEvent.getSource() != this)
226         {
227             return;
228         }
229 
230         if (getParent() != NULL)
231         {
232             getParent()->moveToTop(this);
233         }
234 
235         mDragOffsetX = mouseEvent.getX();
236         mDragOffsetY = mouseEvent.getY();
237 
238         mMoved = mouseEvent.getY() <= (int)mTitleBarHeight;
239     }
240 
mouseReleased(MouseEvent & mouseEvent)241     void Window::mouseReleased(MouseEvent& mouseEvent)
242     {
243         mMoved = false;
244     }
245 
mouseDragged(MouseEvent & mouseEvent)246     void Window::mouseDragged(MouseEvent& mouseEvent)
247     {
248         if (mouseEvent.isConsumed() || mouseEvent.getSource() != this)
249         {
250             return;
251         }
252 
253         if (isMovable() && mMoved)
254         {
255             setPosition(mouseEvent.getX() - mDragOffsetX + getX(),
256                         mouseEvent.getY() - mDragOffsetY + getY());
257         }
258 
259         mouseEvent.consume();
260     }
261 
getChildrenArea()262     Rectangle Window::getChildrenArea()
263     {
264         return Rectangle(getPadding(),
265                          getTitleBarHeight(),
266                          getWidth() - getPadding() * 2,
267                          getHeight() - getPadding() - getTitleBarHeight());
268     }
269 
setMovable(bool movable)270     void Window::setMovable(bool movable)
271     {
272         mMovable = movable;
273     }
274 
isMovable() const275     bool Window::isMovable() const
276     {
277         return mMovable;
278     }
279 
setOpaque(bool opaque)280     void Window::setOpaque(bool opaque)
281     {
282         mOpaque = opaque;
283     }
284 
isOpaque()285     bool Window::isOpaque()
286     {
287         return mOpaque;
288     }
289 
resizeToContent()290     void Window::resizeToContent()
291     {
292         WidgetListIterator it;
293 
294         int w = 0, h = 0;
295         for (it = mWidgets.begin(); it != mWidgets.end(); it++)
296         {
297             if ((*it)->getX() + (*it)->getWidth() > w)
298             {
299                 w = (*it)->getX() + (*it)->getWidth();
300             }
301 
302             if ((*it)->getY() + (*it)->getHeight() > h)
303             {
304                 h = (*it)->getY() + (*it)->getHeight();
305             }
306         }
307 
308         setSize(w + 2* getPadding(), h + getPadding() + getTitleBarHeight());
309     }
310 }
311