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

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

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

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

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

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

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

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

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

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

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