1 /*************************************************************************** 2 * Copyright (c) 2017-2019 by the fifechan team * 3 * https://github.com/fifengine/fifechan * 4 * This file is part of fifechan. * 5 * * 6 * fifechan is free software; you can redistribute it and/or * 7 * modify it under the terms of the GNU Lesser General Public * 8 * License as published by the Free Software Foundation; either * 9 * version 2.1 of the License, or (at your option) any later version. * 10 * * 11 * This library is distributed in the hope that it will be useful, * 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 * Lesser General Public License for more details. * 15 * * 16 * You should have received a copy of the GNU Lesser General Public * 17 * License along with this library; if not, write to the * 18 * Free Software Foundation, Inc., * 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 20 ***************************************************************************/ 21 22 /* _______ __ __ __ ______ __ __ _______ __ __ 23 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ 24 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / 25 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / 26 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / 27 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / 28 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ 29 * 30 * Copyright (c) 2004 - 2008 Olof Naess�n and Per Larsson 31 * 32 * 33 * Per Larsson a.k.a finalman 34 * Olof Naess�n a.k.a jansem/yakslem 35 * 36 * Visit: http://guichan.sourceforge.net 37 * 38 * License: (BSD) 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in 46 * the documentation and/or other materials provided with the 47 * distribution. 48 * 3. Neither the name of Guichan nor the names of its contributors may 49 * be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 58 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 59 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 60 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 61 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 62 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65 /* 66 * For comments regarding functions please see the header file. 67 */ 68 69 #include <algorithm> 70 71 #include "fifechan/widgets/window.hpp" 72 73 #include "fifechan/exception.hpp" 74 #include "fifechan/font.hpp" 75 #include "fifechan/graphics.hpp" 76 #include "fifechan/mouseinput.hpp" 77 78 namespace fcn 79 { Window()80 Window::Window() 81 :mMoved(false) 82 { 83 setBorderSize(1); 84 setInnerBorderSize(1); 85 setPadding(2); 86 setTitleBarHeight(16); 87 setAlignment(Graphics::Center); 88 addMouseListener(this); 89 setMovable(true); 90 setOpaque(true); 91 } 92 Window(const std::string & caption)93 Window::Window(const std::string& caption) 94 :mMoved(false) 95 { 96 setCaption(caption); 97 setBorderSize(1); 98 setInnerBorderSize(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 } 110 setTitleBarHeight(unsigned int height)111 void Window::setTitleBarHeight(unsigned int height) 112 { 113 mTitleBarHeight = height; 114 } 115 getTitleBarHeight() const116 unsigned int Window::getTitleBarHeight() const 117 { 118 return mTitleBarHeight; 119 } 120 setInnerBorderSize(unsigned int border)121 void Window::setInnerBorderSize(unsigned int border) { 122 mInnerBorder = border; 123 } 124 getInnerBorderSize() const125 unsigned int Window::getInnerBorderSize() const { 126 return mInnerBorder; 127 } 128 setCaption(const std::string & caption)129 void Window::setCaption(const std::string& caption) 130 { 131 mCaption = caption; 132 } 133 getCaption() const134 const std::string& Window::getCaption() const 135 { 136 return mCaption; 137 } 138 setAlignment(Graphics::Alignment alignment)139 void Window::setAlignment(Graphics::Alignment alignment) 140 { 141 mAlignment = alignment; 142 } 143 getAlignment() const144 Graphics::Alignment Window::getAlignment() const 145 { 146 return mAlignment; 147 } 148 drawInnerBorder(Graphics * graphics)149 void Window::drawInnerBorder(Graphics* graphics) { 150 const Color &faceColor = getBaseColor(); 151 Color highlightColor, shadowColor; 152 const int alpha = getBaseColor().a; 153 highlightColor = faceColor + 0x303030; 154 highlightColor.a = alpha; 155 shadowColor = faceColor - 0x303030; 156 shadowColor.a = alpha; 157 158 int x = getBorderSize() + getPaddingLeft(); 159 int y = getBorderSize() + getPaddingTop() + getTitleBarHeight(); 160 int width = getWidth() - getBorderSize() - getPaddingRight() - 1; 161 int height = getHeight() - getBorderSize() - getPaddingBottom() - 1; 162 163 unsigned int i; 164 for (i = 0; i < getInnerBorderSize(); ++i) { 165 graphics->setColor(shadowColor); 166 graphics->drawLine(x+i, y+i, width-i, y+i); 167 graphics->drawLine(x+i, y+i+1, x+i, height-i-1); 168 graphics->setColor(highlightColor); 169 graphics->drawLine(width-i, y+i+1, width-i, height-i); 170 graphics->drawLine(x+i, height-i, width-i-1, height-i); 171 } 172 } 173 draw(Graphics * graphics)174 void Window::draw(Graphics* graphics) { 175 const Color &faceColor = getBaseColor(); 176 Color highlightColor, shadowColor; 177 const int alpha = getBaseColor().a; 178 highlightColor = faceColor + 0x303030; 179 highlightColor.a = alpha; 180 shadowColor = faceColor - 0x303030; 181 shadowColor.a = alpha; 182 183 if (isOpaque()) { 184 // Fill the background around the content 185 graphics->setColor(faceColor); 186 graphics->fillRectangle(getBorderSize(), getBorderSize(), 187 getWidth() - 2 * getBorderSize(), getHeight() - 2 * getBorderSize()); 188 } 189 if (mBackgroundWidget) { 190 Rectangle rec(getBorderSize(), getBorderSize(), getWidth() - 2 * getBorderSize(), getHeight() - 2 * getBorderSize()); 191 mBackgroundWidget->setDimension(rec); 192 mBackgroundWidget->_draw(graphics); 193 } 194 if (getBorderSize() > 0) { 195 drawBorder(graphics); 196 } 197 198 // draw inner/content border 199 if (getInnerBorderSize() > 0) { 200 drawInnerBorder(graphics); 201 } 202 203 // draw text 204 int textX; 205 int textY = ((int)getTitleBarHeight() - getFont()->getHeight()) / 2; 206 207 switch (getAlignment()) 208 { 209 case Graphics::Left: 210 textX = 0; 211 break; 212 case Graphics::Center: 213 textX = (getWidth() - 2 * getBorderSize() - getPaddingLeft() - getPaddingRight()) / 2; 214 break; 215 case Graphics::Right: 216 textX = getWidth() - getBorderSize() - getPaddingRight(); 217 break; 218 default: 219 throw FCN_EXCEPTION("Unknown alignment."); 220 } 221 // text clip area 222 Rectangle rec(getBorderSize() + getPaddingLeft(), getBorderSize() + getPaddingTop(), 223 getWidth() - 2 * getBorderSize() - getPaddingLeft() - getPaddingRight(), 224 getTitleBarHeight() - 1); 225 226 graphics->setColor(getForegroundColor()); 227 graphics->setFont(getFont()); 228 graphics->pushClipArea(rec); 229 graphics->drawText(getCaption(), textX, textY, getAlignment()); 230 graphics->popClipArea(); 231 } 232 mousePressed(MouseEvent & mouseEvent)233 void Window::mousePressed(MouseEvent& mouseEvent) 234 { 235 if (mouseEvent.getSource() != this) 236 { 237 return; 238 } 239 240 if (getParent() != NULL) 241 { 242 getParent()->moveToTop(this); 243 } 244 245 mDragOffsetX = mouseEvent.getX(); 246 mDragOffsetY = mouseEvent.getY(); 247 248 int height = getBorderSize() + getPaddingTop() + getTitleBarHeight(); 249 mMoved = mouseEvent.getY() <= height; 250 } 251 mouseReleased(MouseEvent & mouseEvent)252 void Window::mouseReleased(MouseEvent& mouseEvent) 253 { 254 mMoved = false; 255 } 256 mouseDragged(MouseEvent & mouseEvent)257 void Window::mouseDragged(MouseEvent& mouseEvent) 258 { 259 if (mouseEvent.isConsumed() || mouseEvent.getSource() != this) 260 { 261 return; 262 } 263 264 if (isMovable() && mMoved) 265 { 266 setPosition(mouseEvent.getX() - mDragOffsetX + getX(), 267 mouseEvent.getY() - mDragOffsetY + getY()); 268 } 269 270 mouseEvent.consume(); 271 } 272 adjustSize()273 void Window::adjustSize() { 274 resizeToChildren(); 275 int w = std::max(getFont()->getWidth(mCaption), getWidth()) + 2 * getBorderSize() + getPaddingLeft() + getPaddingRight() + 2 * getInnerBorderSize(); 276 int h = getHeight() + 2 * getBorderSize() + getPaddingTop() + getPaddingBottom() + 2 * getInnerBorderSize() + getTitleBarHeight(); 277 setSize(w, h); 278 } 279 getChildrenArea()280 Rectangle Window::getChildrenArea() 281 { 282 Rectangle rec; 283 rec.x = getBorderSize() + getPaddingLeft() + getInnerBorderSize(); 284 rec.y = getBorderSize() + getPaddingTop() + getInnerBorderSize() + getTitleBarHeight(); 285 rec.width = getWidth() - 2 * getBorderSize() - getPaddingLeft() - getPaddingRight() - 2*getInnerBorderSize(); 286 rec.height = getHeight() - 2 * getBorderSize() - getPaddingTop() - getPaddingBottom() - 2*getInnerBorderSize() - getTitleBarHeight(); 287 return rec; 288 } 289 setMovable(bool movable)290 void Window::setMovable(bool movable) 291 { 292 mMovable = movable; 293 } 294 isMovable() const295 bool Window::isMovable() const 296 { 297 return mMovable; 298 } 299 setOpaque(bool opaque)300 void Window::setOpaque(bool opaque) 301 { 302 mOpaque = opaque; 303 } 304 isOpaque() const305 bool Window::isOpaque() const 306 { 307 return mOpaque; 308 } 309 } 310