1 /*
2  *  The ManaPlus Client
3  *  Copyright (C) 2004-2009  The Mana World Development Team
4  *  Copyright (C) 2009-2010  The Mana Developers
5  *  Copyright (C) 2011-2019  The ManaPlus Developers
6  *  Copyright (C) 2019-2021  Andrei Karas
7  *
8  *  This file is part of The ManaPlus Client.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 /*      _______   __   __   __   ______   __   __   _______   __   __
25  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
26  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
27  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
28  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
29  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
30  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
31  *
32  * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
33  *
34  *
35  * Per Larsson a.k.a finalman
36  * Olof Naessén a.k.a jansem/yakslem
37  *
38  * Visit: http://guichan.sourceforge.net
39  *
40  * License: (BSD)
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in
48  *    the documentation and/or other materials provided with the
49  *    distribution.
50  * 3. Neither the name of Guichan nor the names of its contributors may
51  *    be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
60  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
61  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
62  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
63  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65  */
66 
67 #include "gui/widgets/window.h"
68 
69 #include "client.h"
70 #include "configuration.h"
71 #ifndef DYECMD
72 #include "dragdrop.h"
73 #else  // DYECMD
74 #include "resources/image/image.h"
75 #endif  // DYECMD
76 #include "soundmanager.h"
77 
78 #include "const/sound.h"
79 
80 #include "gui/focushandler.h"
81 #include "gui/gui.h"
82 #include "gui/popupmanager.h"
83 #include "gui/skin.h"
84 #include "gui/viewport.h"
85 
86 #include "gui/fonts/font.h"
87 
88 #include "gui/popups/popupmenu.h"
89 
90 #include "gui/windows/setupwindow.h"
91 
92 #include "gui/widgets/containerplacer.h"
93 #include "gui/widgets/layout.h"
94 
95 #include "render/renderers.h"
96 
97 #include "render/vertexes/imagecollection.h"
98 
99 #include "utils/checkutils.h"
100 #include "utils/delete2.h"
101 
102 #include "debug.h"
103 
104 const int resizeMask = 8 + 4 + 2 + 1;
105 
106 int Window::windowInstances = 0;
107 int Window::mouseResize = 0;
108 
Window(const std::string & caption,const Modal modal,Window * const parent,std::string skin)109 Window::Window(const std::string &caption,
110                const Modal modal,
111                Window *const parent,
112                std::string skin) :
113     BasicContainer2(nullptr),
114     MouseListener(),
115     WidgetListener(),
116     mCaption(caption),
117     mAlignment(Graphics::CENTER),
118     mPadding(2),
119     mTitleBarHeight(16),
120     mMovable(Move_true),
121     mDragOffsetX(0),
122     mDragOffsetY(0),
123     mMoved(false),
124     mSkin(nullptr),
125     mDefaultX(0),
126     mDefaultY(0),
127     mDefaultWidth(0),
128     mDefaultHeight(0),
129     mCaptionOffsetX(7),
130     mCaptionOffsetY(5),
131     mShowTitle(true),
132     mLastRedraw(true),
133     mGrip(nullptr),
134     mParentWindow(parent),
135     mLayout(nullptr),
136     mCloseRect(),
137     mStickyRect(),
138     mGripRect(),
139     mTextChunk(),
140     mWindowName("window"),
141     mMinWinWidth(100),
142     mMinWinHeight(40),
143     mMaxWinWidth(mainGraphics->mWidth),
144     mMaxWinHeight(mainGraphics->mHeight),
145     mVertexes(new ImageCollection),
146     mCaptionAlign(Graphics::LEFT),
147     mTitlePadding(4),
148     mGripPadding(2),
149     mResizeHandles(-1),
150     mOldResizeHandles(-1),
151     mClosePadding(0),
152     mStickySpacing(0),
153     mStickyPadding(0),
154     mCaptionFont(getFont()),
155     mModal(modal),
156     mCloseWindowButton(false),
157     mDefaultVisible(false),
158     mSaveVisible(false),
159     mStickyButton(false),
160     mSticky(false),
161     mStickyButtonLock(false),
162     mPlayVisibleSound(false),
163     mInit(false),
164     mTextChanged(true),
165     mAllowClose(false)
166 {
167     logger->log("Window::Window(\"%s\")", caption.c_str());
168 
169     mWindow = this;
170 
171     windowInstances++;
172 
173 //    mFrameSize = 1;
174     addMouseListener(this);
175 
176     setFrameSize(0);
177     setPadding(3);
178     setTitleBarHeight(20);
179 
180     if (skin.empty())
181     {
182         reportAlways("Default skin was used for window: %s",
183             caption.c_str())
184         skin = "window.xml";
185     }
186 
187     int childPalette = 1;
188     // Loads the skin
189     if (theme != nullptr)
190     {
191         mSkin = theme->load(skin,
192             "window.xml",
193             true,
194             Theme::getThemePath());
195         if (mSkin != nullptr)
196         {
197             setPadding(mSkin->getPadding());
198             if (getOptionBool("titlebarBold", false))
199                 mCaptionFont = boldFont;
200             mTitlePadding = mSkin->getTitlePadding();
201             mGripPadding = getOption("resizePadding", 0);
202             mCaptionOffsetX = getOption("captionoffsetx", 0);
203             if (mCaptionOffsetX == 0)
204                 mCaptionOffsetX = 7;
205             mCaptionOffsetY = getOption("captionoffsety", 0);
206             if (mCaptionOffsetY == 0)
207                 mCaptionOffsetY = 5;
208             mCaptionAlign = static_cast<Graphics::Alignment>(
209                 getOption("captionalign", 0));
210             if (mCaptionAlign < Graphics::LEFT
211                 || mCaptionAlign > Graphics::RIGHT)
212             {
213                 mCaptionAlign = Graphics::LEFT;
214             }
215             setTitleBarHeight(CAST_U32(
216                 getOption("titlebarHeight", 0)));
217             if (mTitleBarHeight == 0U)
218                 mTitleBarHeight = mCaptionFont->getHeight() + mPadding;
219 
220             mTitleBarHeight += getOption("titlebarHeightRelative", 0);
221             setPalette(getOption("palette", 0));
222             childPalette = getOption("childPalette", 0);
223             mShowTitle = getOptionBool("showTitle", true);
224             mClosePadding = getOption("closePadding", 0);
225             mStickySpacing = getOption("stickySpacing", 0);
226             mStickyPadding = getOption("stickyPadding", 0);
227         }
228     }
229 
230     // Add this window to the window container
231     if (windowContainer != nullptr)
232         windowContainer->add(this);
233 
234     if (mModal == Modal_true)
235     {
236         gui->setCursorType(Cursor::CURSOR_POINTER);
237         requestModalFocus();
238     }
239 
240     // Windows are invisible by default
241     setVisible(Visible_false, false);
242 
243     addWidgetListener(this);
244     mForegroundColor = getThemeColor(ThemeColorId::WINDOW, 255U);
245     mForegroundColor2 = getThemeColor(ThemeColorId::WINDOW_OUTLINE, 255U);
246     setPalette(childPalette);
247 }
248 
postInit()249 void Window::postInit()
250 {
251     if (mInit)
252     {
253         reportAlways("error: Window created with calling postInit() "
254             "more than once: %s",
255             mWindowName.c_str())
256     }
257     mInit = true;
258 }
259 
~Window()260 Window::~Window()
261 {
262     logger->log("Window::~Window(\"%s\")", getCaption().c_str());
263 
264     if (gui != nullptr)
265         gui->removeDragged(this);
266 
267 #ifndef DYECMD
268     if (setupWindow != nullptr)
269         setupWindow->unregisterWindowForReset(this);
270 #endif  // DYECMD
271 
272     client->windowRemoved(this);
273 
274     saveWindowState();
275 
276     delete2(mLayout)
277 
278     while (!mWidgets.empty())
279         delete mWidgets.front();
280 
281     mWidgets.clear();
282 
283     removeWidgetListener(this);
284     delete2(mVertexes)
285 
286     windowInstances--;
287 
288     if (mSkin != nullptr)
289     {
290         if (theme != nullptr)
291             theme->unload(mSkin);
292         mSkin = nullptr;
293     }
294     if (mGrip != nullptr)
295     {
296         mGrip->decRef();
297         mGrip = nullptr;
298     }
299     if (!mInit)
300     {
301         reportAlways("error: Window created without calling postInit(): %s",
302             mWindowName.c_str())
303     }
304 }
305 
setWindowContainer(WindowContainer * const wc)306 void Window::setWindowContainer(WindowContainer *const wc)
307 {
308     windowContainer = wc;
309 }
310 
draw(Graphics * const graphics)311 void Window::draw(Graphics *const graphics)
312 {
313     if (mSkin == nullptr)
314         return;
315 
316     BLOCK_START("Window::draw")
317     bool update = false;
318 
319     if (mResizeHandles != mOldResizeHandles)
320     {
321         mRedraw = true;
322         mOldResizeHandles = mResizeHandles;
323     }
324     if (mRedraw)
325     {
326         mLastRedraw = true;
327         mRedraw = false;
328         update = true;
329         mVertexes->clear();
330         graphics->calcWindow(mVertexes,
331             0, 0,
332             mDimension.width,
333             mDimension.height,
334             mSkin->getBorder());
335 
336         // Draw Close Button
337         if (mCloseWindowButton)
338         {
339             const Image *const button = mSkin->getCloseImage(
340                 mResizeHandles == CLOSE);
341             if (button != nullptr)
342             {
343                 graphics->calcTileCollection(mVertexes,
344                     button,
345                     mCloseRect.x,
346                     mCloseRect.y);
347             }
348         }
349         // Draw Sticky Button
350         if (mStickyButton)
351         {
352             const Image *const button = mSkin->getStickyImage(mSticky);
353             if (button != nullptr)
354             {
355                 graphics->calcTileCollection(mVertexes,
356                     button,
357                     mStickyRect.x,
358                     mStickyRect.y);
359             }
360         }
361 
362         if (mGrip != nullptr)
363         {
364             graphics->calcTileCollection(mVertexes,
365                 mGrip,
366                 mGripRect.x,
367                 mGripRect.y);
368         }
369         graphics->finalize(mVertexes);
370     }
371     else
372     {
373         mLastRedraw = false;
374     }
375     graphics->drawTileCollection(mVertexes);
376 
377     // Draw title
378     if (mShowTitle)
379     {
380         int x;
381         switch (mCaptionAlign)
382         {
383             case Graphics::LEFT:
384             default:
385                 x = mCaptionOffsetX;
386                 break;
387             case Graphics::CENTER:
388                 x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption) / 2;
389                 break;
390             case Graphics::RIGHT:
391                 x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption);
392                 break;
393         }
394         if (mTextChanged)
395         {
396             mTextChunk.textFont = mCaptionFont;
397             mTextChunk.deleteImage();
398             mTextChunk.text = mCaption;
399             mTextChunk.color = mForegroundColor;
400             mTextChunk.color2 = mForegroundColor2;
401             mCaptionFont->generate(mTextChunk);
402             mTextChanged = false;
403         }
404 
405         const Image *const image = mTextChunk.img;
406         if (image != nullptr)
407             graphics->drawImage(image, x, mCaptionOffsetY);
408     }
409 
410     if (update)
411     {
412         graphics->setRedraw(update);
413         drawChildren(graphics);
414         graphics->setRedraw(false);
415     }
416     else
417     {
418         drawChildren(graphics);
419     }
420     BLOCK_END("Window::draw")
421 }
422 
safeDraw(Graphics * const graphics)423 void Window::safeDraw(Graphics *const graphics)
424 {
425     if (mSkin == nullptr)
426         return;
427 
428     BLOCK_START("Window::safeDraw")
429 
430     graphics->drawImageRect(0, 0,
431         mDimension.width,
432         mDimension.height,
433         mSkin->getBorder());
434 
435     // Draw Close Button
436     if (mCloseWindowButton)
437     {
438         const Image *const button = mSkin->getCloseImage(
439             mResizeHandles == CLOSE);
440         if (button != nullptr)
441             graphics->drawImage(button, mCloseRect.x, mCloseRect.y);
442     }
443     // Draw Sticky Button
444     if (mStickyButton)
445     {
446         const Image *const button = mSkin->getStickyImage(mSticky);
447         if (button != nullptr)
448             graphics->drawImage(button, mStickyRect.x, mStickyRect.y);
449     }
450 
451     if (mGrip != nullptr)
452         graphics->drawImage(mGrip, mGripRect.x, mGripRect.y);
453 
454     // Draw title
455     if (mShowTitle)
456     {
457         int x;
458         switch (mCaptionAlign)
459         {
460             case Graphics::LEFT:
461             default:
462                 x = mCaptionOffsetX;
463                 break;
464             case Graphics::CENTER:
465                 x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption) / 2;
466                 break;
467             case Graphics::RIGHT:
468                 x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption);
469                 break;
470         }
471         if (mTextChanged)
472         {
473             mTextChunk.textFont = mCaptionFont;
474             mTextChunk.deleteImage();
475             mTextChunk.text = mCaption;
476             mTextChunk.color = mForegroundColor;
477             mTextChunk.color2 = mForegroundColor2;
478             mCaptionFont->generate(mTextChunk);
479             mTextChanged = false;
480         }
481 
482         const Image *const image = mTextChunk.img;
483         if (image != nullptr)
484             graphics->drawImage(image, x, mCaptionOffsetY);
485     }
486 
487     safeDrawChildren(graphics);
488 
489     BLOCK_END("Window::safeDraw")
490 }
491 
setContentSize(int width,int height)492 void Window::setContentSize(int width, int height)
493 {
494     width = width + 2 * mPadding;
495     height = height + mPadding + mTitleBarHeight;
496 
497     if (mMinWinWidth > width)
498         width = mMinWinWidth;
499     else if (mMaxWinWidth < width)
500         width = mMaxWinWidth;
501     if (mMinWinHeight > height)
502         height = mMinWinHeight;
503     else if (mMaxWinHeight < height)
504         height = mMaxWinHeight;
505 
506     setSize(width, height);
507 }
508 
setLocationRelativeTo(const Widget * const widget)509 void Window::setLocationRelativeTo(const Widget *const widget)
510 {
511     if (widget == nullptr)
512         return;
513 
514     int wx;
515     int wy;
516     int x;
517     int y;
518 
519     widget->getAbsolutePosition(wx, wy);
520     getAbsolutePosition(x, y);
521 
522     setPosition(mDimension.x + (wx + (widget->getWidth()
523         - mDimension.width) / 2 - x),
524         mDimension.y + (wy + (widget->getHeight()
525         - mDimension.height) / 2 - y));
526 }
527 
setLocationHorisontallyRelativeTo(const Widget * const widget)528 void Window::setLocationHorisontallyRelativeTo(const Widget *const widget)
529 {
530     if (widget == nullptr)
531         return;
532 
533     int wx;
534     int wy;
535     int x;
536     int y;
537 
538     widget->getAbsolutePosition(wx, wy);
539     getAbsolutePosition(x, y);
540 
541     setPosition(mDimension.x + (wx + (widget->getWidth()
542         - mDimension.width) / 2 - x), 0);
543 }
544 
setLocationRelativeTo(const ImagePosition::Type & position,int offsetX,int offsetY)545 void Window::setLocationRelativeTo(const ImagePosition::Type &position,
546                                    int offsetX, int offsetY)
547 {
548     if (position == ImagePosition::UPPER_LEFT)
549     {
550     }
551     else if (position == ImagePosition::UPPER_CENTER)
552     {
553         offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
554     }
555     else if (position == ImagePosition::UPPER_RIGHT)
556     {
557         offsetX += mainGraphics->mWidth - mDimension.width;
558     }
559     else if (position == ImagePosition::LEFT)
560     {
561         offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
562     }
563     else if (position == ImagePosition::CENTER)
564     {
565         offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
566         offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
567     }
568     else if (position == ImagePosition::RIGHT)
569     {
570         offsetX += mainGraphics->mWidth - mDimension.width;
571         offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
572     }
573     else if (position == ImagePosition::LOWER_LEFT)
574     {
575         offsetY += mainGraphics->mHeight - mDimension.height;
576     }
577     else if (position == ImagePosition::LOWER_CENTER)
578     {
579         offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
580         offsetY += mainGraphics->mHeight - mDimension.height;
581     }
582     else if (position == ImagePosition::LOWER_RIGHT)
583     {
584         offsetX += mainGraphics->mWidth - mDimension.width;
585         offsetY += mainGraphics->mHeight - mDimension.height;
586     }
587 
588     setPosition(offsetX, offsetY);
589 }
590 
setMinWidth(const int width)591 void Window::setMinWidth(const int width)
592 {
593     if (mSkin != nullptr)
594     {
595         mMinWinWidth = width > mSkin->getMinWidth()
596             ? width : mSkin->getMinWidth();
597     }
598     else
599     {
600         mMinWinWidth = width;
601     }
602 }
603 
setMinHeight(const int height)604 void Window::setMinHeight(const int height)
605 {
606     if (mSkin != nullptr)
607     {
608         mMinWinHeight = height > mSkin->getMinHeight()
609             ? height : mSkin->getMinHeight();
610     }
611     else
612     {
613         mMinWinHeight = height;
614     }
615 }
616 
setMaxWidth(const int width)617 void Window::setMaxWidth(const int width)
618 {
619     mMaxWinWidth = width;
620 }
621 
setMaxHeight(const int height)622 void Window::setMaxHeight(const int height)
623 {
624     mMaxWinHeight = height;
625 }
626 
setResizable(const bool r)627 void Window::setResizable(const bool r)
628 {
629     if ((mGrip != nullptr) == r)
630         return;
631 
632     if (mGrip != nullptr)
633         mGrip->decRef();
634     if (r)
635     {
636         mGrip = Theme::getImageFromThemeXml("resize.xml", "");
637         if (mGrip != nullptr)
638         {
639             mGripRect.x = mDimension.width - mGrip->getWidth() - mGripPadding;
640             mGripRect.y = mDimension.height - mGrip->getHeight()
641                 - mGripPadding;
642         }
643         else
644         {
645             mGripRect.x = 0;
646             mGripRect.y = 0;
647         }
648     }
649     else
650     {
651         mGrip = nullptr;
652     }
653 }
654 
widgetResized(const Event & event A_UNUSED)655 void Window::widgetResized(const Event &event A_UNUSED)
656 {
657     if (mGrip != nullptr)
658     {
659         mGripRect.x = mDimension.width - mGrip->getWidth() - mGripPadding;
660         mGripRect.y = mDimension.height - mGrip->getHeight() - mGripPadding;
661     }
662 
663     if (mLayout != nullptr)
664     {
665         const Rect area = getChildrenArea();
666         int w = area.width;
667         int h = area.height;
668         mLayout->reflow(w, h);
669     }
670     if (mSkin != nullptr)
671     {
672         const bool showClose = mCloseWindowButton
673             && (mSkin->getCloseImage(false) != nullptr);
674         if (showClose)
675         {
676             const Image *const button = mSkin->getCloseImage(false);
677             if (button != nullptr)
678             {
679                 const int buttonWidth = button->getWidth();
680                 mCloseRect.x = mDimension.width - buttonWidth - mClosePadding;
681                 mCloseRect.y = mClosePadding;
682                 mCloseRect.width = buttonWidth;
683                 mCloseRect.height = button->getHeight();
684             }
685         }
686         if (mStickyButton)
687         {
688             const Image *const button = mSkin->getStickyImage(mSticky);
689             if (button != nullptr)
690             {
691                 const int buttonWidth = button->getWidth();
692                 int x = mDimension.width - buttonWidth
693                     - mStickySpacing - mClosePadding;
694 
695                 if (showClose)
696                     x -= mSkin->getCloseImage(false)->getWidth();
697 
698                 mStickyRect.x = x;
699                 mStickyRect.y = mStickyPadding;
700                 mStickyRect.width = buttonWidth;
701                 mStickyRect.height = button->getHeight();
702             }
703         }
704     }
705     else
706     {
707         mCloseRect.x = 0;
708         mCloseRect.y = 0;
709         mCloseRect.width = 0;
710         mCloseRect.height = 0;
711         mStickyRect.x = 0;
712         mStickyRect.y = 0;
713         mStickyRect.width = 0;
714         mStickyRect.height = 0;
715     }
716 
717     mRedraw = true;
718 }
719 
widgetMoved(const Event & event A_UNUSED)720 void Window::widgetMoved(const Event& event A_UNUSED)
721 {
722     mRedraw = true;
723 }
724 
widgetHidden(const Event & event A_UNUSED)725 void Window::widgetHidden(const Event &event A_UNUSED)
726 {
727     if (isBatchDrawRenders(openGLMode))
728         mVertexes->clear();
729 
730     mTextChunk.deleteImage();
731 
732     mTextChanged = true;
733     mRedraw = true;
734 
735     if (gui != nullptr)
736         gui->setCursorType(Cursor::CURSOR_POINTER);
737 
738     if (mFocusHandler == nullptr)
739         return;
740 
741     for (WidgetListConstIterator it = mWidgets.begin();
742          it != mWidgets.end(); ++ it)
743     {
744         if (mFocusHandler->isFocused(*it))
745             mFocusHandler->focusNone();
746     }
747 }
748 
setCloseButton(const bool flag)749 void Window::setCloseButton(const bool flag)
750 {
751     mCloseWindowButton = flag;
752     if (flag)
753         mAllowClose = true;
754 }
755 
isResizable() const756 bool Window::isResizable() const
757 {
758     return mGrip != nullptr;
759 }
760 
setStickyButton(const bool flag)761 void Window::setStickyButton(const bool flag)
762 {
763     mStickyButton = flag;
764 }
765 
setSticky(const bool sticky)766 void Window::setSticky(const bool sticky)
767 {
768     mSticky = sticky;
769     mRedraw = true;
770 }
771 
setStickyButtonLock(const bool lock)772 void Window::setStickyButtonLock(const bool lock)
773 {
774     mStickyButtonLock = lock;
775     mStickyButton = lock;
776 }
777 
setVisible(Visible visible)778 void Window::setVisible(Visible visible)
779 {
780     setVisible(visible, false);
781 }
782 
setVisible(const Visible visible,const bool forceSticky)783 void Window::setVisible(const Visible visible, const bool forceSticky)
784 {
785     if (visible == mVisible)
786         return;
787 
788     // Check if the window is off screen...
789     if (visible == Visible_true)
790         ensureOnScreen();
791     else
792         mResizeHandles = 0;
793 
794     if (mStickyButtonLock)
795     {
796         BasicContainer2::setVisible(visible);
797     }
798     else
799     {
800         BasicContainer2::setVisible(fromBool((!forceSticky && mSticky) ||
801             visible == Visible_true, Visible));
802     }
803     if (visible == Visible_true)
804     {
805         if (mPlayVisibleSound)
806             soundManager.playGuiSound(SOUND_SHOW_WINDOW);
807         if (gui != nullptr)
808         {
809             MouseEvent *const event = reinterpret_cast<MouseEvent*>(
810                 gui->createMouseEvent(this));
811             if (event != nullptr)
812             {
813                 const int x = event->getX();
814                 const int y = event->getY();
815                 if (x >= 0 && x <= mDimension.width
816                     && y >= 0 && y <= mDimension.height)
817                 {
818                     mouseMoved(*event);
819                 }
820                 delete event;
821             }
822         }
823     }
824     else
825     {
826         if (mPlayVisibleSound)
827             soundManager.playGuiSound(SOUND_HIDE_WINDOW);
828     }
829 }
830 
scheduleDelete()831 void Window::scheduleDelete()
832 {
833     windowContainer->scheduleDelete(this);
834 }
835 
mousePressed(MouseEvent & event)836 void Window::mousePressed(MouseEvent &event)
837 {
838     if (event.isConsumed())
839         return;
840 
841     if (event.getSource() == this)
842     {
843         if (getParent() != nullptr)
844             getParent()->moveToTop(this);
845 
846         mDragOffsetX = event.getX();
847         mDragOffsetY = event.getY();
848         mMoved = event.getY() <= CAST_S32(mTitleBarHeight);
849     }
850 
851     const MouseButtonT button = event.getButton();
852     if (button == MouseButton::LEFT)
853     {
854         const int x = event.getX();
855         const int y = event.getY();
856 
857         // Handle close button
858         if (mCloseWindowButton &&
859             mSkin != nullptr &&
860             mCloseRect.isPointInRect(x, y))
861         {
862             mouseResize = 0;
863             mMoved = false;
864             event.consume();
865             close();
866             return;
867         }
868 
869         // Handle sticky button
870         if (mStickyButton &&
871             mSkin != nullptr &&
872             mStickyRect.isPointInRect(x, y))
873         {
874             setSticky(!isSticky());
875             mouseResize = 0;
876             mMoved = false;
877             event.consume();
878             return;
879         }
880 
881         // Handle window resizing
882         mouseResize = getResizeHandles(event) & resizeMask;
883         if (mouseResize != 0)
884             event.consume();
885         if (canMove())
886             mMoved = (mouseResize == 0);
887         else
888             mMoved = false;
889     }
890 #ifndef DYECMD
891     else if (button == MouseButton::RIGHT)
892     {
893         if (popupMenu != nullptr)
894         {
895             event.consume();
896             popupMenu->showWindowPopup(this);
897         }
898     }
899 #endif  // DYECMD
900 }
901 
close()902 void Window::close()
903 {
904     setVisible(Visible_false);
905 }
906 
mouseReleased(MouseEvent & event A_UNUSED)907 void Window::mouseReleased(MouseEvent &event A_UNUSED)
908 {
909     if ((mGrip != nullptr) && (mouseResize != 0))
910     {
911         mouseResize = 0;
912         if (gui != nullptr)
913             gui->setCursorType(Cursor::CURSOR_POINTER);
914     }
915 
916     mMoved = false;
917 }
918 
mouseEntered(MouseEvent & event)919 void Window::mouseEntered(MouseEvent &event)
920 {
921     updateResizeHandler(event);
922 }
923 
mouseExited(MouseEvent & event A_UNUSED)924 void Window::mouseExited(MouseEvent &event A_UNUSED)
925 {
926     if ((mGrip != nullptr) && (mouseResize == 0) && (gui != nullptr))
927         gui->setCursorType(Cursor::CURSOR_POINTER);
928 }
929 
updateResizeHandler(MouseEvent & event)930 void Window::updateResizeHandler(MouseEvent &event)
931 {
932     if (gui == nullptr)
933         return;
934 
935 #ifndef DYECMD
936     if (!dragDrop.isEmpty())
937         return;
938 #endif  // DYECMD
939 
940     mResizeHandles = getResizeHandles(event);
941 
942     // Changes the custom mouse cursor based on it's current position.
943     switch (mResizeHandles & resizeMask)
944     {
945         case BOTTOM | RIGHT:
946         case TOP | LEFT:
947             gui->setCursorType(Cursor::CURSOR_RESIZE_DOWN_RIGHT);
948             break;
949         case TOP | RIGHT:
950         case BOTTOM | LEFT:
951             gui->setCursorType(Cursor::CURSOR_RESIZE_DOWN_LEFT);
952             break;
953         case BOTTOM:
954         case TOP:
955             gui->setCursorType(Cursor::CURSOR_RESIZE_DOWN);
956             break;
957         case RIGHT:
958         case LEFT:
959             gui->setCursorType(Cursor::CURSOR_RESIZE_ACROSS);
960             break;
961         default:
962             gui->setCursorType(Cursor::CURSOR_POINTER);
963             break;
964     }
965 }
966 
mouseMoved(MouseEvent & event)967 void Window::mouseMoved(MouseEvent &event)
968 {
969     updateResizeHandler(event);
970     if ((popupManager != nullptr) && !event.isConsumed())
971     {
972         PopupManager::hideBeingPopup();
973         PopupManager::hideTextPopup();
974     }
975 }
976 
canMove() const977 bool Window::canMove() const
978 {
979     return !mStickyButtonLock || !mSticky;
980 }
981 
mouseDragged(MouseEvent & event)982 void Window::mouseDragged(MouseEvent &event)
983 {
984     if (canMove())
985     {
986         if (!event.isConsumed() && event.getSource() == this)
987         {
988             if (isMovable() && mMoved)
989             {
990                 setPosition(event.getX() - mDragOffsetX + getX(),
991                     event.getY() - mDragOffsetY + getY());
992             }
993 
994             event.consume();
995         }
996     }
997     else
998     {
999         if (!event.isConsumed() && event.getSource() == this)
1000             event.consume();
1001         return;
1002     }
1003 
1004     // Keep guichan window inside screen when it may be moved
1005     if (isMovable() && mMoved)
1006     {
1007         setPosition(std::min(mainGraphics->mWidth - mDimension.width,
1008             std::max(0, mDimension.x)),
1009             std::min(mainGraphics->mHeight - mDimension.height,
1010             std::max(0, mDimension.y)));
1011     }
1012 
1013     if ((mouseResize != 0) && !mMoved)
1014     {
1015         const int dy = event.getY() - mDragOffsetY;
1016         Rect newDim = getDimension();
1017 
1018         if ((mouseResize & (TOP | BOTTOM)) != 0)
1019         {
1020             const int newHeight = newDim.height
1021                 + ((mouseResize & TOP) != 0 ? -dy : dy);
1022             newDim.height = std::min(mMaxWinHeight,
1023                 std::max(mMinWinHeight, newHeight));
1024 
1025             if ((mouseResize & TOP) != 0)
1026                 newDim.y -= newDim.height - getHeight();
1027         }
1028 
1029         if ((mouseResize & (LEFT | RIGHT)) != 0)
1030         {
1031             const int dx = event.getX() - mDragOffsetX;
1032             const int newWidth = newDim.width
1033                 + ((mouseResize & LEFT) != 0 ? -dx : dx);
1034             newDim.width = std::min(mMaxWinWidth,
1035                 std::max(mMinWinWidth, newWidth));
1036 
1037             if ((mouseResize & LEFT) != 0)
1038                 newDim.x -= newDim.width - mDimension.width;
1039         }
1040 
1041         // Keep guichan window inside screen (supports resizing any side)
1042         if (newDim.x < 0)
1043         {
1044             newDim.width += newDim.x;
1045             newDim.x = 0;
1046         }
1047         if (newDim.y < 0)
1048         {
1049             newDim.height += newDim.y;
1050             newDim.y = 0;
1051         }
1052         if (newDim.x + newDim.width > mainGraphics->mWidth)
1053             newDim.width = mainGraphics->mWidth - newDim.x;
1054         if (newDim.y + newDim.height > mainGraphics->mHeight)
1055             newDim.height = mainGraphics->mHeight - newDim.y;
1056 
1057         // Update mouse offset when dragging bottom or right border
1058         if ((mouseResize & BOTTOM) != 0)
1059             mDragOffsetY += newDim.height - mDimension.height;
1060 
1061         if ((mouseResize & RIGHT) != 0)
1062             mDragOffsetX += newDim.width - mDimension.width;
1063 
1064         // Set the new window and content dimensions
1065         setDimension(newDim);
1066     }
1067 }
1068 
setModal(const Modal modal)1069 void Window::setModal(const Modal modal)
1070 {
1071     if (mModal != modal)
1072     {
1073         mModal = modal;
1074         if (mModal == Modal_true)
1075         {
1076             if (gui != nullptr)
1077                 gui->setCursorType(Cursor::CURSOR_POINTER);
1078             requestModalFocus();
1079         }
1080         else
1081         {
1082             releaseModalFocus();
1083         }
1084     }
1085 }
1086 
loadWindowState()1087 void Window::loadWindowState()
1088 {
1089     const std::string &name = mWindowName;
1090     if (name.empty())
1091         return;
1092 
1093     setPosition(config.getValueInt(name + "WinX", mDefaultX),
1094         config.getValueInt(name + "WinY", mDefaultY));
1095 
1096     if (mSaveVisible)
1097     {
1098         setVisible(fromBool(config.getValueBool(name
1099             + "Visible", mDefaultVisible), Visible));
1100     }
1101 
1102     if (mStickyButton)
1103     {
1104         setSticky(config.getValueBool(name
1105             + "Sticky", isSticky()));
1106     }
1107 
1108     if (mGrip != nullptr)
1109     {
1110         int width = config.getValueInt(name + "WinWidth", mDefaultWidth);
1111         int height = config.getValueInt(name + "WinHeight", mDefaultHeight);
1112 
1113         if (getMinWidth() > width)
1114             width = getMinWidth();
1115         else if (getMaxWidth() < width)
1116             width = getMaxWidth();
1117         if (getMinHeight() > height)
1118             height = getMinHeight();
1119         else if (getMaxHeight() < height)
1120             height = getMaxHeight();
1121 
1122         setSize(width, height);
1123     }
1124     else
1125     {
1126         setSize(mDefaultWidth, mDefaultHeight);
1127     }
1128 
1129     // Check if the window is off screen...
1130     ensureOnScreen();
1131 
1132     if (viewport != nullptr)
1133     {
1134         int width = mDimension.width;
1135         int height = mDimension.height;
1136 
1137         if (mDimension.x + width > viewport->getWidth())
1138             width = viewport->getWidth() - mDimension.x;
1139         if (mDimension.y + height > viewport->getHeight())
1140             height = viewport->getHeight() - mDimension.y;
1141         if (width < 0)
1142             width = 0;
1143         if (height < 0)
1144             height = 0;
1145         setSize(width, height);
1146     }
1147 }
1148 
saveWindowState()1149 void Window::saveWindowState()
1150 {
1151     // Saving X, Y and Width and Height for resizables in the config
1152     if (!mWindowName.empty() && mWindowName != "window")
1153     {
1154         config.setValue(mWindowName + "WinX", mDimension.x);
1155         config.setValue(mWindowName + "WinY", mDimension.y);
1156 
1157         if (mSaveVisible)
1158             config.setValue(mWindowName + "Visible", isWindowVisible());
1159 
1160         if (mStickyButton)
1161             config.setValue(mWindowName + "Sticky", isSticky());
1162 
1163         if (mGrip != nullptr)
1164         {
1165             if (getMinWidth() > mDimension.width)
1166                 setWidth(getMinWidth());
1167             else if (getMaxWidth() < mDimension.width)
1168                 setWidth(getMaxWidth());
1169             if (getMinHeight() > mDimension.height)
1170                 setHeight(getMinHeight());
1171             else if (getMaxHeight() < mDimension.height)
1172                 setHeight(getMaxHeight());
1173 
1174             config.setValue(mWindowName + "WinWidth", mDimension.width);
1175             config.setValue(mWindowName + "WinHeight", mDimension.height);
1176         }
1177     }
1178 }
1179 
setDefaultSize(const int defaultX,const int defaultY,int defaultWidth,int defaultHeight)1180 void Window::setDefaultSize(const int defaultX, const int defaultY,
1181                             int defaultWidth, int defaultHeight)
1182 {
1183     if (mMinWinWidth > defaultWidth)
1184         defaultWidth = mMinWinWidth;
1185     else if (mMaxWinWidth < defaultWidth)
1186         defaultWidth = mMaxWinWidth;
1187     if (mMinWinHeight > defaultHeight)
1188         defaultHeight = mMinWinHeight;
1189     else if (mMaxWinHeight < defaultHeight)
1190         defaultHeight = mMaxWinHeight;
1191 
1192     mDefaultX = defaultX;
1193     mDefaultY = defaultY;
1194     mDefaultWidth = defaultWidth;
1195     mDefaultHeight = defaultHeight;
1196 }
1197 
setDefaultSize()1198 void Window::setDefaultSize()
1199 {
1200     mDefaultX = mDimension.x;
1201     mDefaultY = mDimension.y;
1202     mDefaultWidth = mDimension.width;
1203     mDefaultHeight = mDimension.height;
1204 }
1205 
setDefaultSize(const int defaultWidth,const int defaultHeight,const ImagePosition::Type & position,const int offsetX,const int offsetY)1206 void Window::setDefaultSize(const int defaultWidth, const int defaultHeight,
1207                             const ImagePosition::Type &position,
1208                             const int offsetX, const int offsetY)
1209 {
1210     int x = 0;
1211     int y = 0;
1212 
1213     if (position == ImagePosition::UPPER_LEFT)
1214     {
1215     }
1216     else if (position == ImagePosition::UPPER_CENTER)
1217     {
1218         x = (mainGraphics->mWidth - defaultWidth) / 2;
1219     }
1220     else if (position == ImagePosition::UPPER_RIGHT)
1221     {
1222         x = mainGraphics->mWidth - defaultWidth;
1223     }
1224     else if (position == ImagePosition::LEFT)
1225     {
1226         y = (mainGraphics->mHeight - defaultHeight) / 2;
1227     }
1228     else if (position == ImagePosition::CENTER)
1229     {
1230         x = (mainGraphics->mWidth - defaultWidth) / 2;
1231         y = (mainGraphics->mHeight - defaultHeight) / 2;
1232     }
1233     else if (position == ImagePosition::RIGHT)
1234     {
1235         x = mainGraphics->mWidth - defaultWidth;
1236         y = (mainGraphics->mHeight - defaultHeight) / 2;
1237     }
1238     else if (position == ImagePosition::LOWER_LEFT)
1239     {
1240         y = mainGraphics->mHeight - defaultHeight;
1241     }
1242     else if (position == ImagePosition::LOWER_CENTER)
1243     {
1244         x = (mainGraphics->mWidth - defaultWidth) / 2;
1245         y = mainGraphics->mHeight - defaultHeight;
1246     }
1247     else if (position == ImagePosition::LOWER_RIGHT)
1248     {
1249         x = mainGraphics->mWidth - defaultWidth;
1250         y = mainGraphics->mHeight - defaultHeight;
1251     }
1252 
1253     mDefaultX = x - offsetX;
1254     mDefaultY = y - offsetY;
1255     mDefaultWidth = defaultWidth;
1256     mDefaultHeight = defaultHeight;
1257 }
1258 
resetToDefaultSize()1259 void Window::resetToDefaultSize()
1260 {
1261     setPosition(mDefaultX, mDefaultY);
1262     setSize(mDefaultWidth, mDefaultHeight);
1263     saveWindowState();
1264 }
1265 
adjustPositionAfterResize(const int oldScreenWidth,const int oldScreenHeight)1266 void Window::adjustPositionAfterResize(const int oldScreenWidth,
1267                                        const int oldScreenHeight)
1268 {
1269     // If window was aligned to the right or bottom, keep it there
1270     const int rightMargin = oldScreenWidth - (mDimension.x + mDimension.width);
1271     const int bottomMargin = oldScreenHeight
1272         - (mDimension.y + mDimension.height);
1273     if (mDimension.x > 0 && mDimension.x > rightMargin)
1274         mDimension.x = mainGraphics->mWidth - rightMargin - mDimension.width;
1275     if (mDimension.y > 0 && mDimension.y > bottomMargin)
1276     {
1277         mDimension.y = mainGraphics->mHeight
1278             - bottomMargin - mDimension.height;
1279     }
1280 
1281     ensureOnScreen();
1282     adjustSizeToScreen();
1283 }
1284 
adjustSizeToScreen()1285 void Window::adjustSizeToScreen()
1286 {
1287     if (mGrip == nullptr)
1288         return;
1289 
1290     const int screenWidth = mainGraphics->mWidth;
1291     const int screenHeight = mainGraphics->mHeight;
1292     const int oldWidth = mDimension.width;
1293     const int oldHeight = mDimension.height;
1294     if (oldWidth + mDimension.x > screenWidth)
1295         mDimension.x = 0;
1296     if (oldHeight + mDimension.y > screenHeight)
1297         mDimension.x = 0;
1298     if (mDimension.width > screenWidth)
1299         mDimension.width = screenWidth;
1300     if (mDimension.height > screenHeight)
1301         mDimension.height = screenHeight;
1302     if (oldWidth != mDimension.width || oldHeight != mDimension.height)
1303         widgetResized(Event(this));
1304 }
1305 
getResizeHandles(const MouseEvent & event)1306 int Window::getResizeHandles(const MouseEvent &event)
1307 {
1308     if (event.getX() < 0 || event.getY() < 0)
1309         return 0;
1310 
1311     int resizeHandles = 0;
1312     const unsigned y = event.getY();
1313     const unsigned x = event.getX();
1314     if (mCloseRect.isPointInRect(x, y))
1315         return CLOSE;
1316 
1317     if (!mStickyButtonLock || !mSticky)
1318     {
1319         if ((mGrip != nullptr) &&
1320             (y > mTitleBarHeight ||
1321             (CAST_S32(y) < mPadding &&
1322             CAST_S32(mTitleBarHeight) > mPadding)))
1323         {
1324             if (!getWindowArea().isPointInRect(x, y)
1325                 && event.getSource() == this)
1326             {
1327                 resizeHandles |= (x > mDimension.width - resizeBorderWidth)
1328                     ? RIGHT : (x < resizeBorderWidth) ? LEFT : 0;
1329                 resizeHandles |= (y > mDimension.height - resizeBorderWidth)
1330                     ? BOTTOM : (y < resizeBorderWidth) ? TOP : 0;
1331             }
1332             if (x >= CAST_U32(mGripRect.x)
1333                 && y >= CAST_U32(mGripRect.y))
1334             {
1335                 mDragOffsetX = x;
1336                 mDragOffsetY = y;
1337                 resizeHandles |= BOTTOM | RIGHT;
1338             }
1339         }
1340     }
1341 
1342     return resizeHandles;
1343 }
1344 
isResizeAllowed(const MouseEvent & event) const1345 bool Window::isResizeAllowed(const MouseEvent &event) const
1346 {
1347     const int y = event.getY();
1348 
1349     if ((mGrip != nullptr) &&
1350         (y > CAST_S32(mTitleBarHeight) ||
1351         y < mPadding))
1352     {
1353         const int x = event.getX();
1354 
1355         if (!getWindowArea().isPointInRect(x, y) && event.getSource() == this)
1356             return true;
1357 
1358         if (x >= mGripRect.x && y >= mGripRect.y)
1359             return true;
1360     }
1361 
1362     return false;
1363 }
1364 
getLayout()1365 Layout &Window::getLayout()
1366 {
1367     if (mLayout == nullptr)
1368         mLayout = new Layout;
1369     return *mLayout;
1370 }
1371 
clearLayout()1372 void Window::clearLayout()
1373 {
1374     clear();
1375 
1376     // Recreate layout instance when one is present
1377     if (mLayout != nullptr)
1378     {
1379         delete mLayout;
1380         mLayout = new Layout;
1381     }
1382 }
1383 
place(const int x,const int y,Widget * const wg,const int w,const int h)1384 LayoutCell &Window::place(const int x, const int y, Widget *const wg,
1385                           const int w, const int h)
1386 {
1387     add(wg);
1388     return getLayout().place(wg, x, y, w, h);
1389 }
1390 
getPlacer(const int x,const int y)1391 ContainerPlacer Window::getPlacer(const int x, const int y)
1392 {
1393     return ContainerPlacer(this, &getLayout().at(x, y));
1394 }
1395 
reflowLayout(int w,int h)1396 void Window::reflowLayout(int w, int h)
1397 {
1398     if (mLayout == nullptr)
1399         return;
1400 
1401     mLayout->reflow(w, h);
1402     delete2(mLayout)
1403     setContentSize(w, h);
1404 }
1405 
redraw()1406 void Window::redraw()
1407 {
1408     if (mLayout != nullptr)
1409     {
1410         const Rect area = getChildrenArea();
1411         int w = area.width;
1412         int h = area.height;
1413         mLayout->reflow(w, h);
1414     }
1415 }
1416 
center()1417 void Window::center()
1418 {
1419     setLocationRelativeTo(getParent());
1420 }
1421 
centerHorisontally()1422 void Window::centerHorisontally()
1423 {
1424     setLocationHorisontallyRelativeTo(getParent());
1425 }
1426 
ensureOnScreen()1427 void Window::ensureOnScreen()
1428 {
1429     // Skip when a window hasn't got any size initialized yet
1430     if (mDimension.width == 0 && mDimension.height == 0)
1431         return;
1432 
1433     // Check the left and bottom screen boundaries
1434     if (mDimension.x + mDimension.width > mainGraphics->mWidth)
1435         mDimension.x = mainGraphics->mWidth - mDimension.width;
1436     if (mDimension.y + mDimension.height > mainGraphics->mHeight)
1437         mDimension.y = mainGraphics->mHeight - mDimension.height;
1438 
1439     // But never allow the windows to disappear in to the right and top
1440     if (mDimension.x < 0)
1441         mDimension.x = 0;
1442     if (mDimension.y < 0)
1443         mDimension.y = 0;
1444 }
1445 
getWindowArea() const1446 Rect Window::getWindowArea() const
1447 {
1448     return Rect(mPadding,
1449         mPadding,
1450         mDimension.width - mPadding * 2,
1451         mDimension.height - mPadding * 2);
1452 }
1453 
getOption(const std::string & name,const int def) const1454 int Window::getOption(const std::string &name, const int def) const
1455 {
1456     if (mSkin != nullptr)
1457     {
1458         const int val = mSkin->getOption(name);
1459         if (val != 0)
1460             return val;
1461         return def;
1462     }
1463     return def;
1464 }
1465 
getOptionBool(const std::string & name,const bool def) const1466 bool Window::getOptionBool(const std::string &name, const bool def) const
1467 {
1468     if (mSkin != nullptr)
1469         return mSkin->getOption(name, static_cast<int>(def)) != 0;
1470     return def;
1471 }
1472 
getChildrenArea()1473 Rect Window::getChildrenArea()
1474 {
1475     return Rect(mPadding,
1476         mTitleBarHeight,
1477         mDimension.width - mPadding * 2,
1478         mDimension.height - mPadding - mTitleBarHeight);
1479 }
1480 
resizeToContent()1481 void Window::resizeToContent()
1482 {
1483     int w = 0;
1484     int h = 0;
1485     for (WidgetListConstIterator it = mWidgets.begin();
1486           it != mWidgets.end(); ++ it)
1487     {
1488         const Widget *const widget = *it;
1489         const int x = widget->getX();
1490         const int y = widget->getY();
1491         const int width = widget->getWidth();
1492         const int height = widget->getHeight();
1493         if (x + width > w)
1494             w = x + width;
1495 
1496         if (y + height > h)
1497             h = y + height;
1498     }
1499 
1500     setSize(w + 2 * mPadding,
1501         h + mPadding + mTitleBarHeight);
1502 }
1503 
1504 #ifdef USE_PROFILER
logic()1505 void Window::logic()
1506 {
1507     BLOCK_START("Window::logic")
1508     logicChildren();
1509     BLOCK_END("Window::logic")
1510 }
1511 #endif  // USE_PROFILER
1512