GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/tabs/tab.cpp Lines: 79 204 38.7 %
Date: 2018-07-14 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-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/tabs/tab.h"
67
68
#include "settings.h"
69
70
#include "gui/gui.h"
71
#include "gui/skin.h"
72
73
#include "gui/widgets/label.h"
74
#include "gui/widgets/tabbedarea.h"
75
76
#include "render/vertexes/imagecollection.h"
77
78
#include "resources/imagerect.h"
79
80
#include "resources/image/image.h"
81
82
#include "utils/delete2.h"
83
84
#include "debug.h"
85
86
int Tab::mInstances = 0;
87
float Tab::mAlpha = 1.0;
88
89
namespace
90
{
91
3
    std::string const data[Tab::TAB_COUNT] =
92
    {
93
        "tab.xml",
94
        "tab_highlighted.xml",
95
        "tab_selected.xml",
96
        "tab_unused.xml"
97


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

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

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

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

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

129
}