GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/tabs/tab.cpp Lines: 79 204 38.7 %
Date: 2021-03-17 Branches: 36 130 27.7 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2008-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/tabs/tab.h"
68
69
#include "settings.h"
70
71
#include "gui/gui.h"
72
#include "gui/skin.h"
73
74
#include "gui/widgets/label.h"
75
#include "gui/widgets/tabbedarea.h"
76
77
#include "render/vertexes/imagecollection.h"
78
79
#include "resources/imagerect.h"
80
81
#include "resources/image/image.h"
82
83
#include "utils/delete2.h"
84
85
#include "debug.h"
86
87
int Tab::mInstances = 0;
88
float Tab::mAlpha = 1.0;
89
90
namespace
91
{
92
3
    std::string const data[Tab::TAB_COUNT] =
93
    {
94
        "tab.xml",
95
        "tab_highlighted.xml",
96
        "tab_selected.xml",
97
        "tab_unused.xml"
98


9
    };
99
}  // namespace
100
101
Skin *Tab::tabImg[Tab::TAB_COUNT];
102
103
49
Tab::Tab(const Widget2 *const widget) :
104
    BasicContainer(widget),
105
    MouseListener(),
106
    WidgetListener(),
107

49
    mLabel(new Label(this)),
108
    mTabbedArea(nullptr),
109
98
    mTabColor(&getThemeColor(ThemeColorId::TAB, 255U)),
110
98
    mTabOutlineColor(&getThemeColor(ThemeColorId::TAB_OUTLINE, 255U)),
111
98
    mTabHighlightedColor(&getThemeColor(ThemeColorId::TAB_HIGHLIGHTED, 255U)),
112
    mTabHighlightedOutlineColor(&getThemeColor(
113
98
        ThemeColorId::TAB_HIGHLIGHTED_OUTLINE, 255U)),
114
98
    mTabSelectedColor(&getThemeColor(ThemeColorId::TAB_SELECTED, 255U)),
115
    mTabSelectedOutlineColor(&getThemeColor(
116
98
        ThemeColorId::TAB_SELECTED_OUTLINE, 255U)),
117
98
    mFlashColor(&getThemeColor(ThemeColorId::TAB_FLASH, 255U)),
118
98
    mFlashOutlineColor(&getThemeColor(ThemeColorId::TAB_FLASH_OUTLINE, 255U)),
119
98
    mPlayerFlashColor(&getThemeColor(ThemeColorId::TAB_PLAYER_FLASH, 255U)),
120
    mPlayerFlashOutlineColor(&getThemeColor(
121
98
        ThemeColorId::TAB_PLAYER_FLASH_OUTLINE, 255U)),
122
    mFlash(0),
123

49
    mVertexes(new ImageCollection),
124
    mImage(nullptr),
125
    mMode(0),
126
    mLabelMode(-1),
127
784
    mHasMouse(false)
128
{
129
49
    init();
130
49
}
131
132
239
Tab::~Tab()
133
{
134
49
    if (gui != nullptr)
135
49
        gui->removeDragged(this);
136
137
49
    mInstances--;
138

49
    if (mInstances == 0 && (theme != nullptr))
139
    {
140
63
        for (int mode = 0; mode < TAB_COUNT; mode ++)
141
28
            theme->unload(tabImg[mode]);
142
    }
143
144
49
    delete2(mLabel)
145
146
49
    if (mImage != nullptr)
147
    {
148
        mImage->decRef();
149
        mImage = nullptr;
150
    }
151
49
    delete2(mVertexes)
152
92
}
153
154
49
void Tab::init()
155
{
156
49
    addMouseListener(this);
157
49
    setFocusable(false);
158
98
    setFrameSize(0);
159
49
    mFlash = 0;
160
161
49
    addWidgetListener(this);
162
163
49
    if (mInstances == 0)
164
    {
165
        // Load the skin
166
7
        if (theme != nullptr)
167
        {
168
63
            for (int mode = 0; mode < TAB_COUNT; mode ++)
169
            {
170

112
                tabImg[mode] = theme->load(data[mode],
171
                    "tab.xml",
172
                    true,
173
28
                    Theme::getThemePath());
174
            }
175
        }
176
7
        updateAlpha();
177
    }
178
49
    mInstances++;
179
180
49
    add(mLabel);
181
182
49
    const Skin *const skin = tabImg[TAB_STANDARD];
183
49
    if (skin == nullptr)
184
        return;
185
49
    const int padding = skin->getPadding();
186
187
49
    mLabel->setPosition(padding, padding);
188
}
189
190
7
void Tab::updateAlpha()
191
{
192
    const float alpha = std::max(settings.guiAlpha,
193
21
        theme->getMinimumOpacity());
194
195
7
    if (alpha != mAlpha)
196
    {
197
        mAlpha = alpha;
198
        for (int a = 0; a < 9; a++)
199
        {
200
            for (int t = 0; t < TAB_COUNT; t++)
201
            {
202
                Skin *const skin = tabImg[t];
203
                if (skin != nullptr)
204
                {
205
                    const ImageRect &rect = skin->getBorder();
206
                    Image *const image = rect.grid[a];
207
                    if (image != nullptr)
208
                        image->setAlpha(mAlpha);
209
                }
210
            }
211
        }
212
    }
213
7
}
214
215
void Tab::draw(Graphics *const graphics)
216
{
217
    BLOCK_START("Tab::draw")
218
    int mode = TAB_STANDARD;
219
220
    // check which type of tab to draw
221
    if (mTabbedArea != nullptr)
222
    {
223
        int labelMode = mFlash;
224
225
        if (mTabbedArea->isTabSelected(this))
226
        {
227
            labelMode = 3;
228
            mode = TAB_SELECTED;
229
            // if tab is selected, it doesnt need to highlight activity
230
            mFlash = 0;
231
        }
232
        else if (labelMode == 0)
233
        {
234
            if (mHasMouse)
235
            {
236
                labelMode = 4;
237
                mode = TAB_HIGHLIGHTED;
238
            }
239
        }
240
        else if (mHasMouse)
241
        {
242
            mode = TAB_HIGHLIGHTED;
243
        }
244
245
        // mRedraw need here because no other way to say label to change color
246
        // +++ text from label must be moved to tab itself
247
        if (labelMode != mLabelMode || mRedraw)
248
        {
249
            mLabelMode = labelMode;
250
            switch (labelMode)
251
            {
252
                case 0:  // default state
253
                default:
254
                    mLabel->setForegroundColorAll(*mTabColor,
255
                        *mTabOutlineColor);
256
                    break;
257
                case 1:  // mFlash == 1
258
                    mLabel->setForegroundColorAll(*mFlashColor,
259
                        *mFlashOutlineColor);
260
                    break;
261
                case 2:  // mFlash == 2
262
                    mLabel->setForegroundColorAll(*mPlayerFlashColor,
263
                        *mPlayerFlashOutlineColor);
264
                    break;
265
                case 3:  // mTabbedArea->isTabSelected(this)
266
                    mLabel->setForegroundColorAll(*mTabSelectedColor,
267
                        *mTabSelectedOutlineColor);
268
                    break;
269
                case 4:  // mHasMouse
270
                    mLabel->setForegroundColorAll(*mTabHighlightedColor,
271
                        *mTabHighlightedOutlineColor);
272
                    break;
273
            }
274
        }
275
    }
276
277
    const Skin *const skin = tabImg[mode];
278
    if (skin == nullptr)
279
    {
280
        BLOCK_END("Tab::draw")
281
        return;
282
    }
283
284
    updateAlpha();
285
286
    const ImageRect &rect = skin->getBorder();
287
    if (mRedraw || mode != mMode || graphics->getRedraw())
288
    {
289
        mMode = mode;
290
        mRedraw = false;
291
        mVertexes->clear();
292
        graphics->calcWindow(mVertexes,
293
            0, 0,
294
            mDimension.width, mDimension.height,
295
            rect);
296
297
        if (mImage != nullptr)
298
        {
299
            const Skin *const skin1 = tabImg[TAB_STANDARD];
300
            if (skin1 != nullptr)
301
            {
302
                const int padding = skin1->getPadding();
303
                graphics->calcTileCollection(mVertexes,
304
                    mImage,
305
                    padding,
306
                    padding);
307
            }
308
        }
309
        graphics->finalize(mVertexes);
310
    }
311
312
    graphics->drawTileCollection(mVertexes);
313
314
    drawChildren(graphics);
315
    BLOCK_END("Tab::draw")
316
}
317
318
void Tab::safeDraw(Graphics *const graphics)
319
{
320
    BLOCK_START("Tab::draw")
321
    int mode = TAB_STANDARD;
322
323
    // check which type of tab to draw
324
    if (mTabbedArea != nullptr)
325
    {
326
        int labelMode = mFlash;
327
328
        if (mTabbedArea->isTabSelected(this))
329
        {
330
            labelMode = 3;
331
            mode = TAB_SELECTED;
332
            // if tab is selected, it doesnt need to highlight activity
333
            mFlash = 0;
334
        }
335
        else if (labelMode == 0)
336
        {
337
            if (mHasMouse)
338
            {
339
                labelMode = 4;
340
                mode = TAB_HIGHLIGHTED;
341
            }
342
        }
343
        else if (mHasMouse)
344
        {
345
            mode = TAB_HIGHLIGHTED;
346
        }
347
348
        if (labelMode != mLabelMode)
349
        {
350
            mLabelMode = labelMode;
351
            switch (labelMode)
352
            {
353
                case 0:  // default state
354
                default:
355
                    mLabel->setForegroundColorAll(*mTabColor,
356
                        *mTabOutlineColor);
357
                    break;
358
                case 1:  // mFlash == 1
359
                    mLabel->setForegroundColorAll(*mFlashColor,
360
                        *mFlashOutlineColor);
361
                    break;
362
                case 2:  // mFlash == 2
363
                    mLabel->setForegroundColorAll(*mPlayerFlashColor,
364
                        *mPlayerFlashOutlineColor);
365
                    break;
366
                case 3:  // mTabbedArea->isTabSelected(this)
367
                    mLabel->setForegroundColorAll(*mTabSelectedColor,
368
                        *mTabSelectedOutlineColor);
369
                    break;
370
                case 4:  // mHasMouse
371
                    mLabel->setForegroundColorAll(*mTabHighlightedColor,
372
                        *mTabHighlightedOutlineColor);
373
                    break;
374
            }
375
        }
376
    }
377
378
    const Skin *const skin = tabImg[mode];
379
    if (skin == nullptr)
380
    {
381
        BLOCK_END("Tab::draw")
382
        return;
383
    }
384
385
    updateAlpha();
386
387
    graphics->drawImageRect(0, 0,
388
        mDimension.width, mDimension.height,
389
        skin->getBorder());
390
    if (mImage != nullptr)
391
    {
392
        const Skin *const skin1 = tabImg[TAB_STANDARD];
393
        if (skin1 != nullptr)
394
        {
395
            const int padding = skin1->getPadding();
396
            graphics->drawImage(mImage, padding, padding);
397
        }
398
    }
399
400
    safeDrawChildren(graphics);
401
    BLOCK_END("Tab::draw")
402
}
403
404
49
void Tab::widgetResized(const Event &event A_UNUSED)
405
{
406
49
    mRedraw = true;
407
49
}
408
409
62
void Tab::widgetMoved(const Event &event A_UNUSED)
410
{
411
62
    mRedraw = true;
412
62
}
413
414
void Tab::setLabelFont(Font *const font)
415
{
416
    if (mLabel == nullptr)
417
        return;
418
419
    mLabel->setFont(font);
420
    mLabel->adjustSize();
421
    adjustSize();
422
    mRedraw = true;
423
}
424
425
426
49
void Tab::adjustSize()
427
{
428
49
    const Skin *const skin = tabImg[TAB_STANDARD];
429
49
    if (skin == nullptr)
430
        return;
431
49
    const int pad2 = skin->getPadding() * 2;
432
433
49
    if (mImage != nullptr)
434
    {
435
        const SDL_Rect &rect = mImage->mBounds;
436
        setSize(rect.w + pad2, rect.h + pad2);
437
    }
438
    else
439
    {
440
98
        setSize(mLabel->getWidth() + pad2,
441
147
                mLabel->getHeight() + pad2);
442
    }
443
444
49
    if (mTabbedArea != nullptr)
445
        mTabbedArea->adjustTabPositions();
446
}
447
448
49
void Tab::setTabbedArea(TabbedArea* tabbedArea)
449
{
450
49
    mTabbedArea = tabbedArea;
451
49
}
452
453
TabbedArea* Tab::getTabbedArea() const
454
{
455
    return mTabbedArea;
456
}
457
458
49
void Tab::setCaption(const std::string &caption)
459
{
460
49
    mLabel->setCaption(caption);
461
49
    mLabel->adjustSize();
462
49
    adjustSize();
463
49
}
464
465
void Tab::setImage(Image *const image)
466
{
467
    if (mImage != nullptr)
468
        mImage->decRef();
469
    mImage = image;
470
    adjustSize();
471
}
472
473
384
const std::string &Tab::getCaption() const
474
{
475
768
    return mLabel->getCaption();
476
}
477
478
void Tab::mouseEntered(MouseEvent& event A_UNUSED)
479
{
480
    mHasMouse = true;
481
}
482
483
void Tab::mouseExited(MouseEvent& event A_UNUSED)
484
{
485
    mHasMouse = false;
486
}
487
488
127
void Tab::finalCleanup()
489
{
490
635
    for (int f = 0; f < TAB_COUNT; f ++)
491
    {
492
508
        tabImg[f] = nullptr;
493
    }
494

130
}