GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/button.cpp Lines: 205 396 51.8 %
Date: 2018-05-19 03:07:18 Branches: 99 282 35.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
6
static std::string const data[Button::BUTTON_COUNT] =
91
{
92
    ".xml",
93
    "_highlighted.xml",
94
    "_pressed.xml",
95
    "_disabled.xml"
96


18
};
97
98
48
Button::Button(const Widget2 *const widget,
99
48
               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

48
    mVertexes2(new ImageCollection),
111
96
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON, 255U)),
112
96
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE, 255U)),
113
96
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED, 255U)),
114
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE,
115
96
        255U)),
116
96
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED, 255U)),
117
    mHighlightedColor2(getThemeColor(
118
96
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE, 255U)),
119
96
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED, 255U)),
120
96
    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

816
    mTextChanged(true)
138
{
139
48
    init();
140
48
    adjustSize();
141
48
}
142
143
596
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
596
               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

596
    mVertexes2(new ImageCollection),
159
1192
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON, 255U)),
160
1192
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE, 255U)),
161
1192
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED, 255U)),
162
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE,
163
1192
        255U)),
164
1192
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED, 255U)),
165
    mHighlightedColor2(getThemeColor(
166
1192
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE, 255U)),
167
1192
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED, 255U)),
168
1192
    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

10132
    mTextChanged(true)
186
{
187
596
    init();
188
596
    adjustSize();
189
1192
    setActionEventId(actionEventId);
190
191
596
    if (listener != nullptr)
192
596
        addActionListener(listener);
193
596
}
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
48
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
48
               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

48
    mVertexes2(new ImageCollection),
269
96
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON, 255U)),
270
96
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE, 255U)),
271
96
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED, 255U)),
272
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE,
273
96
        255U)),
274
96
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED, 255U)),
275
    mHighlightedColor2(getThemeColor(
276
96
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE, 255U)),
277
96
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED, 255U)),
278
96
    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

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

16608
            Skin *const skin = theme->load(mSkinName + data[mode],
322
                "button.xml",
323
                true,
324
5536
                Theme::getThemePath());
325
2768
            if (skin != nullptr)
326
            {
327
2768
                mSkin[mode] = skin;
328

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

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



292
    return mPressed || isPressed();
838
}
839
840
bool Button::isPressed() const
841
{
842




352
    if (mMousePressed)
843
        return mHasMouse;
844
352
    return mKeyPressed;
845
}
846
847
2
void Button::focusLost(const Event& event A_UNUSED)
848
{
849
2
    mMousePressed = false;
850
2
    mKeyPressed = false;
851
2
}
852
853
void Button::mousePressed(MouseEvent& event)
854
{
855
    if (event.getButton() == MouseButton::LEFT)
856
    {
857
        mMousePressed = true;
858
        event.consume();
859
    }
860
}
861
862
void Button::mouseEntered(MouseEvent& event A_UNUSED)
863
{
864
    mHasMouse = true;
865
}
866
867
void Button::mouseExited(MouseEvent& event A_UNUSED)
868
{
869
    mHasMouse = false;
870
}
871
872
void Button::mouseDragged(MouseEvent& event)
873
{
874
    event.consume();
875
}
876
877
654
void Button::setParent(Widget *widget)
878
{
879
654
    if (mWindow != nullptr)
880
650
        mWindow->addWidgetListener(this);
881
1308
    Widget::setParent(widget);
882
654
}
883
884
4
void Button::setWindow(Widget *const widget)
885
{
886

4
    if ((widget == nullptr) && (mWindow != nullptr))
887
    {
888
4
        mWindow->removeWidgetListener(this);
889
4
        mWindow = nullptr;
890
    }
891
    else
892
    {
893
        Widget2::setWindow(widget);
894
    }
895

10
}