GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/button.cpp Lines: 202 393 51.4 %
Date: 2018-09-20 Branches: 99 290 34.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/button.h"
67
68
#include "settings.h"
69
70
#include "resources/imageset.h"
71
#include "resources/imagerect.h"
72
73
#include "resources/image/image.h"
74
75
#include "gui/gui.h"
76
#include "gui/skin.h"
77
78
#include "gui/fonts/font.h"
79
80
#include "render/renderers.h"
81
82
#include "render/vertexes/imagecollection.h"
83
84
#include "utils/delete2.h"
85
86
#include "debug.h"
87
88
float Button::mAlpha = 1.0;
89
90
3
static std::string const data[Button::BUTTON_COUNT] =
91
{
92
    ".xml",
93
    "_highlighted.xml",
94
    "_pressed.xml",
95
    "_disabled.xml"
96


9
};
97
98
24
Button::Button(const Widget2 *const widget,
99
24
               const std::string &restrict skinName) :
100
    Widget(widget),
101
    MouseListener(),
102
    KeyListener(),
103
    FocusListener(),
104
    WidgetListener(),
105
    mSkin(),
106
    mCaption(),
107
    mDescription(),
108
    mSkinName(skinName),
109
    mTextChunk(),
110

24
    mVertexes2(new ImageCollection),
111
48
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON, 255U)),
112
48
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE, 255U)),
113
48
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED, 255U)),
114
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE,
115
48
        255U)),
116
48
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED, 255U)),
117
    mHighlightedColor2(getThemeColor(
118
48
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE, 255U)),
119
48
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED, 255U)),
120
48
    mPressedColor2(getThemeColor(ThemeColorId::BUTTON_PRESSED_OUTLINE, 255U)),
121
    mImages(nullptr),
122
    mImageSet(nullptr),
123
    mAlignment(Graphics::CENTER),
124
    mClickCount(0),
125
    mSpacing(),
126
    mTag(0),
127
    mMode(0),
128
    mXOffset(0),
129
    mYOffset(0),
130
    mImageWidth(0),
131
    mImageHeight(0),
132
    mHasMouse(false),
133
    mKeyPressed(false),
134
    mMousePressed(false),
135
    mStick(false),
136
    mPressed(false),
137

408
    mTextChanged(true)
138
{
139
24
    init();
140
24
    adjustSize();
141
24
}
142
143
302
Button::Button(const Widget2 *const widget,
144
               const std::string &restrict caption,
145
               const std::string &restrict actionEventId,
146
               const std::string &restrict skinName,
147
302
               ActionListener *const listener) :
148
    Widget(widget),
149
    MouseListener(),
150
    KeyListener(),
151
    FocusListener(),
152
    WidgetListener(),
153
    mSkin(),
154
    mCaption(caption),
155
    mDescription(),
156
    mSkinName(skinName),
157
    mTextChunk(),
158

302
    mVertexes2(new ImageCollection),
159
604
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON, 255U)),
160
604
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE, 255U)),
161
604
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED, 255U)),
162
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE,
163
604
        255U)),
164
604
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED, 255U)),
165
    mHighlightedColor2(getThemeColor(
166
604
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE, 255U)),
167
604
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED, 255U)),
168
604
    mPressedColor2(getThemeColor(ThemeColorId::BUTTON_PRESSED_OUTLINE, 255U)),
169
    mImages(nullptr),
170
    mImageSet(nullptr),
171
    mAlignment(Graphics::CENTER),
172
    mClickCount(0),
173
    mSpacing(),
174
    mTag(0),
175
    mMode(0),
176
    mXOffset(0),
177
    mYOffset(0),
178
    mImageWidth(0),
179
    mImageHeight(0),
180
    mHasMouse(false),
181
    mKeyPressed(false),
182
    mMousePressed(false),
183
    mStick(false),
184
    mPressed(false),
185

5134
    mTextChanged(true)
186
{
187
302
    init();
188
302
    adjustSize();
189
604
    setActionEventId(actionEventId);
190
191
302
    if (listener != nullptr)
192
302
        addActionListener(listener);
193
302
}
194
195
Button::Button(const Widget2 *const widget,
196
               const std::string &restrict caption,
197
               const std::string &restrict imageName,
198
               const int imageWidth,
199
               const int imageHeight,
200
               const std::string &restrict actionEventId,
201
               const std::string &restrict skinName,
202
               ActionListener *const listener) :
203
    Widget(widget),
204
    MouseListener(),
205
    KeyListener(),
206
    FocusListener(),
207
    WidgetListener(),
208
    mSkin(),
209
    mCaption(caption),
210
    mDescription(),
211
    mSkinName(skinName),
212
    mTextChunk(),
213
    mVertexes2(new ImageCollection),
214
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON, 255U)),
215
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE, 255U)),
216
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED, 255U)),
217
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE,
218
        255U)),
219
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED, 255U)),
220
    mHighlightedColor2(getThemeColor(
221
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE, 255U)),
222
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED, 255U)),
223
    mPressedColor2(getThemeColor(ThemeColorId::BUTTON_PRESSED_OUTLINE, 255U)),
224
    mImages(nullptr),
225
    mImageSet(nullptr),
226
    mAlignment(Graphics::CENTER),
227
    mClickCount(0),
228
    mSpacing(),
229
    mTag(0),
230
    mMode(0),
231
    mXOffset(0),
232
    mYOffset(0),
233
    mImageWidth(imageWidth),
234
    mImageHeight(imageHeight),
235
    mHasMouse(false),
236
    mKeyPressed(false),
237
    mMousePressed(false),
238
    mStick(false),
239
    mPressed(false),
240
    mTextChanged(true)
241
{
242
    init();
243
    loadImageSet(imageName);
244
    adjustSize();
245
    setActionEventId(actionEventId);
246
247
    if (listener != nullptr)
248
        addActionListener(listener);
249
}
250
251
24
Button::Button(const Widget2 *const widget,
252
               const std::string &restrict imageName,
253
               const int imageWidth,
254
               const int imageHeight,
255
               const std::string &restrict actionEventId,
256
               const std::string &restrict skinName,
257
24
               ActionListener *const listener) :
258
    Widget(widget),
259
    MouseListener(),
260
    KeyListener(),
261
    FocusListener(),
262
    WidgetListener(),
263
    mSkin(),
264
    mCaption(),
265
    mDescription(),
266
    mSkinName(skinName),
267
    mTextChunk(),
268

24
    mVertexes2(new ImageCollection),
269
48
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON, 255U)),
270
48
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE, 255U)),
271
48
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED, 255U)),
272
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE,
273
48
        255U)),
274
48
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED, 255U)),
275
    mHighlightedColor2(getThemeColor(
276
48
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE, 255U)),
277
48
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED, 255U)),
278
48
    mPressedColor2(getThemeColor(ThemeColorId::BUTTON_PRESSED_OUTLINE, 255U)),
279
    mImages(nullptr),
280
    mImageSet(nullptr),
281
    mAlignment(Graphics::CENTER),
282
    mClickCount(0),
283
    mSpacing(),
284
    mTag(0),
285
    mMode(0),
286
    mXOffset(0),
287
    mYOffset(0),
288
    mImageWidth(imageWidth),
289
    mImageHeight(imageHeight),
290
    mHasMouse(false),
291
    mKeyPressed(false),
292
    mMousePressed(false),
293
    mStick(false),
294
    mPressed(false),
295

408
    mTextChanged(true)
296
{
297
24
    init();
298
24
    loadImageSet(imageName);
299
24
    adjustSize();
300
48
    setActionEventId(actionEventId);
301
302
24
    if (listener != nullptr)
303
24
        addActionListener(listener);
304
24
}
305
306
350
void Button::init()
307
{
308
350
    mAllowLogic = false;
309
350
    addMouseListener(this);
310
350
    addKeyListener(this);
311
350
    addFocusListener(this);
312
350
    addWidgetListener(this);
313
314
350
    setFocusable(true);
315
700
    setFrameSize(0);
316
317
350
    if (theme != nullptr)
318
    {
319
3150
        for (int mode = 0; mode < BUTTON_COUNT; mode ++)
320
        {
321

7000
            Skin *const skin = theme->load(mSkinName + data[mode],
322
                "button.xml",
323
                true,
324
2800
                Theme::getThemePath());
325
1400
            if (skin != nullptr)
326
            {
327
1400
                mSkin[mode] = skin;
328
5600
                mSpacing[mode] = skin->getOption("spacing");
329
            }
330
        }
331
    }
332
333
350
    updateAlpha();
334
350
}
335
336
3500
Button::~Button()
337
{
338
350
    if (mWindow != nullptr)
339
348
        mWindow->removeWidgetListener(this);
340
341
350
    if (gui != nullptr)
342
350
        gui->removeDragged(this);
343
344
350
    if (theme != nullptr)
345
    {
346
3150
        for (int mode = 0; mode < BUTTON_COUNT; mode ++)
347
1400
            theme->unload(mSkin[mode]);
348
    }
349
350
    delete2(mVertexes2);
350
350
    if (mImageSet != nullptr)
351
    {
352
24
        mImageSet->decRef();
353
24
        mImageSet = nullptr;
354
    }
355
350
    if (mImages != nullptr)
356
    {
357
216
        for (int f = 0; f < BUTTON_COUNT; f ++)
358
96
            mImages[f] = nullptr;
359
24
        delete [] mImages;
360
24
        mImages = nullptr;
361
    }
362
350
    mTextChunk.deleteImage();
363
700
}
364
365
void Button::loadImage(const std::string &imageName)
366
{
367
    if (mImageSet != nullptr)
368
    {
369
        mImageSet->decRef();
370
        mImageSet = nullptr;
371
    }
372
    Image *const image = Theme::getImageFromThemeXml(imageName, "");
373
    mImages = new Image*[BUTTON_COUNT];
374
    for (int f = 0; f < BUTTON_COUNT; f ++)
375
        mImages[f] = image;
376
}
377
378
void Button::setImage(Image *const image)
379
{
380
    if (image == nullptr)
381
        return;
382
    if (mImageSet != nullptr)
383
    {
384
        mImageSet->decRef();
385
        mImageSet = nullptr;
386
    }
387
    mImageWidth = image->getWidth();
388
    mImageHeight = image->getHeight();
389
    mImages = new Image*[BUTTON_COUNT];
390
    for (int f = 0; f < BUTTON_COUNT; f ++)
391
        mImages[f] = image;
392
}
393
394
24
void Button::loadImageSet(const std::string &imageName)
395
{
396
24
    if (mImageSet != nullptr)
397
    {
398
        mImageSet->decRef();
399
        mImageSet = nullptr;
400
    }
401
24
    mImageSet = Theme::getImageSetFromTheme(imageName,
402
        mImageWidth, mImageHeight);
403
24
    if (mImageSet == nullptr)
404
        return;
405
24
    mImages = new Image*[BUTTON_COUNT];
406
24
    mImages[0] = nullptr;
407
120
    for (size_t f = 0; f < BUTTON_COUNT; f ++)
408
    {
409
96
        Image *const img = mImageSet->get(f);
410
96
        if (img != nullptr)
411
96
            mImages[f] = img;
412
        else
413
            mImages[f] = mImages[0];
414
    }
415
}
416
417
453
void Button::updateAlpha()
418
{
419
    const float alpha = std::max(settings.guiAlpha,
420
1359
        theme->getMinimumOpacity());
421
422
453
    if (mAlpha != alpha)
423
    {
424
        mAlpha = alpha;
425
        for (int mode = 0; mode < BUTTON_COUNT; mode ++)
426
        {
427
            for (int a = 0; a < 9; a ++)
428
            {
429
                Skin *const skin = mSkin[mode];
430
                if (skin != nullptr)
431
                {
432
                    const ImageRect &rect = skin->getBorder();
433
                    Image *const image = rect.grid[a];
434
                    if (image != nullptr)
435
                        image->setAlpha(mAlpha);
436
                }
437
            }
438
        }
439
    }
440
453
}
441
442
103
void Button::draw(Graphics *const graphics)
443
{
444
    BLOCK_START("Button::draw")
445
    int mode;
446
447
103
    if (!isEnabled())
448
        mode = BUTTON_DISABLED;
449
73
    else if (isPressed2())
450
        mode = BUTTON_PRESSED;
451
73
    else if (mHasMouse)
452
        mode = BUTTON_HIGHLIGHTED;
453
    else
454
73
        mode = BUTTON_STANDARD;
455
456
103
    const Skin *const skin = mSkin[mode];
457
103
    if (skin == nullptr)
458
    {
459
        BLOCK_END("Button::draw")
460
        return;
461
    }
462
463
103
    updateAlpha();
464
465
103
    bool recalc = false;
466
103
    if (mRedraw)
467
    {
468
        recalc = true;
469
    }
470
    else
471
    {
472
        // because we don't know where parent windows was moved,
473
        // need recalc vertexes
474
        ClipRect &rect = graphics->getTopClip();
475
        if (rect.xOffset != mXOffset || rect.yOffset != mYOffset)
476
        {
477
            recalc = true;
478
            mXOffset = rect.xOffset;
479
            mYOffset = rect.yOffset;
480
        }
481
        else if (mMode != mode)
482
        {
483
            recalc = true;
484
            mMode = mode;
485
        }
486
        else if (graphics->getRedraw())
487
        {
488
            recalc = true;
489
        }
490
    }
491
492
103
    const int padding = skin->getPadding();
493
103
    const int spacing = mSpacing[mode];
494
495
103
    if (recalc)
496
103
        mTextChanged = true;
497
498
103
    int imageX = 0;
499
103
    int imageY = 0;
500
103
    int textX = 0;
501
103
    const Rect &rect = mDimension;
502
103
    const int width = rect.width;
503
103
    const int height = rect.height;
504
103
    Font *const font = getFont();
505
103
    int textY = height / 2 - font->getHeight() / 2;
506
103
    if (mImages != nullptr)
507
        imageY = height / 2 - mImageHeight / 2;
508
509
// need move calculation from draw!!!
510
511
103
    switch (mAlignment)
512
    {
513
        default:
514
        case Graphics::LEFT:
515
        {
516
            if (mImages != nullptr)
517
            {
518
                imageX = padding;
519
                textX = padding + mImageWidth + spacing;
520
            }
521
            else
522
            {
523
                textX = padding;
524
            }
525
            break;
526
        }
527
        case Graphics::CENTER:
528
        {
529
103
            const int width1 = font->getWidth(mCaption);
530
103
            if (mImages != nullptr)
531
            {
532
                const int w = width1 + mImageWidth + spacing;
533
                imageX = (width - w) / 2;
534
                textX = imageX + mImageWidth + spacing - width1 / 2;
535
            }
536
            else
537
            {
538
103
                textX = (width - width1) / 2;
539
            }
540
            break;
541
        }
542
        case Graphics::RIGHT:
543
        {
544
            const int width1 = font->getWidth(mCaption);
545
            textX = width - width1 - padding;
546
            imageX = textX - width1 - spacing;
547
            break;
548
        }
549
    }
550
551
103
    if (recalc)
552
    {
553
103
        mRedraw = false;
554
103
        mMode = mode;
555
103
        mVertexes2->clear();
556
103
        graphics->calcWindow(mVertexes2,
557
            0, 0,
558
            width, height,
559
206
            skin->getBorder());
560
561
103
        if (mImages != nullptr)
562
        {
563
            if (isPressed())
564
            {
565
                graphics->calcTileCollection(mVertexes2,
566
                    mImages[mode],
567
                    imageX + 1, imageY + 1);
568
            }
569
            else
570
            {
571
                graphics->calcTileCollection(mVertexes2,
572
                    mImages[mode],
573
                    imageX, imageY);
574
            }
575
        }
576
103
        graphics->finalize(mVertexes2);
577
    }
578
103
    graphics->drawTileCollection(mVertexes2);
579
580
103
    if (isPressed())
581
    {
582
        textX ++;
583
        textY ++;
584
    }
585
586
103
    if (mTextChanged)
587
    {
588
103
        mTextChunk.textFont = font;
589
103
        mTextChunk.deleteImage();
590
206
        mTextChunk.text = mCaption;
591

103
        switch (mode)
592
        {
593
            case BUTTON_DISABLED:
594
30
                mTextChunk.color = mDisabledColor;
595
30
                mTextChunk.color2 = mDisabledColor2;
596
30
                break;
597
            case BUTTON_PRESSED:
598
                mTextChunk.color = mPressedColor;
599
                mTextChunk.color2 = mPressedColor2;
600
                break;
601
            case BUTTON_HIGHLIGHTED:
602
                mTextChunk.color = mHighlightedColor;
603
                mTextChunk.color2 = mHighlightedColor2;
604
                break;
605
            default:
606
73
                mTextChunk.color = mEnabledColor;
607
73
                mTextChunk.color2 = mEnabledColor2;
608
73
                break;
609
        }
610
103
        font->generate(mTextChunk);
611
103
        mTextChanged = false;
612
    }
613
614
103
    const Image *const image = mTextChunk.img;
615
103
    if (image != nullptr)
616
101
        graphics->drawImage(image, textX, textY);
617
618
    BLOCK_END("Button::draw")
619
}
620
621
void Button::safeDraw(Graphics *const graphics)
622
{
623
    BLOCK_START("Button::safeDraw")
624
    int mode;
625
626
    if (!isEnabled())
627
        mode = BUTTON_DISABLED;
628
    else if (isPressed2())
629
        mode = BUTTON_PRESSED;
630
    else if (mHasMouse || isFocused())
631
        mode = BUTTON_HIGHLIGHTED;
632
    else
633
        mode = BUTTON_STANDARD;
634
635
    const Skin *const skin = mSkin[mode];
636
    if (skin == nullptr)
637
    {
638
        BLOCK_END("Button::safeDraw")
639
        return;
640
    }
641
642
    updateAlpha();
643
644
    if (mMode != mode)
645
    {
646
        mTextChanged = true;
647
        mMode = mode;
648
    }
649
650
    const int padding = skin->getPadding();
651
    const int spacing = mSpacing[mode];
652
653
    int imageX = 0;
654
    int imageY = 0;
655
    int textX = 0;
656
    const Rect &rect = mDimension;
657
    const int width = rect.width;
658
    const int height = rect.height;
659
    Font *const font = getFont();
660
    int textY = height / 2 - font->getHeight() / 2;
661
    if (mImages != nullptr)
662
        imageY = height / 2 - mImageHeight / 2;
663
664
// need move calculation from draw!!!
665
666
    switch (mAlignment)
667
    {
668
        default:
669
        case Graphics::LEFT:
670
        {
671
            if (mImages != nullptr)
672
            {
673
                imageX = padding;
674
                textX = padding + mImageWidth + spacing;
675
            }
676
            else
677
            {
678
                textX = padding;
679
            }
680
            break;
681
        }
682
        case Graphics::CENTER:
683
        {
684
            const int width1 = font->getWidth(mCaption);
685
            if (mImages != nullptr)
686
            {
687
                const int w = width1 + mImageWidth + spacing;
688
                imageX = (width - w) / 2;
689
                textX = imageX + mImageWidth + spacing - width1 / 2;
690
            }
691
            else
692
            {
693
                textX = (width - width1) / 2;
694
            }
695
            break;
696
        }
697
        case Graphics::RIGHT:
698
        {
699
            const int width1 = font->getWidth(mCaption);
700
            textX = width - width1 - padding;
701
            imageX = textX - width1 - spacing;
702
            break;
703
        }
704
    }
705
706
    graphics->drawImageRect(0, 0, width, height, skin->getBorder());
707
708
    if (mImages != nullptr)
709
    {
710
        if (isPressed())
711
            graphics->drawImage(mImages[mode], imageX + 1, imageY + 1);
712
        else
713
            graphics->drawImage(mImages[mode], imageX, imageY);
714
    }
715
716
    if (isPressed())
717
    {
718
        textX ++;
719
        textY ++;
720
    }
721
722
    if (mTextChanged)
723
    {
724
        mTextChunk.textFont = font;
725
        mTextChunk.deleteImage();
726
        mTextChunk.text = mCaption;
727
        switch (mode)
728
        {
729
            case BUTTON_DISABLED:
730
                mTextChunk.color = mDisabledColor;
731
                mTextChunk.color2 = mDisabledColor2;
732
                break;
733
            case BUTTON_PRESSED:
734
                mTextChunk.color = mPressedColor;
735
                mTextChunk.color2 = mPressedColor2;
736
                break;
737
            case BUTTON_HIGHLIGHTED:
738
                mTextChunk.color = mHighlightedColor;
739
                mTextChunk.color2 = mHighlightedColor2;
740
                break;
741
            default:
742
                mTextChunk.color = mEnabledColor;
743
                mTextChunk.color2 = mEnabledColor2;
744
                break;
745
        }
746
        font->generate(mTextChunk);
747
        mTextChanged = false;
748
    }
749
750
    const Image *const image = mTextChunk.img;
751
    if (image != nullptr)
752
        graphics->drawImage(image, textX, textY);
753
754
    BLOCK_END("Button::safeDraw")
755
}
756
757
void Button::mouseReleased(MouseEvent& event)
758
{
759
    if (event.getButton() == MouseButton::LEFT)
760
    {
761
        if (mStick)
762
            mPressed = !mPressed;
763
764
        if (mMousePressed && mHasMouse)
765
        {
766
            mMousePressed = false;
767
            mClickCount = event.getClickCount();
768
            distributeActionEvent();
769
        }
770
        else
771
        {
772
            mMousePressed = false;
773
            mClickCount = 0;
774
        }
775
        event.consume();
776
    }
777
}
778
779
931
void Button::widgetResized(const Event &event A_UNUSED)
780
{
781
931
    mRedraw = true;
782
931
}
783
784
634
void Button::widgetMoved(const Event &event A_UNUSED)
785
{
786
634
    mRedraw = true;
787
634
}
788
789
174
void Button::widgetHidden(const Event &event A_UNUSED)
790
{
791
174
    if (isBatchDrawRenders(openGLMode))
792
174
        mVertexes2->clear();
793
174
    mTextChunk.deleteImage();
794
174
    mRedraw = true;
795
174
    mTextChanged = true;
796
174
}
797
798
393
void Button::adjustSize()
799
{
800
393
    const Font *const font = getFont();
801
393
    const Skin *const skin = mSkin[BUTTON_STANDARD];
802
393
    if (skin == nullptr)
803
        return;
804
393
    const int padding = skin->getPadding();
805
806
393
    if (mImages != nullptr)
807
    {
808
24
        const int spacing = mSpacing[BUTTON_STANDARD];
809
24
        const int width = font->getWidth(mCaption);
810
24
        if (width != 0)
811
            setWidth(width + mImageWidth + spacing + 2 * padding);
812
        else
813
24
            setWidth(mImageWidth + 2 * padding);
814
24
        int height = font->getHeight();
815
24
        if (height < mImageHeight)
816
            height = mImageHeight;
817
24
        setHeight(height + 2 * padding);
818
    }
819
    else
820
    {
821
369
        setWidth(font->getWidth(mCaption) + 2 * padding);
822
369
        setHeight(font->getHeight() + 2 * padding);
823
    }
824
}
825
826
void Button::keyPressed(KeyEvent& event)
827
{
828
    const InputActionT action = event.getActionId();
829
830
    if (action == InputAction::GUI_SELECT)
831
    {
832
        mKeyPressed = true;
833
        event.consume();
834
    }
835
}
836
837
void Button::keyReleased(KeyEvent& event)
838
{
839
    const InputActionT action = event.getActionId();
840
841
    if (action == InputAction::GUI_SELECT && mKeyPressed)
842
    {
843
        mKeyPressed = false;
844
        if (mStick)
845
            mPressed = !mPressed;
846
        distributeActionEvent();
847
        event.consume();
848
    }
849
}
850
851
bool Button::isPressed2() const
852
{
853



146
    return mPressed || isPressed();
854
}
855
856
bool Button::isPressed() const
857
{
858




176
    if (mMousePressed)
859
        return mHasMouse;
860
176
    return mKeyPressed;
861
}
862
863
1
void Button::focusLost(const Event& event A_UNUSED)
864
{
865
1
    mMousePressed = false;
866
1
    mKeyPressed = false;
867
1
}
868
869
void Button::mousePressed(MouseEvent& event)
870
{
871
    if (event.getButton() == MouseButton::LEFT)
872
    {
873
        mMousePressed = true;
874
        event.consume();
875
    }
876
}
877
878
void Button::mouseEntered(MouseEvent& event A_UNUSED)
879
{
880
    mHasMouse = true;
881
}
882
883
void Button::mouseExited(MouseEvent& event A_UNUSED)
884
{
885
    mHasMouse = false;
886
}
887
888
void Button::mouseDragged(MouseEvent& event)
889
{
890
    event.consume();
891
}
892
893
331
void Button::setParent(Widget *widget)
894
{
895
331
    if (mWindow != nullptr)
896
329
        mWindow->addWidgetListener(this);
897
662
    Widget::setParent(widget);
898
331
}
899
900
2
void Button::setWindow(Widget *const widget)
901
{
902

2
    if ((widget == nullptr) && (mWindow != nullptr))
903
    {
904
2
        mWindow->removeWidgetListener(this);
905
2
        mWindow = nullptr;
906
    }
907
    else
908
    {
909
        Widget2::setWindow(widget);
910
    }
911

5
}