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

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

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

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

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

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

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

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

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

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

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






707
    if (mSkin != nullptr)
1457
    {
1458





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






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

154
    if (mSkin != nullptr)
1469

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

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