GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/window.cpp Lines: 394 730 54.0 %
Date: 2018-06-18 21:15:20 Branches: 267 649 41.1 %

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
126
Window::Window(const std::string &caption,
109
               const Modal modal,
110
               Window *const parent,
111
126
               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
126
    mMaxWinWidth(mainGraphics->mWidth),
143
126
    mMaxWinHeight(mainGraphics->mHeight),
144

126
    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
126
    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

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

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

630
            if (getOptionBool("titlebarBold", false))
198
112
                mCaptionFont = boldFont;
199
252
            mTitlePadding = mSkin->getTitlePadding();
200
630
            mGripPadding = getOption("resizePadding", 0);
201
630
            mCaptionOffsetX = getOption("captionoffsetx", 0);
202
126
            if (mCaptionOffsetX == 0)
203
12
                mCaptionOffsetX = 7;
204
630
            mCaptionOffsetY = getOption("captionoffsety", 0);
205
126
            if (mCaptionOffsetY == 0)
206
12
                mCaptionOffsetY = 5;
207
126
            mCaptionAlign = static_cast<Graphics::Alignment>(
208
630
                getOption("captionalign", 0));
209
126
            if (mCaptionAlign < Graphics::LEFT
210
                || mCaptionAlign > Graphics::RIGHT)
211
            {
212
                mCaptionAlign = Graphics::LEFT;
213
            }
214
252
            setTitleBarHeight(CAST_U32(
215
630
                getOption("titlebarHeight", 0)));
216
126
            if (mTitleBarHeight == 0u)
217
14
                mTitleBarHeight = mCaptionFont->getHeight() + mPadding;
218
219
630
            mTitleBarHeight += getOption("titlebarHeightRelative", 0);
220
756
            setPalette(getOption("palette", 0));
221
630
            childPalette = getOption("childPalette", 0);
222
630
            mShowTitle = getOptionBool("showTitle", true);
223
630
            mClosePadding = getOption("closePadding", 0);
224
630
            mStickySpacing = getOption("stickySpacing", 0);
225
630
            mStickyPadding = getOption("stickyPadding", 0);
226
        }
227
    }
228
229
    // Add this window to the window container
230
126
    if (windowContainer != nullptr)
231
126
        windowContainer->add(this);
232
233
126
    if (mModal == Modal_true)
234
    {
235
20
        gui->setCursorType(Cursor::CURSOR_POINTER);
236
10
        requestModalFocus();
237
    }
238
239
    // Windows are invisible by default
240
126
    setVisible(Visible_false, false);
241
242
126
    addWidgetListener(this);
243
252
    mForegroundColor = getThemeColor(ThemeColorId::WINDOW, 255U);
244
252
    mForegroundColor2 = getThemeColor(ThemeColorId::WINDOW_OUTLINE, 255U);
245
252
    setPalette(childPalette);
246
126
}
247
248
126
void Window::postInit()
249
{
250
126
    if (mInit)
251
    {
252
        reportAlways("error: Window created with calling postInit() "
253
            "more than once: %s",
254
            mWindowName.c_str());
255
    }
256
126
    mInit = true;
257
126
}
258
259
1134
Window::~Window()
260
{
261
252
    logger->log("Window::~Window(\"%s\")", getCaption().c_str());
262
263
126
    if (gui != nullptr)
264
126
        gui->removeDragged(this);
265
266
#ifndef DYECMD
267
126
    if (setupWindow != nullptr)
268
4
        setupWindow->unregisterWindowForReset(this);
269
#endif  // DYECMD
270
271
126
    client->windowRemoved(this);
272
273
126
    saveWindowState();
274
275
252
    delete2(mLayout);
276
277
1768
    while (!mWidgets.empty())
278
1516
        delete mWidgets.front();
279
280
252
    mWidgets.clear();
281
282
126
    removeWidgetListener(this);
283
126
    delete2(mVertexes);
284
285
126
    windowInstances--;
286
287
126
    if (mSkin != nullptr)
288
    {
289
126
        if (theme != nullptr)
290
126
            theme->unload(mSkin);
291
126
        mSkin = nullptr;
292
    }
293
126
    if (mGrip != nullptr)
294
    {
295
84
        mGrip->decRef();
296
84
        mGrip = nullptr;
297
    }
298
126
    if (!mInit)
299
    {
300
        reportAlways("error: Window created without calling postInit(): %s",
301
            mWindowName.c_str());
302
    }
303
126
}
304
305
504
void Window::setWindowContainer(WindowContainer *const wc)
306
{
307
504
    windowContainer = wc;
308
504
}
309
310
64
void Window::draw(Graphics *const graphics)
311
{
312
64
    if (mSkin == nullptr)
313
        return;
314
315
    BLOCK_START("Window::draw")
316
64
    bool update = false;
317
318
64
    if (mResizeHandles != mOldResizeHandles)
319
    {
320
64
        mRedraw = true;
321
64
        mOldResizeHandles = mResizeHandles;
322
    }
323
64
    if (mRedraw)
324
    {
325
64
        mLastRedraw = true;
326
64
        mRedraw = false;
327
64
        update = true;
328
64
        mVertexes->clear();
329
64
        graphics->calcWindow(mVertexes,
330
            0, 0,
331
            mDimension.width,
332
            mDimension.height,
333
64
            mSkin->getBorder());
334
335
        // Draw Close Button
336
64
        if (mCloseWindowButton)
337
        {
338
72
            const Image *const button = mSkin->getCloseImage(
339
72
                mResizeHandles == CLOSE);
340
36
            if (button != nullptr)
341
            {
342
36
                graphics->calcTileCollection(mVertexes,
343
                    button,
344
                    mCloseRect.x,
345
36
                    mCloseRect.y);
346
            }
347
        }
348
        // Draw Sticky Button
349
64
        if (mStickyButton)
350
        {
351
60
            const Image *const button = mSkin->getStickyImage(mSticky);
352
30
            if (button != nullptr)
353
            {
354
10
                graphics->calcTileCollection(mVertexes,
355
                    button,
356
                    mStickyRect.x,
357
10
                    mStickyRect.y);
358
            }
359
        }
360
361
64
        if (mGrip != nullptr)
362
        {
363
36
            graphics->calcTileCollection(mVertexes,
364
                mGrip,
365
                mGripRect.x,
366
36
                mGripRect.y);
367
        }
368
64
        graphics->finalize(mVertexes);
369
    }
370
    else
371
    {
372
        mLastRedraw = false;
373
    }
374
64
    graphics->drawTileCollection(mVertexes);
375
376
    // Draw title
377
64
    if (mShowTitle)
378
    {
379
        int x;
380
62
        switch (mCaptionAlign)
381
        {
382
62
            case Graphics::LEFT:
383
            default:
384
62
                x = mCaptionOffsetX;
385
62
                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
62
        if (mTextChanged)
394
        {
395
62
            mTextChunk.textFont = mCaptionFont;
396
62
            mTextChunk.deleteImage();
397
124
            mTextChunk.text = mCaption;
398
62
            mTextChunk.color = mForegroundColor;
399
62
            mTextChunk.color2 = mForegroundColor2;
400
62
            mCaptionFont->generate(mTextChunk);
401
62
            mTextChanged = false;
402
        }
403
404
62
        const Image *const image = mTextChunk.img;
405
62
        if (image != nullptr)
406
52
            graphics->drawImage(image, x, mCaptionOffsetY);
407
    }
408
409
64
    if (update)
410
    {
411
128
        graphics->setRedraw(update);
412
64
        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
62
void Window::setContentSize(int width, int height)
492
{
493
62
    width = width + 2 * mPadding;
494
62
    height = height + mPadding + mTitleBarHeight;
495
496
62
    if (mMinWinWidth > width)
497
        width = mMinWinWidth;
498
58
    else if (mMaxWinWidth < width)
499
4
        width = mMaxWinWidth;
500
62
    if (mMinWinHeight > height)
501
        height = mMinWinHeight;
502
62
    else if (mMaxWinHeight < height)
503
4
        height = mMaxWinHeight;
504
505
62
    setSize(width, height);
506
62
}
507
508
74
void Window::setLocationRelativeTo(const Widget *const widget)
509
{
510
74
    if (widget == nullptr)
511
2
        return;
512
513
    int wx, wy;
514
    int x, y;
515
516
72
    widget->getAbsolutePosition(wx, wy);
517
72
    getAbsolutePosition(x, y);
518
519
288
    setPosition(mDimension.x + (wx + (widget->getWidth()
520
144
        - mDimension.width) / 2 - x),
521
216
        mDimension.y + (wy + (widget->getHeight()
522
144
        - 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
70
void Window::setMinWidth(const int width)
587
{
588
70
    if (mSkin != nullptr)
589
    {
590
140
        mMinWinWidth = width > mSkin->getMinWidth()
591
70
            ? width : mSkin->getMinWidth();
592
    }
593
    else
594
    {
595
        mMinWinWidth = width;
596
    }
597
70
}
598
599
68
void Window::setMinHeight(const int height)
600
{
601
68
    if (mSkin != nullptr)
602
    {
603
136
        mMinWinHeight = height > mSkin->getMinHeight()
604
68
            ? height : mSkin->getMinHeight();
605
    }
606
    else
607
    {
608
        mMinWinHeight = height;
609
    }
610
68
}
611
612
2
void Window::setMaxWidth(const int width)
613
{
614
2
    mMaxWinWidth = width;
615
2
}
616
617
2
void Window::setMaxHeight(const int height)
618
{
619
2
    mMaxWinHeight = height;
620
2
}
621
622
88
void Window::setResizable(const bool r)
623
{
624
88
    if ((mGrip != nullptr) == r)
625
        return;
626
627
84
    if (mGrip != nullptr)
628
        mGrip->decRef();
629
84
    if (r)
630
    {
631

588
        mGrip = Theme::getImageFromThemeXml("resize.xml", "");
632
84
        if (mGrip != nullptr)
633
        {
634
168
            mGripRect.x = mDimension.width - mGrip->getWidth() - mGripPadding;
635
252
            mGripRect.y = mDimension.height - mGrip->getHeight()
636
84
                - 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
166
void Window::widgetResized(const Event &event A_UNUSED)
651
{
652
166
    if (mGrip != nullptr)
653
    {
654
204
        mGripRect.x = mDimension.width - mGrip->getWidth() - mGripPadding;
655
204
        mGripRect.y = mDimension.height - mGrip->getHeight() - mGripPadding;
656
    }
657
658
166
    if (mLayout != nullptr)
659
    {
660
176
        const Rect area = getChildrenArea();
661
88
        int w = area.width;
662
88
        int h = area.height;
663
88
        mLayout->reflow(w, h);
664
    }
665
166
    if (mSkin != nullptr)
666
    {
667
166
        const bool showClose = mCloseWindowButton
668

272
            && (mSkin->getCloseImage(false) != nullptr);
669
        if (showClose)
670
        {
671
106
            const Image *const button = mSkin->getCloseImage(false);
672
            if (button != nullptr)
673
            {
674
106
                const int buttonWidth = button->getWidth();
675
106
                mCloseRect.x = mDimension.width - buttonWidth - mClosePadding;
676
106
                mCloseRect.y = mClosePadding;
677
106
                mCloseRect.width = buttonWidth;
678
106
                mCloseRect.height = button->getHeight();
679
            }
680
        }
681
166
        if (mStickyButton)
682
        {
683
192
            const Image *const button = mSkin->getStickyImage(mSticky);
684
96
            if (button != nullptr)
685
            {
686
72
                const int buttonWidth = button->getWidth();
687
144
                int x = mDimension.width - buttonWidth
688
72
                    - mStickySpacing - mClosePadding;
689
690
72
                if (showClose)
691
198
                    x -= mSkin->getCloseImage(false)->getWidth();
692
693
72
                mStickyRect.x = x;
694
72
                mStickyRect.y = mStickyPadding;
695
72
                mStickyRect.width = buttonWidth;
696
72
                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
166
    mRedraw = true;
713
166
}
714
715
126
void Window::widgetMoved(const Event& event A_UNUSED)
716
{
717
126
    mRedraw = true;
718
126
}
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
3
    for (WidgetListConstIterator it = mWidgets.begin();
737
15
         it != mWidgets.end(); ++ it)
738
    {
739
4
        if (mFocusHandler->isFocused(*it))
740
            mFocusHandler->focusNone();
741
    }
742
}
743
744
86
void Window::setCloseButton(const bool flag)
745
{
746
86
    mCloseWindowButton = flag;
747
86
    if (flag)
748
84
        mAllowClose = true;
749
86
}
750
751
bool Window::isResizable() const
752
{
753
    return mGrip != nullptr;
754
}
755
756
2
void Window::setStickyButton(const bool flag)
757
{
758
2
    mStickyButton = flag;
759
2
}
760
761
2
void Window::setSticky(const bool sticky)
762
{
763
72
    mSticky = sticky;
764
72
    mRedraw = true;
765
2
}
766
767
72
void Window::setStickyButtonLock(const bool lock)
768
{
769
72
    mStickyButtonLock = lock;
770
72
    mStickyButton = lock;
771
72
}
772
773
106
void Window::setVisible(Visible visible)
774
{
775
106
    setVisible(visible, false);
776
106
}
777
778
234
void Window::setVisible(const Visible visible, const bool forceSticky)
779
{
780
234
    if (visible == mVisible)
781
        return;
782
783
    // Check if the window is off screen...
784
196
    if (visible == Visible_true)
785
69
        ensureOnScreen();
786
    else
787
127
        mResizeHandles = 0;
788
789
196
    if (mStickyButtonLock)
790
    {
791
30
        BasicContainer2::setVisible(visible);
792
    }
793
    else
794
    {
795

166
        BasicContainer2::setVisible(fromBool((!forceSticky && mSticky) ||
796
            visible == Visible_true, Visible));
797
    }
798
196
    if (visible == Visible_true)
799
    {
800
69
        if (mPlayVisibleSound)
801
16
            soundManager.playGuiSound(SOUND_SHOW_WINDOW);
802
69
        if (gui != nullptr)
803
        {
804
            MouseEvent *const event = reinterpret_cast<MouseEvent*>(
805
69
                gui->createMouseEvent(this));
806
69
            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
127
        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
90
void Window::loadWindowState()
1083
{
1084
90
    const std::string &name = mWindowName;
1085
90
    if (name.empty())
1086
        return;
1087
1088


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

64
        setVisible(fromBool(config.getValueBool(name
1094
32
            + "Visible", mDefaultVisible), Visible));
1095
    }
1096
1097
88
    if (mStickyButton)
1098
    {
1099
210
        setSticky(config.getValueBool(name
1100
210
            + "Sticky", isSticky()));
1101
    }
1102
1103
88
    if (mGrip != nullptr)
1104
    {
1105
152
        int width = config.getValueInt(name + "WinWidth", mDefaultWidth);
1106
152
        int height = config.getValueInt(name + "WinHeight", mDefaultHeight);
1107
1108
76
        if (getMinWidth() > width)
1109
            width = getMinWidth();
1110
75
        else if (getMaxWidth() < width)
1111
            width = getMaxWidth();
1112
76
        if (getMinHeight() > height)
1113
            height = getMinHeight();
1114
75
        else if (getMaxHeight() < height)
1115
1
            height = getMaxHeight();
1116
1117
76
        setSize(width, height);
1118
    }
1119
    else
1120
    {
1121
12
        setSize(mDefaultWidth, mDefaultHeight);
1122
    }
1123
1124
    // Check if the window is off screen...
1125
88
    ensureOnScreen();
1126
1127
88
    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
126
void Window::saveWindowState()
1145
{
1146
    // Saving X, Y and Width and Height for resizables in the config
1147

376
    if (!mWindowName.empty() && mWindowName != "window")
1148
    {
1149
184
        config.setValue(mWindowName + "WinX", mDimension.x);
1150
184
        config.setValue(mWindowName + "WinY", mDimension.y);
1151
1152
92
        if (mSaveVisible)
1153
96
            config.setValue(mWindowName + "Visible", isWindowVisible());
1154
1155
92
        if (mStickyButton)
1156
210
            config.setValue(mWindowName + "Sticky", isSticky());
1157
1158
92
        if (mGrip != nullptr)
1159
        {
1160
76
            if (getMinWidth() > mDimension.width)
1161
                setWidth(getMinWidth());
1162
76
            else if (getMaxWidth() < mDimension.width)
1163
                setWidth(getMaxWidth());
1164
76
            if (getMinHeight() > mDimension.height)
1165
                setHeight(getMinHeight());
1166
76
            else if (getMaxHeight() < mDimension.height)
1167
                setHeight(getMaxHeight());
1168
1169
152
            config.setValue(mWindowName + "WinWidth", mDimension.width);
1170
152
            config.setValue(mWindowName + "WinHeight", mDimension.height);
1171
        }
1172
    }
1173
126
}
1174
1175
12
void Window::setDefaultSize(const int defaultX, const int defaultY,
1176
                            int defaultWidth, int defaultHeight)
1177
{
1178
12
    if (mMinWinWidth > defaultWidth)
1179
        defaultWidth = mMinWinWidth;
1180
12
    else if (mMaxWinWidth < defaultWidth)
1181
        defaultWidth = mMaxWinWidth;
1182
12
    if (mMinWinHeight > defaultHeight)
1183
        defaultHeight = mMinWinHeight;
1184
12
    else if (mMaxWinHeight < defaultHeight)
1185
2
        defaultHeight = mMaxWinHeight;
1186
1187
12
    mDefaultX = defaultX;
1188
12
    mDefaultY = defaultY;
1189
12
    mDefaultWidth = defaultWidth;
1190
12
    mDefaultHeight = defaultHeight;
1191
12
}
1192
1193
6
void Window::setDefaultSize()
1194
{
1195
6
    mDefaultX = mDimension.x;
1196
6
    mDefaultY = mDimension.y;
1197
6
    mDefaultWidth = mDimension.width;
1198
6
    mDefaultHeight = mDimension.height;
1199
6
}
1200
1201
74
void Window::setDefaultSize(const int defaultWidth, const int defaultHeight,
1202
                            const ImagePosition::Type &position,
1203
                            const int offsetX, const int offsetY)
1204
{
1205
74
    int x = 0;
1206
74
    int y = 0;
1207
1208
74
    if (position == ImagePosition::UPPER_LEFT)
1209
    {
1210
    }
1211
74
    else if (position == ImagePosition::UPPER_CENTER)
1212
    {
1213
        x = (mainGraphics->mWidth - defaultWidth) / 2;
1214
    }
1215
74
    else if (position == ImagePosition::UPPER_RIGHT)
1216
    {
1217
        x = mainGraphics->mWidth - defaultWidth;
1218
    }
1219
74
    else if (position == ImagePosition::LEFT)
1220
    {
1221
        y = (mainGraphics->mHeight - defaultHeight) / 2;
1222
    }
1223
74
    else if (position == ImagePosition::CENTER)
1224
    {
1225
64
        x = (mainGraphics->mWidth - defaultWidth) / 2;
1226
64
        y = (mainGraphics->mHeight - defaultHeight) / 2;
1227
    }
1228
10
    else if (position == ImagePosition::RIGHT)
1229
    {
1230
2
        x = mainGraphics->mWidth - defaultWidth;
1231
2
        y = (mainGraphics->mHeight - defaultHeight) / 2;
1232
    }
1233
8
    else if (position == ImagePosition::LOWER_LEFT)
1234
    {
1235
6
        y = mainGraphics->mHeight - defaultHeight;
1236
    }
1237
2
    else if (position == ImagePosition::LOWER_CENTER)
1238
    {
1239
        x = (mainGraphics->mWidth - defaultWidth) / 2;
1240
        y = mainGraphics->mHeight - defaultHeight;
1241
    }
1242
2
    else if (position == ImagePosition::LOWER_RIGHT)
1243
    {
1244
2
        x = mainGraphics->mWidth - defaultWidth;
1245
2
        y = mainGraphics->mHeight - defaultHeight;
1246
    }
1247
1248
74
    mDefaultX = x - offsetX;
1249
74
    mDefaultY = y - offsetY;
1250
74
    mDefaultWidth = defaultWidth;
1251
74
    mDefaultHeight = defaultHeight;
1252
74
}
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
404
Layout &Window::getLayout()
1361
{
1362
404
    if (mLayout == nullptr)
1363
88
        mLayout = new Layout;
1364
404
    return *mLayout;
1365
}
1366
1367
4
void Window::clearLayout()
1368
{
1369
4
    clear();
1370
1371
    // Recreate layout instance when one is present
1372
4
    if (mLayout != nullptr)
1373
    {
1374
2
        delete mLayout;
1375
2
        mLayout = new Layout;
1376
    }
1377
4
}
1378
1379
288
LayoutCell &Window::place(const int x, const int y, Widget *const wg,
1380
                          const int w, const int h)
1381
{
1382
288
    add(wg);
1383
288
    return getLayout().place(wg, x, y, w, h);
1384
}
1385
1386
54
ContainerPlacer Window::getPlacer(const int x, const int y)
1387
{
1388
54
    return ContainerPlacer(this, &getLayout().at(x, y));
1389
}
1390
1391
22
void Window::reflowLayout(int w, int h)
1392
{
1393
22
    if (mLayout == nullptr)
1394
        return;
1395
1396
22
    mLayout->reflow(w, h);
1397
44
    delete2(mLayout);
1398
22
    setContentSize(w, h);
1399
}
1400
1401
2
void Window::redraw()
1402
{
1403
2
    if (mLayout != nullptr)
1404
    {
1405
4
        const Rect area = getChildrenArea();
1406
2
        int w = area.width;
1407
2
        int h = area.height;
1408
2
        mLayout->reflow(w, h);
1409
    }
1410
2
}
1411
1412
62
void Window::center()
1413
{
1414
124
    setLocationRelativeTo(getParent());
1415
62
}
1416
1417
void Window::centerHorisontally()
1418
{
1419
    setLocationHorisontallyRelativeTo(getParent());
1420
}
1421
1422
157
void Window::ensureOnScreen()
1423
{
1424
    // Skip when a window hasn't got any size initialized yet
1425
157
    if (mDimension.width == 0 && mDimension.height == 0)
1426
        return;
1427
1428
    // Check the left and bottom screen boundaries
1429
146
    if (mDimension.x + mDimension.width > mainGraphics->mWidth)
1430
2
        mDimension.x = mainGraphics->mWidth - mDimension.width;
1431
146
    if (mDimension.y + mDimension.height > mainGraphics->mHeight)
1432
4
        mDimension.y = mainGraphics->mHeight - mDimension.height;
1433
1434
    // But never allow the windows to disappear in to the right and top
1435
146
    if (mDimension.x < 0)
1436
24
        mDimension.x = 0;
1437
146
    if (mDimension.y < 0)
1438
26
        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
28
int Window::getOption(const std::string &name, const int def) const
1450
{
1451






1414
    if (mSkin != nullptr)
1452
    {
1453





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






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

308
    if (mSkin != nullptr)
1464

308
        return mSkin->getOption(name, static_cast<int>(def)) != 0;
1465
    return def;
1466
}
1467
1468
174
Rect Window::getChildrenArea()
1469
{
1470
    return Rect(mPadding,
1471
        mTitleBarHeight,
1472
174
        mDimension.width - mPadding * 2,
1473
522
        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

6
}
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