GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/progressbar.cpp Lines: 99 189 52.4 %
Date: 2017-11-29 Branches: 39 136 28.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
#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
32
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
32
                         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

32
    mVertexes(new ImageCollection),
60
    mProgressPalette(backColor),
61
    mPadding(2),
62
    mFillPadding(3),
63
    mFillImage(false),
64
    mSmoothProgress(true),
65
    mSmoothColorChange(true),
66
192
    mTextChanged(true)
67
{
68
32
    mBackgroundColor = Theme::getProgressColor(
69
        backColor >= ProgressColorId::PROG_HP
70
        ? backColor : ProgressColorId::PROG_HP,
71
32
        mProgress);
72
32
    mBackgroundColorToGo = mBackgroundColor;
73
64
    mForegroundColor2 = getThemeColor(ThemeColorId::PROGRESS_BAR_OUTLINE);
74
75
    // The progress value is directly set at load time:
76

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

160
        mSkin = theme->load(skin, "progressbar.xml");
86
32
        if (mSkin != nullptr)
87
        {
88
96
            setPadding(mSkin->getPadding());
89

128
            mFillPadding = mSkin->getOption("fillPadding");
90

128
            mFillImage = mSkin->getOption("fillImage") != 0;
91
32
            if (mFillImage)
92
                theme->loadRect(mFillRect, skinFill, "progressbar_fill.xml");
93
        }
94

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

10
    if (mRedraw || graphics->getRedraw())
170
    {
171
10
        mRedraw = false;
172
10
        mVertexes->clear();
173
10
        graphics->calcWindow(mVertexes, 0, 0,
174
10
            mDimension.width, mDimension.height, mSkin->getBorder());
175
10
        if (mFillImage)
176
        {
177
            const unsigned int pad = 2 * mFillPadding;
178
            const int maxWidth = mDimension.width - pad;
179
            int width = CAST_S32(mProgress
180
                * static_cast<float>(maxWidth));
181
            if (width > 0)
182
            {
183
                if (width > maxWidth)
184
                    width = maxWidth;
185
                graphics->calcWindow(mVertexes, mFillPadding, mFillPadding,
186
                    width, mDimension.height - pad, mFillRect);
187
            }
188
        }
189
10
        graphics->finalize(mVertexes);
190
    }
191
192
10
    graphics->drawTileCollection(mVertexes);
193
194
    // The bar
195

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

2
    if (mProgressPalette != oldPalette &&
330
        mProgressPalette >= ProgressColorId::PROG_HP)
331
    {
332
        mBackgroundColorToGo = Theme::getProgressColor(
333
            mProgressPalette, mProgressToGo);
334
    }
335
2
}
336
337
void ProgressBar::setBackgroundColor(const Color &color)
338
{
339
    mRedraw = true;
340
    mBackgroundColorToGo = color;
341
342
    if (!mSmoothColorChange)
343
        mBackgroundColor = color;
344
}
345
346
32
void ProgressBar::setColor(const Color &color1, const Color &color2)
347
{
348
32
    mForegroundColor = color1;
349
32
    mForegroundColor2 = color2;
350
32
    mTextChanged = true;
351
32
}
352
353
78
void ProgressBar::widgetResized(const Event &event A_UNUSED)
354
{
355
78
    mRedraw = true;
356
78
}
357
358
20
void ProgressBar::widgetMoved(const Event &event A_UNUSED)
359
{
360
20
    mRedraw = true;
361
20
}
362
363
22
void ProgressBar::setText(const std::string &str)
364
{
365
22
    if (mText != str)
366
    {
367
44
        mText = str;
368
22
        mTextChanged = true;
369
    }
370
22
}
371
372
10
void ProgressBar::widgetHidden(const Event &event A_UNUSED)
373
{
374
10
    mTextChanged = true;
375
10
    mTextChunk.deleteImage();
376
10
}