GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/window.cpp Lines: 396 719 55.1 %
Date: 2018-12-09 Branches: 271 687 39.4 %

Line Branch Exec Source
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-2018  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/*      _______   __   __   __   ______   __   __   _______   __   __
24
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
25
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
26
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
27
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
28
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
29
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
30
 *
31
 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
32
 *
33
 *
34
 * Per Larsson a.k.a finalman
35
 * Olof Naessén a.k.a jansem/yakslem
36
 *
37
 * Visit: http://guichan.sourceforge.net
38
 *
39
 * License: (BSD)
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in
47
 *    the documentation and/or other materials provided with the
48
 *    distribution.
49
 * 3. Neither the name of Guichan nor the names of its contributors may
50
 *    be used to endorse or promote products derived from this software
51
 *    without specific prior written permission.
52
 *
53
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
56
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
57
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
59
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64
 */
65
66
#include "gui/widgets/window.h"
67
68
#include "client.h"
69
#include "configuration.h"
70
#ifndef DYECMD
71
#include "dragdrop.h"
72
#else  // DYECMD
73
#include "resources/image/image.h"
74
#endif  // DYECMD
75
#include "soundmanager.h"
76
77
#include "const/sound.h"
78
79
#include "gui/focushandler.h"
80
#include "gui/gui.h"
81
#include "gui/popupmanager.h"
82
#include "gui/skin.h"
83
#include "gui/viewport.h"
84
85
#include "gui/fonts/font.h"
86
87
#include "gui/popups/popupmenu.h"
88
89
#include "gui/windows/setupwindow.h"
90
91
#include "gui/widgets/containerplacer.h"
92
#include "gui/widgets/layout.h"
93
94
#include "render/renderers.h"
95
96
#include "render/vertexes/imagecollection.h"
97
98
#include "utils/checkutils.h"
99
#include "utils/delete2.h"
100
101
#include "debug.h"
102
103
const int resizeMask = 8 + 4 + 2 + 1;
104
105
int Window::windowInstances = 0;
106
int Window::mouseResize = 0;
107
108
63
Window::Window(const std::string &caption,
109
               const Modal modal,
110
               Window *const parent,
111
63
               std::string skin) :
112
    BasicContainer2(nullptr),
113
    MouseListener(),
114
    WidgetListener(),
115
    mCaption(caption),
116
    mAlignment(Graphics::CENTER),
117
    mPadding(2),
118
    mTitleBarHeight(16),
119
    mMovable(Move_true),
120
    mDragOffsetX(0),
121
    mDragOffsetY(0),
122
    mMoved(false),
123
    mSkin(nullptr),
124
    mDefaultX(0),
125
    mDefaultY(0),
126
    mDefaultWidth(0),
127
    mDefaultHeight(0),
128
    mCaptionOffsetX(7),
129
    mCaptionOffsetY(5),
130
    mShowTitle(true),
131
    mLastRedraw(true),
132
    mGrip(nullptr),
133
    mParentWindow(parent),
134
    mLayout(nullptr),
135
    mCloseRect(),
136
    mStickyRect(),
137
    mGripRect(),
138
    mTextChunk(),
139
    mWindowName("window"),
140
    mMinWinWidth(100),
141
    mMinWinHeight(40),
142
63
    mMaxWinWidth(mainGraphics->mWidth),
143
63
    mMaxWinHeight(mainGraphics->mHeight),
144

63
    mVertexes(new ImageCollection),
145
    mCaptionAlign(Graphics::LEFT),
146
    mTitlePadding(4),
147
    mGripPadding(2),
148
    mResizeHandles(-1),
149
    mOldResizeHandles(-1),
150
    mClosePadding(0),
151
    mStickySpacing(0),
152
    mStickyPadding(0),
153
63
    mCaptionFont(getFont()),
154
    mModal(modal),
155
    mCloseWindowButton(false),
156
    mDefaultVisible(false),
157
    mSaveVisible(false),
158
    mStickyButton(false),
159
    mSticky(false),
160
    mStickyButtonLock(false),
161
    mPlayVisibleSound(false),
162
    mInit(false),
163
    mTextChanged(true),
164

819
    mAllowClose(false)
165
{
166
63
    logger->log("Window::Window(\"%s\")", caption.c_str());
167
168
63
    mWindow = this;
169
170
63
    windowInstances++;
171
172
//    mFrameSize = 1;
173
63
    addMouseListener(this);
174
175
126
    setFrameSize(0);
176
126
    setPadding(3);
177
126
    setTitleBarHeight(20);
178
179
63
    if (skin.empty())
180
    {
181
        reportAlways("Default skin was used for window: %s",
182
            caption.c_str())
183
        skin = "window.xml";
184
    }
185
186
63
    int childPalette = 1;
187
    // Loads the skin
188
63
    if (theme != nullptr)
189
    {
190

252
        mSkin = theme->load(skin,
191
            "window.xml",
192
            true,
193
63
            Theme::getThemePath());
194
63
        if (mSkin != nullptr)
195
        {
196
189
            setPadding(mSkin->getPadding());
197

315
            if (getOptionBool("titlebarBold", false))
198
56
                mCaptionFont = boldFont;
199
126
            mTitlePadding = mSkin->getTitlePadding();
200
315
            mGripPadding = getOption("resizePadding", 0);
201
315
            mCaptionOffsetX = getOption("captionoffsetx", 0);
202
63
            if (mCaptionOffsetX == 0)
203
6
                mCaptionOffsetX = 7;
204
315
            mCaptionOffsetY = getOption("captionoffsety", 0);
205
63
            if (mCaptionOffsetY == 0)
206
6
                mCaptionOffsetY = 5;
207
63
            mCaptionAlign = static_cast<Graphics::Alignment>(
208
315
                getOption("captionalign", 0));
209
63
            if (mCaptionAlign < Graphics::LEFT
210
                || mCaptionAlign > Graphics::RIGHT)
211
            {
212
                mCaptionAlign = Graphics::LEFT;
213
            }
214
63
            setTitleBarHeight(CAST_U32(
215
441
                getOption("titlebarHeight", 0)));
216
63
            if (mTitleBarHeight == 0U)
217
7
                mTitleBarHeight = mCaptionFont->getHeight() + mPadding;
218
219
315
            mTitleBarHeight += getOption("titlebarHeightRelative", 0);
220
378
            setPalette(getOption("palette", 0));
221
315
            childPalette = getOption("childPalette", 0);
222
315
            mShowTitle = getOptionBool("showTitle", true);
223
315
            mClosePadding = getOption("closePadding", 0);
224
315
            mStickySpacing = getOption("stickySpacing", 0);
225
315
            mStickyPadding = getOption("stickyPadding", 0);
226
        }
227
    }
228
229
    // Add this window to the window container
230
63
    if (windowContainer != nullptr)
231
63
        windowContainer->add(this);
232
233
63
    if (mModal == Modal_true)
234
    {
235
10
        gui->setCursorType(Cursor::CURSOR_POINTER);
236
5
        requestModalFocus();
237
    }
238
239
    // Windows are invisible by default
240
63
    setVisible(Visible_false, false);
241
242
63
    addWidgetListener(this);
243
126
    mForegroundColor = getThemeColor(ThemeColorId::WINDOW, 255U);
244
126
    mForegroundColor2 = getThemeColor(ThemeColorId::WINDOW_OUTLINE, 255U);
245
126
    setPalette(childPalette);
246
63
}
247
248
63
void Window::postInit()
249
{
250
63
    if (mInit)
251
    {
252
        reportAlways("error: Window created with calling postInit() "
253
            "more than once: %s",
254
            mWindowName.c_str())
255
    }
256
63
    mInit = true;
257
63
}
258
259
567
Window::~Window()
260
{
261
63
    logger->log("Window::~Window(\"%s\")", getCaption().c_str());
262
263
63
    if (gui != nullptr)
264
63
        gui->removeDragged(this);
265
266
#ifndef DYECMD
267
63
    if (setupWindow != nullptr)
268
2
        setupWindow->unregisterWindowForReset(this);
269
#endif  // DYECMD
270
271
63
    client->windowRemoved(this);
272
273
63
    saveWindowState();
274
275
126
    delete2(mLayout)
276
277
884
    while (!mWidgets.empty())
278
758
        delete mWidgets.front();
279
280
126
    mWidgets.clear();
281
282
63
    removeWidgetListener(this);
283
63
    delete2(mVertexes)
284
285
63
    windowInstances--;
286
287
63
    if (mSkin != nullptr)
288
    {
289
63
        if (theme != nullptr)
290
63
            theme->unload(mSkin);
291
63
        mSkin = nullptr;
292
    }
293
63
    if (mGrip != nullptr)
294
    {
295
42
        mGrip->decRef();
296
42
        mGrip = nullptr;
297
    }
298
63
    if (!mInit)
299
    {
300
        reportAlways("error: Window created without calling postInit(): %s",
301
            mWindowName.c_str())
302
    }
303
63
}
304
305
254
void Window::setWindowContainer(WindowContainer *const wc)
306
{
307
254
    windowContainer = wc;
308
254
}
309
310
32
void Window::draw(Graphics *const graphics)
311
{
312
32
    if (mSkin == nullptr)
313
        return;
314
315
    BLOCK_START("Window::draw")
316
32
    bool update = false;
317
318
32
    if (mResizeHandles != mOldResizeHandles)
319
    {
320
32
        mRedraw = true;
321
32
        mOldResizeHandles = mResizeHandles;
322
    }
323
32
    if (mRedraw)
324
    {
325
32
        mLastRedraw = true;
326
32
        mRedraw = false;
327
32
        update = true;
328
32
        mVertexes->clear();
329
32
        graphics->calcWindow(mVertexes,
330
            0, 0,
331
            mDimension.width,
332
            mDimension.height,
333
64
            mSkin->getBorder());
334
335
        // Draw Close Button
336
32
        if (mCloseWindowButton)
337
        {
338
18
            const Image *const button = mSkin->getCloseImage(
339
36
                mResizeHandles == CLOSE);
340
18
            if (button != nullptr)
341
            {
342
18
                graphics->calcTileCollection(mVertexes,
343
                    button,
344
                    mCloseRect.x,
345
36
                    mCloseRect.y);
346
            }
347
        }
348
        // Draw Sticky Button
349
32
        if (mStickyButton)
350
        {
351
30
            const Image *const button = mSkin->getStickyImage(mSticky);
352
15
            if (button != nullptr)
353
            {
354
5
                graphics->calcTileCollection(mVertexes,
355
                    button,
356
                    mStickyRect.x,
357
10
                    mStickyRect.y);
358
            }
359
        }
360
361
32
        if (mGrip != nullptr)
362
        {
363
18
            graphics->calcTileCollection(mVertexes,
364
                mGrip,
365
                mGripRect.x,
366
36
                mGripRect.y);
367
        }
368
32
        graphics->finalize(mVertexes);
369
    }
370
    else
371
    {
372
        mLastRedraw = false;
373
    }
374
32
    graphics->drawTileCollection(mVertexes);
375
376
    // Draw title
377
32
    if (mShowTitle)
378
    {
379
        int x;
380
31
        switch (mCaptionAlign)
381
        {
382
            case Graphics::LEFT:
383
            default:
384
31
                x = mCaptionOffsetX;
385
31
                break;
386
            case Graphics::CENTER:
387
                x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption) / 2;
388
                break;
389
            case Graphics::RIGHT:
390
                x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption);
391
                break;
392
        }
393
31
        if (mTextChanged)
394
        {
395
31
            mTextChunk.textFont = mCaptionFont;
396
31
            mTextChunk.deleteImage();
397
62
            mTextChunk.text = mCaption;
398
31
            mTextChunk.color = mForegroundColor;
399
31
            mTextChunk.color2 = mForegroundColor2;
400
31
            mCaptionFont->generate(mTextChunk);
401
31
            mTextChanged = false;
402
        }
403
404
31
        const Image *const image = mTextChunk.img;
405
31
        if (image != nullptr)
406
26
            graphics->drawImage(image, x, mCaptionOffsetY);
407
    }
408
409
32
    if (update)
410
    {
411
64
        graphics->setRedraw(update);
412
32
        drawChildren(graphics);
413
        graphics->setRedraw(false);
414
    }
415
    else
416
    {
417
        drawChildren(graphics);
418
    }
419
    BLOCK_END("Window::draw")
420
}
421
422
void Window::safeDraw(Graphics *const graphics)
423
{
424
    if (mSkin == nullptr)
425
        return;
426
427
    BLOCK_START("Window::safeDraw")
428
429
    graphics->drawImageRect(0, 0,
430
        mDimension.width,
431
        mDimension.height,
432
        mSkin->getBorder());
433
434
    // Draw Close Button
435
    if (mCloseWindowButton)
436
    {
437
        const Image *const button = mSkin->getCloseImage(
438
            mResizeHandles == CLOSE);
439
        if (button != nullptr)
440
            graphics->drawImage(button, mCloseRect.x, mCloseRect.y);
441
    }
442
    // Draw Sticky Button
443
    if (mStickyButton)
444
    {
445
        const Image *const button = mSkin->getStickyImage(mSticky);
446
        if (button != nullptr)
447
            graphics->drawImage(button, mStickyRect.x, mStickyRect.y);
448
    }
449
450
    if (mGrip != nullptr)
451
        graphics->drawImage(mGrip, mGripRect.x, mGripRect.y);
452
453
    // Draw title
454
    if (mShowTitle)
455
    {
456
        int x;
457
        switch (mCaptionAlign)
458
        {
459
            case Graphics::LEFT:
460
            default:
461
                x = mCaptionOffsetX;
462
                break;
463
            case Graphics::CENTER:
464
                x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption) / 2;
465
                break;
466
            case Graphics::RIGHT:
467
                x = mCaptionOffsetX - mCaptionFont->getWidth(mCaption);
468
                break;
469
        }
470
        if (mTextChanged)
471
        {
472
            mTextChunk.textFont = mCaptionFont;
473
            mTextChunk.deleteImage();
474
            mTextChunk.text = mCaption;
475
            mTextChunk.color = mForegroundColor;
476
            mTextChunk.color2 = mForegroundColor2;
477
            mCaptionFont->generate(mTextChunk);
478
            mTextChanged = false;
479
        }
480
481
        const Image *const image = mTextChunk.img;
482
        if (image != nullptr)
483
            graphics->drawImage(image, x, mCaptionOffsetY);
484
    }
485
486
    safeDrawChildren(graphics);
487
488
    BLOCK_END("Window::safeDraw")
489
}
490
491
31
void Window::setContentSize(int width, int height)
492
{
493
31
    width = width + 2 * mPadding;
494
31
    height = height + mPadding + mTitleBarHeight;
495
496
31
    if (mMinWinWidth > width)
497
        width = mMinWinWidth;
498
29
    else if (mMaxWinWidth < width)
499
2
        width = mMaxWinWidth;
500
31
    if (mMinWinHeight > height)
501
        height = mMinWinHeight;
502
31
    else if (mMaxWinHeight < height)
503
2
        height = mMaxWinHeight;
504
505
31
    setSize(width, height);
506
31
}
507
508
37
void Window::setLocationRelativeTo(const Widget *const widget)
509
{
510
37
    if (widget == nullptr)
511
1
        return;
512
513
    int wx;
514
    int wy;
515
    int x;
516
    int y;
517
518
36
    widget->getAbsolutePosition(wx, wy);
519
36
    getAbsolutePosition(x, y);
520
521
144
    setPosition(mDimension.x + (wx + (widget->getWidth()
522
72
        - mDimension.width) / 2 - x),
523
108
        mDimension.y + (wy + (widget->getHeight()
524
108
        - mDimension.height) / 2 - y));
525
}
526
527
void Window::setLocationHorisontallyRelativeTo(const Widget *const widget)
528
{
529
    if (widget == nullptr)
530
        return;
531
532
    int wx;
533
    int wy;
534
    int x;
535
    int y;
536
537
    widget->getAbsolutePosition(wx, wy);
538
    getAbsolutePosition(x, y);
539
540
    setPosition(mDimension.x + (wx + (widget->getWidth()
541
        - mDimension.width) / 2 - x), 0);
542
}
543
544
void Window::setLocationRelativeTo(const ImagePosition::Type &position,
545
                                   int offsetX, int offsetY)
546
{
547
    if (position == ImagePosition::UPPER_LEFT)
548
    {
549
    }
550
    else if (position == ImagePosition::UPPER_CENTER)
551
    {
552
        offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
553
    }
554
    else if (position == ImagePosition::UPPER_RIGHT)
555
    {
556
        offsetX += mainGraphics->mWidth - mDimension.width;
557
    }
558
    else if (position == ImagePosition::LEFT)
559
    {
560
        offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
561
    }
562
    else if (position == ImagePosition::CENTER)
563
    {
564
        offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
565
        offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
566
    }
567
    else if (position == ImagePosition::RIGHT)
568
    {
569
        offsetX += mainGraphics->mWidth - mDimension.width;
570
        offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
571
    }
572
    else if (position == ImagePosition::LOWER_LEFT)
573
    {
574
        offsetY += mainGraphics->mHeight - mDimension.height;
575
    }
576
    else if (position == ImagePosition::LOWER_CENTER)
577
    {
578
        offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
579
        offsetY += mainGraphics->mHeight - mDimension.height;
580
    }
581
    else if (position == ImagePosition::LOWER_RIGHT)
582
    {
583
        offsetX += mainGraphics->mWidth - mDimension.width;
584
        offsetY += mainGraphics->mHeight - mDimension.height;
585
    }
586
587
    setPosition(offsetX, offsetY);
588
}
589
590
35
void Window::setMinWidth(const int width)
591
{
592
35
    if (mSkin != nullptr)
593
    {
594
70
        mMinWinWidth = width > mSkin->getMinWidth()
595
35
            ? width : mSkin->getMinWidth();
596
    }
597
    else
598
    {
599
        mMinWinWidth = width;
600
    }
601
35
}
602
603
34
void Window::setMinHeight(const int height)
604
{
605
34
    if (mSkin != nullptr)
606
    {
607
68
        mMinWinHeight = height > mSkin->getMinHeight()
608
34
            ? height : mSkin->getMinHeight();
609
    }
610
    else
611
    {
612
        mMinWinHeight = height;
613
    }
614
34
}
615
616
1
void Window::setMaxWidth(const int width)
617
{
618
1
    mMaxWinWidth = width;
619
1
}
620
621
1
void Window::setMaxHeight(const int height)
622
{
623
1
    mMaxWinHeight = height;
624
1
}
625
626
44
void Window::setResizable(const bool r)
627
{
628
44
    if ((mGrip != nullptr) == r)
629
        return;
630
631
42
    if (mGrip != nullptr)
632
        mGrip->decRef();
633
42
    if (r)
634
    {
635

294
        mGrip = Theme::getImageFromThemeXml("resize.xml", "");
636
42
        if (mGrip != nullptr)
637
        {
638
84
            mGripRect.x = mDimension.width - mGrip->getWidth() - mGripPadding;
639
126
            mGripRect.y = mDimension.height - mGrip->getHeight()
640
42
                - mGripPadding;
641
        }
642
        else
643
        {
644
            mGripRect.x = 0;
645
            mGripRect.y = 0;
646
        }
647
    }
648
    else
649
    {
650
        mGrip = nullptr;
651
    }
652
}
653
654
83
void Window::widgetResized(const Event &event A_UNUSED)
655
{
656
83
    if (mGrip != nullptr)
657
    {
658
102
        mGripRect.x = mDimension.width - mGrip->getWidth() - mGripPadding;
659
102
        mGripRect.y = mDimension.height - mGrip->getHeight() - mGripPadding;
660
    }
661
662
83
    if (mLayout != nullptr)
663
    {
664
88
        const Rect area = getChildrenArea();
665
44
        int w = area.width;
666
44
        int h = area.height;
667
44
        mLayout->reflow(w, h);
668
    }
669
83
    if (mSkin != nullptr)
670
    {
671
83
        const bool showClose = mCloseWindowButton
672

136
            && (mSkin->getCloseImage(false) != nullptr);
673
83
        if (showClose)
674
        {
675
106
            const Image *const button = mSkin->getCloseImage(false);
676
53
            if (button != nullptr)
677
            {
678
53
                const int buttonWidth = button->getWidth();
679
53
                mCloseRect.x = mDimension.width - buttonWidth - mClosePadding;
680
53
                mCloseRect.y = mClosePadding;
681
53
                mCloseRect.width = buttonWidth;
682
53
                mCloseRect.height = button->getHeight();
683
            }
684
        }
685
83
        if (mStickyButton)
686
        {
687
96
            const Image *const button = mSkin->getStickyImage(mSticky);
688
48
            if (button != nullptr)
689
            {
690
36
                const int buttonWidth = button->getWidth();
691
36
                int x = mDimension.width - buttonWidth
692
36
                    - mStickySpacing - mClosePadding;
693
694
36
                if (showClose)
695
99
                    x -= mSkin->getCloseImage(false)->getWidth();
696
697
36
                mStickyRect.x = x;
698
36
                mStickyRect.y = mStickyPadding;
699
36
                mStickyRect.width = buttonWidth;
700
36
                mStickyRect.height = button->getHeight();
701
            }
702
        }
703
    }
704
    else
705
    {
706
        mCloseRect.x = 0;
707
        mCloseRect.y = 0;
708
        mCloseRect.width = 0;
709
        mCloseRect.height = 0;
710
        mStickyRect.x = 0;
711
        mStickyRect.y = 0;
712
        mStickyRect.width = 0;
713
        mStickyRect.height = 0;
714
    }
715
716
83
    mRedraw = true;
717
83
}
718
719
63
void Window::widgetMoved(const Event& event A_UNUSED)
720
{
721
63
    mRedraw = true;
722
63
}
723
724
1
void Window::widgetHidden(const Event &event A_UNUSED)
725
{
726
1
    if (isBatchDrawRenders(openGLMode))
727
1
        mVertexes->clear();
728
729
1
    mTextChunk.deleteImage();
730
731
1
    mTextChanged = true;
732
1
    mRedraw = true;
733
734
1
    if (gui != nullptr)
735
1
        gui->setCursorType(Cursor::CURSOR_POINTER);
736
737
1
    if (mFocusHandler == nullptr)
738
        return;
739
740
8
    for (WidgetListConstIterator it = mWidgets.begin();
741
10
         it != mWidgets.end(); ++ it)
742
    {
743
4
        if (mFocusHandler->isFocused(*it))
744
            mFocusHandler->focusNone();
745
    }
746
}
747
748
43
void Window::setCloseButton(const bool flag)
749
{
750
43
    mCloseWindowButton = flag;
751
43
    if (flag)
752
42
        mAllowClose = true;
753
43
}
754
755
bool Window::isResizable() const
756
{
757
    return mGrip != nullptr;
758
}
759
760
1
void Window::setStickyButton(const bool flag)
761
{
762
1
    mStickyButton = flag;
763
1
}
764
765
1
void Window::setSticky(const bool sticky)
766
{
767
36
    mSticky = sticky;
768
36
    mRedraw = true;
769
1
}
770
771
36
void Window::setStickyButtonLock(const bool lock)
772
{
773
36
    mStickyButtonLock = lock;
774
36
    mStickyButton = lock;
775
36
}
776
777
53
void Window::setVisible(Visible visible)
778
{
779
53
    setVisible(visible, false);
780
53
}
781
782
117
void Window::setVisible(const Visible visible, const bool forceSticky)
783
{
784
117
    if (visible == mVisible)
785
        return;
786
787
    // Check if the window is off screen...
788
99
    if (visible == Visible_true)
789
35
        ensureOnScreen();
790
    else
791
64
        mResizeHandles = 0;
792
793
99
    if (mStickyButtonLock)
794
    {
795
16
        BasicContainer2::setVisible(visible);
796
    }
797
    else
798
    {
799

83
        BasicContainer2::setVisible(fromBool((!forceSticky && mSticky) ||
800
83
            visible == Visible_true, Visible));
801
    }
802
99
    if (visible == Visible_true)
803
    {
804
35
        if (mPlayVisibleSound)
805
8
            soundManager.playGuiSound(SOUND_SHOW_WINDOW);
806
35
        if (gui != nullptr)
807
        {
808
            MouseEvent *const event = reinterpret_cast<MouseEvent*>(
809
35
                gui->createMouseEvent(this));
810
35
            if (event != nullptr)
811
            {
812
                const int x = event->getX();
813
                const int y = event->getY();
814
                if (x >= 0 && x <= mDimension.width
815
                    && y >= 0 && y <= mDimension.height)
816
                {
817
                    mouseMoved(*event);
818
                }
819
                delete event;
820
            }
821
        }
822
    }
823
    else
824
    {
825
64
        if (mPlayVisibleSound)
826
1
            soundManager.playGuiSound(SOUND_HIDE_WINDOW);
827
    }
828
}
829
830
void Window::scheduleDelete()
831
{
832
    windowContainer->scheduleDelete(this);
833
}
834
835
void Window::mousePressed(MouseEvent &event)
836
{
837
    if (event.isConsumed())
838
        return;
839
840
    if (event.getSource() == this)
841
    {
842
        if (getParent() != nullptr)
843
            getParent()->moveToTop(this);
844
845
        mDragOffsetX = event.getX();
846
        mDragOffsetY = event.getY();
847
        mMoved = event.getY() <= CAST_S32(mTitleBarHeight);
848
    }
849
850
    const MouseButtonT button = event.getButton();
851
    if (button == MouseButton::LEFT)
852
    {
853
        const int x = event.getX();
854
        const int y = event.getY();
855
856
        // Handle close button
857
        if (mCloseWindowButton &&
858
            mSkin != nullptr &&
859
            mCloseRect.isPointInRect(x, y))
860
        {
861
            mouseResize = 0;
862
            mMoved = false;
863
            event.consume();
864
            close();
865
            return;
866
        }
867
868
        // Handle sticky button
869
        if (mStickyButton &&
870
            mSkin != nullptr &&
871
            mStickyRect.isPointInRect(x, y))
872
        {
873
            setSticky(!isSticky());
874
            mouseResize = 0;
875
            mMoved = false;
876
            event.consume();
877
            return;
878
        }
879
880
        // Handle window resizing
881
        mouseResize = getResizeHandles(event) & resizeMask;
882
        if (mouseResize != 0)
883
            event.consume();
884
        if (canMove())
885
            mMoved = (mouseResize == 0);
886
        else
887
            mMoved = false;
888
    }
889
#ifndef DYECMD
890
    else if (button == MouseButton::RIGHT)
891
    {
892
        if (popupMenu != nullptr)
893
        {
894
            event.consume();
895
            popupMenu->showWindowPopup(this);
896
        }
897
    }
898
#endif  // DYECMD
899
}
900
901
void Window::close()
902
{
903
    setVisible(Visible_false);
904
}
905
906
void Window::mouseReleased(MouseEvent &event A_UNUSED)
907
{
908
    if ((mGrip != nullptr) && (mouseResize != 0))
909
    {
910
        mouseResize = 0;
911
        if (gui != nullptr)
912
            gui->setCursorType(Cursor::CURSOR_POINTER);
913
    }
914
915
    mMoved = false;
916
}
917
918
void Window::mouseEntered(MouseEvent &event)
919
{
920
    updateResizeHandler(event);
921
}
922
923
void Window::mouseExited(MouseEvent &event A_UNUSED)
924
{
925
    if ((mGrip != nullptr) && (mouseResize == 0) && (gui != nullptr))
926
        gui->setCursorType(Cursor::CURSOR_POINTER);
927
}
928
929
void Window::updateResizeHandler(MouseEvent &event)
930
{
931
    if (gui == nullptr)
932
        return;
933
934
#ifndef DYECMD
935
    if (!dragDrop.isEmpty())
936
        return;
937
#endif  // DYECMD
938
939
    mResizeHandles = getResizeHandles(event);
940
941
    // Changes the custom mouse cursor based on it's current position.
942
    switch (mResizeHandles & resizeMask)
943
    {
944
        case BOTTOM | RIGHT:
945
        case TOP | LEFT:
946
            gui->setCursorType(Cursor::CURSOR_RESIZE_DOWN_RIGHT);
947
            break;
948
        case TOP | RIGHT:
949
        case BOTTOM | LEFT:
950
            gui->setCursorType(Cursor::CURSOR_RESIZE_DOWN_LEFT);
951
            break;
952
        case BOTTOM:
953
        case TOP:
954
            gui->setCursorType(Cursor::CURSOR_RESIZE_DOWN);
955
            break;
956
        case RIGHT:
957
        case LEFT:
958
            gui->setCursorType(Cursor::CURSOR_RESIZE_ACROSS);
959
            break;
960
        default:
961
            gui->setCursorType(Cursor::CURSOR_POINTER);
962
            break;
963
    }
964
}
965
966
void Window::mouseMoved(MouseEvent &event)
967
{
968
    updateResizeHandler(event);
969
    if ((popupManager != nullptr) && !event.isConsumed())
970
    {
971
        PopupManager::hideBeingPopup();
972
        PopupManager::hideTextPopup();
973
    }
974
}
975
976
bool Window::canMove() const
977
{
978
    return !mStickyButtonLock || !mSticky;
979
}
980
981
void Window::mouseDragged(MouseEvent &event)
982
{
983
    if (canMove())
984
    {
985
        if (!event.isConsumed() && event.getSource() == this)
986
        {
987
            if (isMovable() && mMoved)
988
            {
989
                setPosition(event.getX() - mDragOffsetX + getX(),
990
                    event.getY() - mDragOffsetY + getY());
991
            }
992
993
            event.consume();
994
        }
995
    }
996
    else
997
    {
998
        if (!event.isConsumed() && event.getSource() == this)
999
            event.consume();
1000
        return;
1001
    }
1002
1003
    // Keep guichan window inside screen when it may be moved
1004
    if (isMovable() && mMoved)
1005
    {
1006
        setPosition(std::min(mainGraphics->mWidth - mDimension.width,
1007
            std::max(0, mDimension.x)),
1008
            std::min(mainGraphics->mHeight - mDimension.height,
1009
            std::max(0, mDimension.y)));
1010
    }
1011
1012
    if ((mouseResize != 0) && !mMoved)
1013
    {
1014
        const int dx = event.getX() - mDragOffsetX;
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 newWidth = newDim.width
1032
                + ((mouseResize & LEFT) != 0 ? -dx : dx);
1033
            newDim.width = std::min(mMaxWinWidth,
1034
                std::max(mMinWinWidth, newWidth));
1035
1036
            if ((mouseResize & LEFT) != 0)
1037
                newDim.x -= newDim.width - mDimension.width;
1038
        }
1039
1040
        // Keep guichan window inside screen (supports resizing any side)
1041
        if (newDim.x < 0)
1042
        {
1043
            newDim.width += newDim.x;
1044
            newDim.x = 0;
1045
        }
1046
        if (newDim.y < 0)
1047
        {
1048
            newDim.height += newDim.y;
1049
            newDim.y = 0;
1050
        }
1051
        if (newDim.x + newDim.width > mainGraphics->mWidth)
1052
            newDim.width = mainGraphics->mWidth - newDim.x;
1053
        if (newDim.y + newDim.height > mainGraphics->mHeight)
1054
            newDim.height = mainGraphics->mHeight - newDim.y;
1055
1056
        // Update mouse offset when dragging bottom or right border
1057
        if ((mouseResize & BOTTOM) != 0)
1058
            mDragOffsetY += newDim.height - mDimension.height;
1059
1060
        if ((mouseResize & RIGHT) != 0)
1061
            mDragOffsetX += newDim.width - mDimension.width;
1062
1063
        // Set the new window and content dimensions
1064
        setDimension(newDim);
1065
    }
1066
}
1067
1068
void Window::setModal(const Modal modal)
1069
{
1070
    if (mModal != modal)
1071
    {
1072
        mModal = modal;
1073
        if (mModal == Modal_true)
1074
        {
1075
            if (gui != nullptr)
1076
                gui->setCursorType(Cursor::CURSOR_POINTER);
1077
            requestModalFocus();
1078
        }
1079
        else
1080
        {
1081
            releaseModalFocus();
1082
        }
1083
    }
1084
}
1085
1086
45
void Window::loadWindowState()
1087
{
1088
45
    const std::string &name = mWindowName;
1089
45
    if (name.empty())
1090
        return;
1091
1092

132
    setPosition(config.getValueInt(name + "WinX", mDefaultX),
1093
132
        config.getValueInt(name + "WinY", mDefaultY));
1094
1095
44
    if (mSaveVisible)
1096
    {
1097

32
        setVisible(fromBool(config.getValueBool(name
1098
32
            + "Visible", mDefaultVisible), Visible));
1099
    }
1100
1101
44
    if (mStickyButton)
1102
    {
1103
70
        setSticky(config.getValueBool(name
1104
140
            + "Sticky", isSticky()));
1105
    }
1106
1107
44
    if (mGrip != nullptr)
1108
    {
1109
76
        int width = config.getValueInt(name + "WinWidth", mDefaultWidth);
1110
76
        int height = config.getValueInt(name + "WinHeight", mDefaultHeight);
1111
1112
38
        if (getMinWidth() > width)
1113
            width = getMinWidth();
1114
37
        else if (getMaxWidth() < width)
1115
            width = getMaxWidth();
1116
38
        if (getMinHeight() > height)
1117
            height = getMinHeight();
1118
37
        else if (getMaxHeight() < height)
1119
1
            height = getMaxHeight();
1120
1121
38
        setSize(width, height);
1122
    }
1123
    else
1124
    {
1125
6
        setSize(mDefaultWidth, mDefaultHeight);
1126
    }
1127
1128
    // Check if the window is off screen...
1129
44
    ensureOnScreen();
1130
1131
44
    if (viewport != nullptr)
1132
    {
1133
        int width = mDimension.width;
1134
        int height = mDimension.height;
1135
1136
        if (mDimension.x + width > viewport->getWidth())
1137
            width = viewport->getWidth() - mDimension.x;
1138
        if (mDimension.y + height > viewport->getHeight())
1139
            height = viewport->getHeight() - mDimension.y;
1140
        if (width < 0)
1141
            width = 0;
1142
        if (height < 0)
1143
            height = 0;
1144
        setSize(width, height);
1145
    }
1146
}
1147
1148
63
void Window::saveWindowState()
1149
{
1150
    // Saving X, Y and Width and Height for resizables in the config
1151

188
    if (!mWindowName.empty() && mWindowName != "window")
1152
    {
1153
92
        config.setValue(mWindowName + "WinX", mDimension.x);
1154
92
        config.setValue(mWindowName + "WinY", mDimension.y);
1155
1156
46
        if (mSaveVisible)
1157
48
            config.setValue(mWindowName + "Visible", isWindowVisible());
1158
1159
46
        if (mStickyButton)
1160
105
            config.setValue(mWindowName + "Sticky", isSticky());
1161
1162
46
        if (mGrip != nullptr)
1163
        {
1164
38
            if (getMinWidth() > mDimension.width)
1165
                setWidth(getMinWidth());
1166
38
            else if (getMaxWidth() < mDimension.width)
1167
                setWidth(getMaxWidth());
1168
38
            if (getMinHeight() > mDimension.height)
1169
                setHeight(getMinHeight());
1170
38
            else if (getMaxHeight() < mDimension.height)
1171
                setHeight(getMaxHeight());
1172
1173
76
            config.setValue(mWindowName + "WinWidth", mDimension.width);
1174
76
            config.setValue(mWindowName + "WinHeight", mDimension.height);
1175
        }
1176
    }
1177
63
}
1178
1179
6
void Window::setDefaultSize(const int defaultX, const int defaultY,
1180
                            int defaultWidth, int defaultHeight)
1181
{
1182
6
    if (mMinWinWidth > defaultWidth)
1183
        defaultWidth = mMinWinWidth;
1184
6
    else if (mMaxWinWidth < defaultWidth)
1185
        defaultWidth = mMaxWinWidth;
1186
6
    if (mMinWinHeight > defaultHeight)
1187
        defaultHeight = mMinWinHeight;
1188
6
    else if (mMaxWinHeight < defaultHeight)
1189
1
        defaultHeight = mMaxWinHeight;
1190
1191
6
    mDefaultX = defaultX;
1192
6
    mDefaultY = defaultY;
1193
6
    mDefaultWidth = defaultWidth;
1194
6
    mDefaultHeight = defaultHeight;
1195
6
}
1196
1197
3
void Window::setDefaultSize()
1198
{
1199
3
    mDefaultX = mDimension.x;
1200
3
    mDefaultY = mDimension.y;
1201
3
    mDefaultWidth = mDimension.width;
1202
3
    mDefaultHeight = mDimension.height;
1203
3
}
1204
1205
37
void Window::setDefaultSize(const int defaultWidth, const int defaultHeight,
1206
                            const ImagePosition::Type &position,
1207
                            const int offsetX, const int offsetY)
1208
{
1209
37
    int x = 0;
1210
37
    int y = 0;
1211
1212
37
    if (position == ImagePosition::UPPER_LEFT)
1213
    {
1214
    }
1215
37
    else if (position == ImagePosition::UPPER_CENTER)
1216
    {
1217
        x = (mainGraphics->mWidth - defaultWidth) / 2;
1218
    }
1219
37
    else if (position == ImagePosition::UPPER_RIGHT)
1220
    {
1221
        x = mainGraphics->mWidth - defaultWidth;
1222
    }
1223
37
    else if (position == ImagePosition::LEFT)
1224
    {
1225
        y = (mainGraphics->mHeight - defaultHeight) / 2;
1226
    }
1227
37
    else if (position == ImagePosition::CENTER)
1228
    {
1229
32
        x = (mainGraphics->mWidth - defaultWidth) / 2;
1230
32
        y = (mainGraphics->mHeight - defaultHeight) / 2;
1231
    }
1232
5
    else if (position == ImagePosition::RIGHT)
1233
    {
1234
1
        x = mainGraphics->mWidth - defaultWidth;
1235
1
        y = (mainGraphics->mHeight - defaultHeight) / 2;
1236
    }
1237
4
    else if (position == ImagePosition::LOWER_LEFT)
1238
    {
1239
3
        y = mainGraphics->mHeight - defaultHeight;
1240
    }
1241
1
    else if (position == ImagePosition::LOWER_CENTER)
1242
    {
1243
        x = (mainGraphics->mWidth - defaultWidth) / 2;
1244
        y = mainGraphics->mHeight - defaultHeight;
1245
    }
1246
1
    else if (position == ImagePosition::LOWER_RIGHT)
1247
    {
1248
1
        x = mainGraphics->mWidth - defaultWidth;
1249
1
        y = mainGraphics->mHeight - defaultHeight;
1250
    }
1251
1252
37
    mDefaultX = x - offsetX;
1253
37
    mDefaultY = y - offsetY;
1254
37
    mDefaultWidth = defaultWidth;
1255
37
    mDefaultHeight = defaultHeight;
1256
37
}
1257
1258
void Window::resetToDefaultSize()
1259
{
1260
    setPosition(mDefaultX, mDefaultY);
1261
    setSize(mDefaultWidth, mDefaultHeight);
1262
    saveWindowState();
1263
}
1264
1265
void Window::adjustPositionAfterResize(const int oldScreenWidth,
1266
                                       const int oldScreenHeight)
1267
{
1268
    // If window was aligned to the right or bottom, keep it there
1269
    const int rightMargin = oldScreenWidth - (mDimension.x + mDimension.width);
1270
    const int bottomMargin = oldScreenHeight
1271
        - (mDimension.y + mDimension.height);
1272
    if (mDimension.x > 0 && mDimension.x > rightMargin)
1273
        mDimension.x = mainGraphics->mWidth - rightMargin - mDimension.width;
1274
    if (mDimension.y > 0 && mDimension.y > bottomMargin)
1275
    {
1276
        mDimension.y = mainGraphics->mHeight
1277
            - bottomMargin - mDimension.height;
1278
    }
1279
1280
    ensureOnScreen();
1281
    adjustSizeToScreen();
1282
}
1283
1284
void Window::adjustSizeToScreen()
1285
{
1286
    if (mGrip == nullptr)
1287
        return;
1288
1289
    const int screenWidth = mainGraphics->mWidth;
1290
    const int screenHeight = mainGraphics->mHeight;
1291
    const int oldWidth = mDimension.width;
1292
    const int oldHeight = mDimension.height;
1293
    if (oldWidth + mDimension.x > screenWidth)
1294
        mDimension.x = 0;
1295
    if (oldHeight + mDimension.y > screenHeight)
1296
        mDimension.x = 0;
1297
    if (mDimension.width > screenWidth)
1298
        mDimension.width = screenWidth;
1299
    if (mDimension.height > screenHeight)
1300
        mDimension.height = screenHeight;
1301
    if (oldWidth != mDimension.width || oldHeight != mDimension.height)
1302
        widgetResized(Event(this));
1303
}
1304
1305
int Window::getResizeHandles(const MouseEvent &event)
1306
{
1307
    if (event.getX() < 0 || event.getY() < 0)
1308
        return 0;
1309
1310
    int resizeHandles = 0;
1311
    const unsigned y = event.getY();
1312
    const unsigned x = event.getX();
1313
    if (mCloseRect.isPointInRect(x, y))
1314
        return CLOSE;
1315
1316
    if (!mStickyButtonLock || !mSticky)
1317
    {
1318
        if ((mGrip != nullptr) &&
1319
            (y > mTitleBarHeight ||
1320
            (CAST_S32(y) < mPadding &&
1321
            CAST_S32(mTitleBarHeight) > mPadding)))
1322
        {
1323
            if (!getWindowArea().isPointInRect(x, y)
1324
                && event.getSource() == this)
1325
            {
1326
                resizeHandles |= (x > mDimension.width - resizeBorderWidth)
1327
                    ? RIGHT : (x < resizeBorderWidth) ? LEFT : 0;
1328
                resizeHandles |= (y > mDimension.height - resizeBorderWidth)
1329
                    ? BOTTOM : (y < resizeBorderWidth) ? TOP : 0;
1330
            }
1331
            if (x >= CAST_U32(mGripRect.x)
1332
                && y >= CAST_U32(mGripRect.y))
1333
            {
1334
                mDragOffsetX = x;
1335
                mDragOffsetY = y;
1336
                resizeHandles |= BOTTOM | RIGHT;
1337
            }
1338
        }
1339
    }
1340
1341
    return resizeHandles;
1342
}
1343
1344
bool Window::isResizeAllowed(const MouseEvent &event) const
1345
{
1346
    const int y = event.getY();
1347
1348
    if ((mGrip != nullptr) &&
1349
        (y > CAST_S32(mTitleBarHeight) ||
1350
        y < mPadding))
1351
    {
1352
        const int x = event.getX();
1353
1354
        if (!getWindowArea().isPointInRect(x, y) && event.getSource() == this)
1355
            return true;
1356
1357
        if (x >= mGripRect.x && y >= mGripRect.y)
1358
            return true;
1359
    }
1360
1361
    return false;
1362
}
1363
1364
202
Layout &Window::getLayout()
1365
{
1366
202
    if (mLayout == nullptr)
1367
44
        mLayout = new Layout;
1368
202
    return *mLayout;
1369
}
1370
1371
2
void Window::clearLayout()
1372
{
1373
2
    clear();
1374
1375
    // Recreate layout instance when one is present
1376
2
    if (mLayout != nullptr)
1377
    {
1378
1
        delete mLayout;
1379
1
        mLayout = new Layout;
1380
    }
1381
2
}
1382
1383
144
LayoutCell &Window::place(const int x, const int y, Widget *const wg,
1384
                          const int w, const int h)
1385
{
1386
144
    add(wg);
1387
144
    return getLayout().place(wg, x, y, w, h);
1388
}
1389
1390
27
ContainerPlacer Window::getPlacer(const int x, const int y)
1391
{
1392
27
    return ContainerPlacer(this, &getLayout().at(x, y));
1393
}
1394
1395
11
void Window::reflowLayout(int w, int h)
1396
{
1397
11
    if (mLayout == nullptr)
1398
        return;
1399
1400
11
    mLayout->reflow(w, h);
1401
22
    delete2(mLayout)
1402
11
    setContentSize(w, h);
1403
}
1404
1405
1
void Window::redraw()
1406
{
1407
1
    if (mLayout != nullptr)
1408
    {
1409
2
        const Rect area = getChildrenArea();
1410
1
        int w = area.width;
1411
1
        int h = area.height;
1412
1
        mLayout->reflow(w, h);
1413
    }
1414
1
}
1415
1416
31
void Window::center()
1417
{
1418
62
    setLocationRelativeTo(getParent());
1419
31
}
1420
1421
void Window::centerHorisontally()
1422
{
1423
    setLocationHorisontallyRelativeTo(getParent());
1424
}
1425
1426
79
void Window::ensureOnScreen()
1427
{
1428
    // Skip when a window hasn't got any size initialized yet
1429
79
    if (mDimension.width == 0 && mDimension.height == 0)
1430
        return;
1431
1432
    // Check the left and bottom screen boundaries
1433
73
    if (mDimension.x + mDimension.width > mainGraphics->mWidth)
1434
2
        mDimension.x = mainGraphics->mWidth - mDimension.width;
1435
73
    if (mDimension.y + mDimension.height > mainGraphics->mHeight)
1436
3
        mDimension.y = mainGraphics->mHeight - mDimension.height;
1437
1438
    // But never allow the windows to disappear in to the right and top
1439
73
    if (mDimension.x < 0)
1440
14
        mDimension.x = 0;
1441
73
    if (mDimension.y < 0)
1442
15
        mDimension.y = 0;
1443
}
1444
1445
Rect Window::getWindowArea() const
1446
{
1447
    return Rect(mPadding,
1448
        mPadding,
1449
        mDimension.width - mPadding * 2,
1450
        mDimension.height - mPadding * 2);
1451
}
1452
1453
14
int Window::getOption(const std::string &name, const int def) const
1454
{
1455






707
    if (mSkin != nullptr)
1456
    {
1457





707
        const int val = mSkin->getOption(name);
1458






707
        if (val != 0)
1459
            return val;
1460
7
        return def;
1461
    }
1462
    return def;
1463
}
1464
1465
28
bool Window::getOptionBool(const std::string &name, const bool def) const
1466
{
1467

154
    if (mSkin != nullptr)
1468

154
        return mSkin->getOption(name, static_cast<int>(def)) != 0;
1469
    return def;
1470
}
1471
1472
87
Rect Window::getChildrenArea()
1473
{
1474
    return Rect(mPadding,
1475
        mTitleBarHeight,
1476
87
        mDimension.width - mPadding * 2,
1477
261
        mDimension.height - mPadding - mTitleBarHeight);
1478
}
1479
1480
void Window::resizeToContent()
1481
{
1482
    int w = 0;
1483
    int h = 0;
1484
    for (WidgetListConstIterator it = mWidgets.begin();
1485
          it != mWidgets.end(); ++ it)
1486
    {
1487
        const Widget *const widget = *it;
1488
        const int x = widget->getX();
1489
        const int y = widget->getY();
1490
        const int width = widget->getWidth();
1491
        const int height = widget->getHeight();
1492
        if (x + width > w)
1493
            w = x + width;
1494
1495
        if (y + height > h)
1496
            h = y + height;
1497
    }
1498
1499
    setSize(w + 2 * mPadding,
1500
        h + mPadding + mTitleBarHeight);
1501

3
}
1502
1503
#ifdef USE_PROFILER
1504
void Window::logic()
1505
{
1506
    BLOCK_START("Window::logic")
1507
    logicChildren();
1508
    BLOCK_END("Window::logic")
1509
}
1510
#endif  // USE_PROFILER