GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/progressbar.cpp Lines: 100 190 52.6 %
Date: 2021-03-17 Branches: 40 142 28.2 %

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
#include "gui/widgets/progressbar.h"
25
26
#include "settings.h"
27
28
#include "gui/gui.h"
29
#include "gui/skin.h"
30
31
#include "gui/fonts/font.h"
32
33
#include "utils/delete2.h"
34
35
#include "render/graphics.h"
36
37
#include "render/vertexes/imagecollection.h"
38
39
#include "debug.h"
40
41
int ProgressBar::mInstances = 0;
42
float ProgressBar::mAlpha = 1.0;
43
44
16
ProgressBar::ProgressBar(const Widget2 *const widget,
45
                         float progress,
46
                         const int width,
47
                         const int height,
48
                         const ProgressColorIdT backColor,
49
                         const std::string &skin,
50
16
                         const std::string &skinFill) :
51
    Widget(widget),
52
    WidgetListener(),
53
    mFillRect(),
54
    mTextChunk(),
55
    mSkin(nullptr),
56
    mProgress(progress),
57
    mProgressToGo(progress),
58
    mBackgroundColorToGo(),
59
    mText(),
60

16
    mVertexes(new ImageCollection),
61
    mProgressPalette(backColor),
62
    mPadding(2),
63
    mFillPadding(3),
64
    mFillImage(false),
65
    mSmoothProgress(true),
66
    mSmoothColorChange(true),
67
96
    mTextChanged(true)
68
{
69
    mBackgroundColor = Theme::getProgressColor(
70
        backColor >= ProgressColorId::PROG_HP
71
        ? backColor : ProgressColorId::PROG_HP,
72

16
        mProgress);
73
16
    mBackgroundColorToGo = mBackgroundColor;
74
16
    mForegroundColor2 = getThemeColor(ThemeColorId::PROGRESS_BAR_OUTLINE,
75
32
        255U);
76
77
    // The progress value is directly set at load time:
78

16
    if (mProgress > 1.0F || mProgress < 0.0F)
79
1
        mProgress = 1.0F;
80
81
32
    mForegroundColor = getThemeColor(ThemeColorId::PROGRESS_BAR, 255U);
82
16
    addWidgetListener(this);
83
16
    setSize(width, height);
84
85
16
    if (theme != nullptr)
86
    {
87

64
        mSkin = theme->load(skin,
88
            "progressbar.xml",
89
            true,
90
16
            Theme::getThemePath());
91
16
        if (mSkin != nullptr)
92
        {
93
48
            setPadding(mSkin->getPadding());
94

64
            mFillPadding = mSkin->getOption("fillPadding");
95

64
            mFillImage = mSkin->getOption("fillImage") != 0;
96
16
            if (mFillImage)
97
            {
98
                theme->loadRect(mFillRect,
99
                    skinFill,
100
                    "progressbar_fill.xml",
101
                    0,
102
                    8);
103
            }
104
        }
105

16
        setHeight(2 * mPadding + getFont()->getHeight() + 2);
106
    }
107
108
16
    mInstances++;
109
16
}
110
111
80
ProgressBar::~ProgressBar()
112
{
113
16
    if (gui != nullptr)
114
16
        gui->removeDragged(this);
115
116
16
    mInstances--;
117
16
    if (mSkin != nullptr)
118
    {
119
16
        if (theme != nullptr)
120
16
            theme->unload(mSkin);
121
16
        mSkin = nullptr;
122
    }
123
16
    Theme::unloadRect(mFillRect, 0, 8);
124
16
    delete2(mVertexes)
125
16
    mTextChunk.deleteImage();
126
32
}
127
128
void ProgressBar::logic()
129
{
130
    BLOCK_START("ProgressBar::logic")
131
    if (mSmoothColorChange && mBackgroundColorToGo != mBackgroundColor)
132
    {
133
        // Smoothly changing the color for a nicer effect.
134
        if (mBackgroundColorToGo.r > mBackgroundColor.r)
135
            mBackgroundColor.r++;
136
        if (mBackgroundColorToGo.g > mBackgroundColor.g)
137
            mBackgroundColor.g++;
138
        if (mBackgroundColorToGo.b > mBackgroundColor.b)
139
            mBackgroundColor.b++;
140
        if (mBackgroundColorToGo.r < mBackgroundColor.r)
141
            mBackgroundColor.r--;
142
        if (mBackgroundColorToGo.g < mBackgroundColor.g)
143
            mBackgroundColor.g--;
144
        if (mBackgroundColorToGo.b < mBackgroundColor.b)
145
            mBackgroundColor.b--;
146
        mRedraw = true;
147
    }
148
149
    if (mSmoothProgress && mProgressToGo != mProgress)
150
    {
151
        // Smoothly showing the progressbar changes.
152
        if (mProgressToGo > mProgress)
153
            mProgress = std::min(1.0F, mProgress + 0.005F);
154
        if (mProgressToGo < mProgress)
155
            mProgress = std::max(0.0F, mProgress - 0.005F);
156
        mRedraw = true;
157
    }
158
    BLOCK_END("ProgressBar::logic")
159
}
160
161
void ProgressBar::updateAlpha()
162
{
163
    const float alpha = std::max(settings.guiAlpha,
164
15
        theme->getMinimumOpacity());
165
5
    mAlpha = alpha;
166
}
167
168
5
void ProgressBar::draw(Graphics *const graphics)
169
{
170
    BLOCK_START("ProgressBar::draw")
171
5
    if (mSkin == nullptr)
172
    {
173
        BLOCK_END("ProgressBar::draw")
174
        return;
175
    }
176
177
5
    updateAlpha();
178
5
    mBackgroundColor.a = CAST_U32(mAlpha * 255);
179
180

5
    if (mRedraw || graphics->getRedraw())
181
    {
182
5
        mRedraw = false;
183
5
        mVertexes->clear();
184
5
        graphics->calcWindow(mVertexes, 0, 0,
185
10
            mDimension.width, mDimension.height, mSkin->getBorder());
186
5
        if (mFillImage)
187
        {
188
            const unsigned int pad = 2 * mFillPadding;
189
            const int maxWidth = mDimension.width - pad;
190
            int width = CAST_S32(mProgress
191
                * static_cast<float>(maxWidth));
192
            if (width > 0)
193
            {
194
                if (width > maxWidth)
195
                    width = maxWidth;
196
                graphics->calcWindow(mVertexes, mFillPadding, mFillPadding,
197
                    width, mDimension.height - pad, mFillRect);
198
            }
199
        }
200
5
        graphics->finalize(mVertexes);
201
    }
202
203
5
    graphics->drawTileCollection(mVertexes);
204
205
    // The bar
206

5
    if (!mFillImage && mProgress > 0)
207
    {
208
        graphics->setColor(mBackgroundColor);
209
        const unsigned int pad = 2 * mFillPadding;
210
        const int maxWidth = mDimension.width - pad;
211
        int width = CAST_S32(mProgress * static_cast<float>(maxWidth));
212
        if (width > 0)
213
        {
214
            if (width > maxWidth)
215
                width = maxWidth;
216
            graphics->fillRectangle(Rect(mFillPadding, mFillPadding,
217
                width, mDimension.height - pad));
218
        }
219
    }
220
221
    // The label
222
10
    if (!mText.empty())
223
    {
224
6
        Font *const font = gui->getFont();
225
3
        if (mTextChanged)
226
        {
227
3
            mTextChunk.textFont = font;
228
3
            mTextChunk.deleteImage();
229
6
            mTextChunk.text = mText;
230
3
            mTextChunk.color = mForegroundColor;
231
3
            mTextChunk.color2 = mForegroundColor2;
232
3
            font->generate(mTextChunk);
233
3
            mTextChanged = false;
234
        }
235
236
3
        const Image *const image = mTextChunk.img;
237
3
        if (image != nullptr)
238
        {
239
3
            const int textX = (mDimension.width - font->getWidth(mText)) / 2;
240
3
            const int textY = (mDimension.height - font->getHeight()) / 2;
241
3
            graphics->drawImage(image, textX, textY);
242
        }
243
    }
244
    BLOCK_END("ProgressBar::draw")
245
}
246
247
void ProgressBar::safeDraw(Graphics *const graphics)
248
{
249
    BLOCK_START("ProgressBar::safeDraw")
250
    if (mSkin == nullptr)
251
    {
252
        BLOCK_END("ProgressBar::safeDraw")
253
        return;
254
    }
255
256
    updateAlpha();
257
    mBackgroundColor.a = CAST_U32(mAlpha * 255);
258
259
    graphics->drawImageRect(0, 0, mDimension.width, mDimension.height,
260
        mSkin->getBorder());
261
    if (mFillImage)
262
    {
263
        const unsigned int pad = 2 * mFillPadding;
264
        const int maxWidth = mDimension.width - pad;
265
        int width = CAST_S32(mProgress
266
            * static_cast<float>(maxWidth));
267
        if (width > 0)
268
        {
269
            if (width > maxWidth)
270
                width = maxWidth;
271
            graphics->drawImageRect(mFillPadding, mFillPadding,
272
                width, mDimension.height - pad, mFillRect);
273
        }
274
    }
275
276
    // The bar
277
    if (!mFillImage && mProgress > 0)
278
    {
279
        graphics->setColor(mBackgroundColor);
280
        const unsigned int pad = 2 * mFillPadding;
281
        const int maxWidth = mDimension.width - pad;
282
        int width = CAST_S32(mProgress * static_cast<float>(maxWidth));
283
        if (width > 0)
284
        {
285
            if (width > maxWidth)
286
                width = maxWidth;
287
            graphics->fillRectangle(Rect(mFillPadding, mFillPadding,
288
                width, mDimension.height - pad));
289
        }
290
    }
291
292
    // The label
293
    if (!mText.empty())
294
    {
295
        Font *const font = gui->getFont();
296
        if (mTextChanged)
297
        {
298
            mTextChunk.textFont = font;
299
            mTextChunk.deleteImage();
300
            mTextChunk.text = mText;
301
            mTextChunk.color = mForegroundColor;
302
            mTextChunk.color2 = mForegroundColor2;
303
            font->generate(mTextChunk);
304
            mTextChanged = false;
305
        }
306
307
        const Image *const image = mTextChunk.img;
308
        if (image != nullptr)
309
        {
310
            const int textX = (mDimension.width - font->getWidth(mText)) / 2;
311
            const int textY = (mDimension.height - font->getHeight()) / 2;
312
            graphics->drawImage(image, textX, textY);
313
        }
314
    }
315
    BLOCK_END("ProgressBar::safeDraw")
316
}
317
318
8
void ProgressBar::setProgress(const float progress)
319
{
320
24
    const float p = std::min(1.0F, std::max(0.0F, progress));
321
8
    mProgressToGo = p;
322
8
    mRedraw = true;
323
324
8
    if (!mSmoothProgress)
325
        mProgress = p;
326
327
8
    if (mProgressPalette >= ProgressColorId::PROG_HP)
328
    {
329
        mBackgroundColorToGo = Theme::getProgressColor(
330
8
            mProgressPalette, progress);
331
    }
332
8
}
333
334
1
void ProgressBar::setProgressPalette(const ProgressColorIdT progressPalette)
335
{
336
1
    const ProgressColorIdT oldPalette = mProgressPalette;
337
1
    mProgressPalette = progressPalette;
338
1
    mRedraw = true;
339
340

1
    if (mProgressPalette != oldPalette &&
341
        mProgressPalette >= ProgressColorId::PROG_HP)
342
    {
343
        mBackgroundColorToGo = Theme::getProgressColor(
344
            mProgressPalette, mProgressToGo);
345
    }
346
1
}
347
348
void ProgressBar::setBackgroundColor(const Color &color)
349
{
350
    mRedraw = true;
351
    mBackgroundColorToGo = color;
352
353
    if (!mSmoothColorChange)
354
        mBackgroundColor = color;
355
}
356
357
16
void ProgressBar::setColor(const Color &color1, const Color &color2)
358
{
359
16
    mForegroundColor = color1;
360
16
    mForegroundColor2 = color2;
361
16
    mTextChanged = true;
362
16
}
363
364
39
void ProgressBar::widgetResized(const Event &event A_UNUSED)
365
{
366
39
    mRedraw = true;
367
39
}
368
369
10
void ProgressBar::widgetMoved(const Event &event A_UNUSED)
370
{
371
10
    mRedraw = true;
372
10
}
373
374
11
void ProgressBar::setText(const std::string &str)
375
{
376
22
    if (mText != str)
377
    {
378
22
        mText = str;
379
11
        mTextChanged = true;
380
    }
381
11
}
382
383
5
void ProgressBar::widgetHidden(const Event &event A_UNUSED)
384
{
385
5
    mTextChanged = true;
386
5
    mTextChunk.deleteImage();
387
5
}