GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/button.cpp Lines: 206 415 49.6 %
Date: 2017-11-29 Branches: 96 294 32.7 %

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-2017  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
int Button::mInstances = 0;
89
float Button::mAlpha = 1.0;
90
91
6
static std::string const data[Button::BUTTON_COUNT] =
92
{
93
    "button.xml",
94
    "button_highlighted.xml",
95
    "button_pressed.xml",
96
    "button_disabled.xml"
97


18
};
98
99
Skin *Button::button[BUTTON_COUNT];
100
101
48
Button::Button(const Widget2 *const widget) :
102
    Widget(widget),
103
    MouseListener(),
104
    KeyListener(),
105
    FocusListener(),
106
    WidgetListener(),
107
    mCaption(),
108
    mDescription(),
109
    mTextChunk(),
110

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

768
    mTextChanged(true)
137
{
138
48
    init();
139
48
    adjustSize();
140
48
}
141
142
574
Button::Button(const Widget2 *const widget,
143
               const std::string &restrict caption,
144
               const std::string &restrict actionEventId,
145
574
               ActionListener *const listener) :
146
    Widget(widget),
147
    MouseListener(),
148
    KeyListener(),
149
    FocusListener(),
150
    WidgetListener(),
151
    mCaption(caption),
152
    mDescription(),
153
    mTextChunk(),
154

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

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

40
    mVertexes2(new ImageCollection),
255
80
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON)),
256
80
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE)),
257
80
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED)),
258
80
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE)),
259
80
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED)),
260
    mHighlightedColor2(getThemeColor(
261
80
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE)),
262
80
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED)),
263
80
    mPressedColor2(getThemeColor(ThemeColorId::BUTTON_PRESSED_OUTLINE)),
264
    mImages(nullptr),
265
    mImageSet(nullptr),
266
    mAlignment(Graphics::CENTER),
267
    mClickCount(0),
268
    mSpacing(),
269
    mTag(0),
270
    mMode(0),
271
    mXOffset(0),
272
    mYOffset(0),
273
    mImageWidth(imageWidth),
274
    mImageHeight(imageHeight),
275
    mHasMouse(false),
276
    mKeyPressed(false),
277
    mMousePressed(false),
278
    mStick(false),
279
    mPressed(false),
280

640
    mTextChanged(true)
281
{
282
40
    init();
283
40
    loadImageSet(imageName);
284
40
    adjustSize();
285
80
    setActionEventId(actionEventId);
286
287
40
    if (listener != nullptr)
288
40
        addActionListener(listener);
289
40
}
290
291
Button::Button(const Widget2 *const widget,
292
               const std::string &restrict caption,
293
               const std::string &restrict imageName,
294
               const std::string &restrict actionEventId,
295
               ActionListener *const listener) :
296
    Widget(widget),
297
    MouseListener(),
298
    KeyListener(),
299
    FocusListener(),
300
    WidgetListener(),
301
    mCaption(caption),
302
    mDescription(),
303
    mTextChunk(),
304
    mVertexes2(new ImageCollection),
305
    mEnabledColor(getThemeColor(ThemeColorId::BUTTON)),
306
    mEnabledColor2(getThemeColor(ThemeColorId::BUTTON_OUTLINE)),
307
    mDisabledColor(getThemeColor(ThemeColorId::BUTTON_DISABLED)),
308
    mDisabledColor2(getThemeColor(ThemeColorId::BUTTON_DISABLED_OUTLINE)),
309
    mHighlightedColor(getThemeColor(ThemeColorId::BUTTON_HIGHLIGHTED)),
310
    mHighlightedColor2(getThemeColor(
311
        ThemeColorId::BUTTON_HIGHLIGHTED_OUTLINE)),
312
    mPressedColor(getThemeColor(ThemeColorId::BUTTON_PRESSED)),
313
    mPressedColor2(getThemeColor(ThemeColorId::BUTTON_PRESSED_OUTLINE)),
314
    mImages(nullptr),
315
    mImageSet(nullptr),
316
    mAlignment(Graphics::CENTER),
317
    mClickCount(0),
318
    mSpacing(),
319
    mTag(0),
320
    mMode(0),
321
    mXOffset(0),
322
    mYOffset(0),
323
    mImageWidth(0),
324
    mImageHeight(0),
325
    mHasMouse(false),
326
    mKeyPressed(false),
327
    mMousePressed(false),
328
    mStick(false),
329
    mPressed(false),
330
    mTextChanged(true)
331
{
332
    init();
333
    loadImage(imageName);
334
    adjustSize();
335
    setActionEventId(actionEventId);
336
337
    if (listener != nullptr)
338
        addActionListener(listener);
339
}
340
341
662
void Button::init()
342
{
343
662
    mAllowLogic = false;
344
662
    addMouseListener(this);
345
662
    addKeyListener(this);
346
662
    addFocusListener(this);
347
662
    addWidgetListener(this);
348
349
662
    setFocusable(true);
350
1324
    setFrameSize(0);
351
352
662
    if (mInstances == 0)
353
    {
354
104
        if (theme != nullptr)
355
        {
356
936
            for (int mode = 0; mode < BUTTON_COUNT; mode ++)
357
            {
358

2496
                Skin *const skin = theme->load(data[mode], "button.xml");
359
416
                if (skin != nullptr)
360
                {
361
416
                    button[mode] = skin;
362

1664
                    mSpacing[mode] = skin->getOption("spacing");
363
                }
364
            }
365
        }
366
367
104
        updateAlpha();
368
    }
369
370
662
    mInstances++;
371
662
}
372
373
5958
Button::~Button()
374
{
375
662
    if (mWindow != nullptr)
376
658
        mWindow->removeWidgetListener(this);
377
378
662
    if (gui != nullptr)
379
662
        gui->removeDragged(this);
380
381
662
    mInstances--;
382
383

662
    if (mInstances == 0 && (theme != nullptr))
384
    {
385
936
        for (int mode = 0; mode < BUTTON_COUNT; mode ++)
386
416
            theme->unload(button[mode]);
387
    }
388
662
    delete2(mVertexes2);
389
662
    if (mImageSet != nullptr)
390
    {
391
40
        mImageSet->decRef();
392
40
        mImageSet = nullptr;
393
    }
394
662
    if (mImages != nullptr)
395
    {
396
360
        for (int f = 0; f < BUTTON_COUNT; f ++)
397
160
            mImages[f] = nullptr;
398
40
        delete [] mImages;
399
40
        mImages = nullptr;
400
    }
401
662
    mTextChunk.deleteImage();
402
1324
}
403
404
void Button::loadImage(const std::string &imageName)
405
{
406
    if (mImageSet != nullptr)
407
    {
408
        mImageSet->decRef();
409
        mImageSet = nullptr;
410
    }
411
    Image *const image = Theme::getImageFromThemeXml(imageName, "");
412
    mImages = new Image*[BUTTON_COUNT];
413
    for (int f = 0; f < BUTTON_COUNT; f ++)
414
        mImages[f] = image;
415
}
416
417
40
void Button::loadImageSet(const std::string &imageName)
418
{
419
40
    if (mImageSet != nullptr)
420
    {
421
        mImageSet->decRef();
422
        mImageSet = nullptr;
423
    }
424
40
    mImageSet = Theme::getImageSetFromTheme(imageName,
425
        mImageWidth, mImageHeight);
426
40
    if (mImageSet == nullptr)
427
        return;
428
40
    mImages = new Image*[BUTTON_COUNT];
429
40
    mImages[0] = nullptr;
430
200
    for (size_t f = 0; f < BUTTON_COUNT; f ++)
431
    {
432
160
        Image *const img = mImageSet->get(f);
433
160
        if (img != nullptr)
434
160
            mImages[f] = img;
435
        else
436
            mImages[f] = mImages[0];
437
    }
438
}
439
440
308
void Button::updateAlpha()
441
{
442
    const float alpha = std::max(settings.guiAlpha,
443
924
        theme->getMinimumOpacity());
444
445
308
    if (mAlpha != alpha)
446
    {
447
        mAlpha = alpha;
448
        for (int mode = 0; mode < BUTTON_COUNT; mode ++)
449
        {
450
            for (int a = 0; a < 9; a ++)
451
            {
452
                Skin *const skin = button[mode];
453
                if (skin != nullptr)
454
                {
455
                    const ImageRect &rect = skin->getBorder();
456
                    Image *const image = rect.grid[a];
457
                    if (image != nullptr)
458
                        image->setAlpha(mAlpha);
459
                }
460
            }
461
        }
462
    }
463
308
}
464
465
204
void Button::draw(Graphics *const graphics)
466
{
467
    BLOCK_START("Button::draw")
468
    int mode;
469
470
204
    if (!isEnabled())
471
        mode = BUTTON_DISABLED;
472
144
    else if (isPressed2())
473
        mode = BUTTON_PRESSED;
474
144
    else if (mHasMouse)
475
        mode = BUTTON_HIGHLIGHTED;
476
    else
477
144
        mode = BUTTON_STANDARD;
478
479
204
    const Skin *const skin = button[mode];
480
204
    if (skin == nullptr)
481
    {
482
        BLOCK_END("Button::draw")
483
        return;
484
    }
485
486
204
    updateAlpha();
487
488
204
    bool recalc = false;
489
204
    if (mRedraw)
490
    {
491
        recalc = true;
492
    }
493
    else
494
    {
495
        // because we don't know where parent windows was moved,
496
        // need recalc vertexes
497
        ClipRect &rect = graphics->getTopClip();
498
        if (rect.xOffset != mXOffset || rect.yOffset != mYOffset)
499
        {
500
            recalc = true;
501
            mXOffset = rect.xOffset;
502
            mYOffset = rect.yOffset;
503
        }
504
        else if (mMode != mode)
505
        {
506
            recalc = true;
507
            mMode = mode;
508
        }
509
        else if (graphics->getRedraw())
510
        {
511
            recalc = true;
512
        }
513
    }
514
515
204
    const int padding = skin->getPadding();
516
204
    const int spacing = mSpacing[mode];
517
518
204
    if (recalc)
519
204
        mTextChanged = true;
520
521
204
    int imageX = 0;
522
204
    int imageY = 0;
523
204
    int textX = 0;
524
204
    const Rect &rect = mDimension;
525
204
    const int width = rect.width;
526
204
    const int height = rect.height;
527
204
    Font *const font = getFont();
528
204
    int textY = height / 2 - font->getHeight() / 2;
529
204
    if (mImages != nullptr)
530
        imageY = height / 2 - mImageHeight / 2;
531
532
// need move calculation from draw!!!
533
534
204
    switch (mAlignment)
535
    {
536
        default:
537
        case Graphics::LEFT:
538
        {
539
            if (mImages != nullptr)
540
            {
541
                imageX = padding;
542
                textX = padding + mImageWidth + spacing;
543
            }
544
            else
545
            {
546
                textX = padding;
547
            }
548
            break;
549
        }
550
204
        case Graphics::CENTER:
551
        {
552
204
            const int width1 = font->getWidth(mCaption);
553
204
            if (mImages != nullptr)
554
            {
555
                const int w = width1 + mImageWidth + spacing;
556
                imageX = (width - w) / 2;
557
                textX = imageX + mImageWidth + spacing - width1 / 2;
558
            }
559
            else
560
            {
561
204
                textX = (width - width1) / 2;
562
            }
563
            break;
564
        }
565
        case Graphics::RIGHT:
566
        {
567
            const int width1 = font->getWidth(mCaption);
568
            textX = width - width1 - padding;
569
            imageX = textX - width1 - spacing;
570
            break;
571
        }
572
    }
573
574
204
    if (recalc)
575
    {
576
204
        mRedraw = false;
577
204
        mMode = mode;
578
204
        mVertexes2->clear();
579
204
        graphics->calcWindow(mVertexes2,
580
            0, 0,
581
            width, height,
582
204
            skin->getBorder());
583
584
204
        if (mImages != nullptr)
585
        {
586
            if (isPressed())
587
            {
588
                graphics->calcTileCollection(mVertexes2,
589
                    mImages[mode],
590
                    imageX + 1, imageY + 1);
591
            }
592
            else
593
            {
594
                graphics->calcTileCollection(mVertexes2,
595
                    mImages[mode],
596
                    imageX, imageY);
597
            }
598
        }
599
204
        graphics->finalize(mVertexes2);
600
    }
601
204
    graphics->drawTileCollection(mVertexes2);
602
603
204
    if (isPressed())
604
    {
605
        textX ++;
606
        textY ++;
607
    }
608
609
204
    if (mTextChanged)
610
    {
611
204
        mTextChunk.textFont = font;
612
204
        mTextChunk.deleteImage();
613
408
        mTextChunk.text = mCaption;
614

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



288
    return mPressed || isPressed();
877
}
878
879
bool Button::isPressed() const
880
{
881




348
    if (mMousePressed)
882
        return mHasMouse;
883
348
    return mKeyPressed;
884
}
885
886
2
void Button::focusLost(const Event& event A_UNUSED)
887
{
888
2
    mMousePressed = false;
889
2
    mKeyPressed = false;
890
2
}
891
892
void Button::mousePressed(MouseEvent& event)
893
{
894
    if (event.getButton() == MouseButton::LEFT)
895
    {
896
        mMousePressed = true;
897
        event.consume();
898
    }
899
}
900
901
void Button::mouseEntered(MouseEvent& event A_UNUSED)
902
{
903
    mHasMouse = true;
904
}
905
906
void Button::mouseExited(MouseEvent& event A_UNUSED)
907
{
908
    mHasMouse = false;
909
}
910
911
void Button::mouseDragged(MouseEvent& event)
912
{
913
    event.consume();
914
}
915
916
628
void Button::setParent(Widget *widget)
917
{
918
628
    if (mWindow != nullptr)
919
624
        mWindow->addWidgetListener(this);
920
1256
    Widget::setParent(widget);
921
628
}
922
923
4
void Button::setWindow(Widget *const widget)
924
{
925

4
    if ((widget == nullptr) && (mWindow != nullptr))
926
    {
927
4
        mWindow->removeWidgetListener(this);
928
4
        mWindow = nullptr;
929
    }
930
    else
931
    {
932
        Widget2::setWindow(widget);
933
    }
934

10
}