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


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

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

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

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

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

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

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

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

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



146
    return mPressed || isPressed();
859
}
860
861
bool Button::isPressed() const
862
{
863




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

2
    if ((widget == nullptr) && (mWindow != nullptr))
908
    {
909
2
        mWindow->removeWidgetListener(this);
910
2
        mWindow = nullptr;
911
    }
912
    else
913
    {
914
        Widget2::setWindow(widget);
915
    }
916

5
}