GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/window.cpp Lines: 396 719 55.1 %
Date: 2018-09-20 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, wy;
514
    int x, y;
515
516
36
    widget->getAbsolutePosition(wx, wy);
517
36
    getAbsolutePosition(x, y);
518
519
144
    setPosition(mDimension.x + (wx + (widget->getWidth()
520
72
        - mDimension.width) / 2 - x),
521
108
        mDimension.y + (wy + (widget->getHeight()
522
108
        - mDimension.height) / 2 - y));
523
}
524
525
void Window::setLocationHorisontallyRelativeTo(const Widget *const widget)
526
{
527
    if (widget == nullptr)
528
        return;
529
530
    int wx, wy;
531
    int x, y;
532
533
    widget->getAbsolutePosition(wx, wy);
534
    getAbsolutePosition(x, y);
535
536
    setPosition(mDimension.x + (wx + (widget->getWidth()
537
        - mDimension.width) / 2 - x), 0);
538
}
539
540
void Window::setLocationRelativeTo(const ImagePosition::Type &position,
541
                                   int offsetX, int offsetY)
542
{
543
    if (position == ImagePosition::UPPER_LEFT)
544
    {
545
    }
546
    else if (position == ImagePosition::UPPER_CENTER)
547
    {
548
        offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
549
    }
550
    else if (position == ImagePosition::UPPER_RIGHT)
551
    {
552
        offsetX += mainGraphics->mWidth - mDimension.width;
553
    }
554
    else if (position == ImagePosition::LEFT)
555
    {
556
        offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
557
    }
558
    else if (position == ImagePosition::CENTER)
559
    {
560
        offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
561
        offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
562
    }
563
    else if (position == ImagePosition::RIGHT)
564
    {
565
        offsetX += mainGraphics->mWidth - mDimension.width;
566
        offsetY += (mainGraphics->mHeight - mDimension.height) / 2;
567
    }
568
    else if (position == ImagePosition::LOWER_LEFT)
569
    {
570
        offsetY += mainGraphics->mHeight - mDimension.height;
571
    }
572
    else if (position == ImagePosition::LOWER_CENTER)
573
    {
574
        offsetX += (mainGraphics->mWidth - mDimension.width) / 2;
575
        offsetY += mainGraphics->mHeight - mDimension.height;
576
    }
577
    else if (position == ImagePosition::LOWER_RIGHT)
578
    {
579
        offsetX += mainGraphics->mWidth - mDimension.width;
580
        offsetY += mainGraphics->mHeight - mDimension.height;
581
    }
582
583
    setPosition(offsetX, offsetY);
584
}
585
586
35
void Window::setMinWidth(const int width)
587
{
588
35
    if (mSkin != nullptr)
589
    {
590
70
        mMinWinWidth = width > mSkin->getMinWidth()
591
35
            ? width : mSkin->getMinWidth();
592
    }
593
    else
594
    {
595
        mMinWinWidth = width;
596
    }
597
35
}
598
599
34
void Window::setMinHeight(const int height)
600
{
601
34
    if (mSkin != nullptr)
602
    {
603
68
        mMinWinHeight = height > mSkin->getMinHeight()
604
34
            ? height : mSkin->getMinHeight();
605
    }
606
    else
607
    {
608
        mMinWinHeight = height;
609
    }
610
34
}
611
612
1
void Window::setMaxWidth(const int width)
613
{
614
1
    mMaxWinWidth = width;
615
1
}
616
617
1
void Window::setMaxHeight(const int height)
618
{
619
1
    mMaxWinHeight = height;
620
1
}
621
622
44
void Window::setResizable(const bool r)
623
{
624
44
    if ((mGrip != nullptr) == r)
625
        return;
626
627
42
    if (mGrip != nullptr)
628
        mGrip->decRef();
629
42
    if (r)
630
    {
631

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

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

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

132
    setPosition(config.getValueInt(name + "WinX", mDefaultX),
1089
132
        config.getValueInt(name + "WinY", mDefaultY));
1090
1091
44
    if (mSaveVisible)
1092
    {
1093

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

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






707
    if (mSkin != nullptr)
1452
    {
1453





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






707
        if (val != 0)
1455
            return val;
1456
7
        return def;
1457
    }
1458
    return def;
1459
}
1460
1461
28
bool Window::getOptionBool(const std::string &name, const bool def) const
1462
{
1463

154
    if (mSkin != nullptr)
1464

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

3
}
1498
1499
#ifdef USE_PROFILER
1500
void Window::logic()
1501
{
1502
    BLOCK_START("Window::logic")
1503
    logicChildren();
1504
    BLOCK_END("Window::logic")
1505
}
1506
#endif  // USE_PROFILER