GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/slider.cpp Lines: 94 227 41.4 %
Date: 2021-03-17 Branches: 42 200 21.0 %

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
/*      _______   __   __   __   ______   __   __   _______   __   __
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/slider.h"
68
69
#include "settings.h"
70
71
#include "enums/gui/slidergrid.h"
72
73
#include "gui/gui.h"
74
75
#include "utils/delete2.h"
76
77
#include "resources/imagerect.h"
78
79
#include "resources/image/image.h"
80
81
#include "render/graphics.h"
82
83
#include "render/vertexes/imagecollection.h"
84
85
#include "debug.h"
86
87
5
ImageRect Slider::buttons[2];
88
float Slider::mAlpha = 1.0;
89
int Slider::mInstances = 0;
90
91
3
static std::string const data[2] =
92
{
93
    "slider.xml",
94
    "slider_highlighted.xml"
95

4
};
96
97
6
Slider::Slider(Widget2 *const widget,
98
               const double scaleEnd,
99
6
               const double stepLength) :
100
    Widget(widget),
101
    MouseListener(),
102
    KeyListener(),
103
    mValue(0),
104
    mStepLength(stepLength),
105
    mScaleStart(0),
106
    mScaleEnd(scaleEnd),
107
    mOrientation(Orientation::HORIZONTAL),
108

6
    mVertexes(new ImageCollection),
109
    mMarkerLength(10),
110
24
    mHasMouse(false)
111
{
112
6
    init();
113
6
}
114
115
27
Slider::Slider(Widget2 *const widget,
116
               const double scaleStart,
117
               const double scaleEnd,
118
27
               const double stepLength) :
119
    Widget(widget),
120
    MouseListener(),
121
    KeyListener(),
122
    mValue(scaleStart),
123
    mStepLength(stepLength),
124
    mScaleStart(scaleStart),
125
    mScaleEnd(scaleEnd),
126
    mOrientation(Orientation::HORIZONTAL),
127

27
    mVertexes(new ImageCollection),
128
    mMarkerLength(10),
129
108
    mHasMouse(false)
130
{
131
27
    init();
132
27
}
133
134
165
Slider::~Slider()
135
{
136
33
    if (gui != nullptr)
137
33
        gui->removeDragged(this);
138
139
33
    delete2(mVertexes)
140
33
    mInstances--;
141
33
    if (mInstances == 0)
142
    {
143
45
        for (int mode = 0; mode < 2; mode ++)
144
18
            Theme::unloadRect(buttons[mode], 0, 8);
145
    }
146
66
}
147
148
33
void Slider::init()
149
{
150
33
    mAllowLogic = false;
151
33
    setFocusable(true);
152
66
    setFrameSize(1);
153
154
33
    addMouseListener(this);
155
33
    addKeyListener(this);
156
157
66
    setFrameSize(0);
158
159
    // Load resources
160
33
    if (mInstances == 0)
161
    {
162
9
        if (theme != nullptr)
163
        {
164
45
            for (int mode = 0; mode < 2; mode ++)
165
54
                theme->loadRect(buttons[mode], data[mode], "slider.xml", 0, 8);
166
        }
167
9
        updateAlpha();
168
    }
169
170
33
    mInstances++;
171
172
33
    if (buttons[0].grid[SliderGrid::HGRIP] != nullptr)
173
66
        setMarkerLength(buttons[0].grid[SliderGrid::HGRIP]->getWidth());
174
33
}
175
176
16
void Slider::updateAlpha()
177
{
178
    const float alpha = std::max(settings.guiAlpha,
179
48
        theme->getMinimumOpacity());
180
181
16
    if (alpha != mAlpha)
182
    {
183
        mAlpha = alpha;
184
        for (int f = 0; f < 2; f ++)
185
        {
186
            for (int d = 0; d < SliderGrid::SLIDER_MAX; d ++)
187
            {
188
                if (buttons[f].grid[d] != nullptr)
189
                    buttons[f].grid[d]->setAlpha(mAlpha);
190
            }
191
        }
192
    }
193
16
}
194
195
7
void Slider::draw(Graphics *const graphics)
196
{
197
    BLOCK_START("Slider::draw")
198

14
    if ((buttons[0].grid[SliderGrid::HSTART] == nullptr) ||
199
14
        (buttons[1].grid[SliderGrid::HSTART] == nullptr) ||
200
7
        (buttons[0].grid[SliderGrid::HEND] == nullptr))
201
    {
202
        BLOCK_END("Slider::draw")
203
        return;
204
    }
205
206
14
    int w = getWidth();
207
14
    const int h = getHeight();
208
14
    const int y = mHasMouse ?
209
        (h - buttons[1].grid[SliderGrid::HSTART]->getHeight()) / 2 :
210
21
        (h - buttons[0].grid[SliderGrid::HSTART]->getHeight()) / 2;
211
212
7
    updateAlpha();
213
214

7
    if (mRedraw || graphics->getRedraw())
215
    {
216
7
        int x = 0;
217
7
        mRedraw = false;
218
7
        mVertexes->clear();
219
7
        if (!mHasMouse)
220
        {
221
7
            graphics->calcTileCollection(mVertexes,
222
7
                buttons[0].grid[SliderGrid::HSTART],
223
14
                x, y);
224
225
14
            const int width = buttons[0].grid[SliderGrid::HSTART]->getWidth();
226
14
            w -= width + buttons[0].grid[SliderGrid::HEND]->getWidth();
227
7
            x += width;
228
229
7
            if (buttons[0].grid[SliderGrid::HMID] != nullptr)
230
            {
231
7
                const Image *const hMid = buttons[0].grid[SliderGrid::HMID];
232
7
                graphics->calcPattern(mVertexes,
233
                    hMid,
234
                    x, y,
235
14
                    w, hMid->getHeight());
236
            }
237
238
7
            x += w;
239
7
            graphics->calcTileCollection(mVertexes,
240
7
                buttons[0].grid[SliderGrid::HEND],
241
14
                x, y);
242
243
7
            const Image *const img = buttons[0].grid[SliderGrid::HGRIP];
244
7
            if (img != nullptr)
245
            {
246
14
                graphics->calcTileCollection(mVertexes,
247
                    img,
248
                    getMarkerPosition(),
249
21
                    (mDimension.height - img->getHeight()) / 2);
250
            }
251
        }
252
        else
253
        {
254
            graphics->calcTileCollection(mVertexes,
255
                buttons[1].grid[SliderGrid::HSTART],
256
                x, y);
257
258
            const int width = buttons[1].grid[SliderGrid::HSTART]->getWidth();
259
            w -= width;
260
            if (buttons[1].grid[SliderGrid::HEND] != nullptr)
261
                w -= buttons[1].grid[SliderGrid::HEND]->getWidth();
262
            x += width;
263
264
            if (buttons[1].grid[SliderGrid::HMID] != nullptr)
265
            {
266
                const Image *const hMid = buttons[1].grid[SliderGrid::HMID];
267
                graphics->calcPattern(mVertexes,
268
                    hMid,
269
                    x, y,
270
                    w, hMid->getHeight());
271
            }
272
273
            x += w;
274
            if (buttons[1].grid[SliderGrid::HEND] != nullptr)
275
            {
276
                graphics->calcTileCollection(mVertexes,
277
                    buttons[1].grid[SliderGrid::HEND], x, y);
278
            }
279
280
            const Image *const img = buttons[1].grid[SliderGrid::HGRIP];
281
            if (img != nullptr)
282
            {
283
                graphics->calcTileCollection(mVertexes,
284
                    img,
285
                    getMarkerPosition(),
286
                    (mDimension.height - img->getHeight()) / 2);
287
            }
288
        }
289
7
        graphics->finalize(mVertexes);
290
    }
291
7
    graphics->drawTileCollection(mVertexes);
292
293
    BLOCK_END("Slider::draw")
294
}
295
296
void Slider::safeDraw(Graphics *const graphics)
297
{
298
    BLOCK_START("Slider::draw")
299
    if ((buttons[0].grid[SliderGrid::HSTART] == nullptr) ||
300
        (buttons[1].grid[SliderGrid::HSTART] == nullptr) ||
301
        (buttons[0].grid[SliderGrid::HEND] == nullptr))
302
    {
303
        BLOCK_END("Slider::draw")
304
        return;
305
    }
306
307
    int w = getWidth();
308
    const int h = getHeight();
309
    int x = 0;
310
    const int y = mHasMouse ?
311
        (h - buttons[1].grid[SliderGrid::HSTART]->getHeight()) / 2 :
312
        (h - buttons[0].grid[SliderGrid::HSTART]->getHeight()) / 2;
313
314
    updateAlpha();
315
316
    if (!mHasMouse)
317
    {
318
        graphics->drawImage(buttons[0].grid[SliderGrid::HSTART], x, y);
319
        const int width = buttons[0].grid[SliderGrid::HSTART]->getWidth();
320
        w -= width + buttons[0].grid[SliderGrid::HEND]->getWidth();
321
        x += width;
322
323
        if (buttons[0].grid[SliderGrid::HMID] != nullptr)
324
        {
325
            const Image *const hMid = buttons[0].grid[SliderGrid::HMID];
326
            graphics->drawPattern(hMid, x, y, w, hMid->getHeight());
327
        }
328
329
        x += w;
330
        graphics->drawImage(buttons[0].grid[SliderGrid::HEND], x, y);
331
332
        const Image *const img = buttons[0].grid[SliderGrid::HGRIP];
333
        if (img != nullptr)
334
        {
335
            graphics->drawImage(img, getMarkerPosition(),
336
                (mDimension.height - img->getHeight()) / 2);
337
        }
338
    }
339
    else
340
    {
341
        graphics->drawImage(buttons[1].grid[SliderGrid::HSTART], x, y);
342
343
        const int width = buttons[1].grid[SliderGrid::HSTART]->getWidth();
344
        w -= width;
345
        if (buttons[1].grid[SliderGrid::HEND] != nullptr)
346
            w -= buttons[1].grid[SliderGrid::HEND]->getWidth();
347
        x += width;
348
349
        if (buttons[1].grid[SliderGrid::HMID] != nullptr)
350
        {
351
            const Image *const hMid = buttons[1].grid[SliderGrid::HMID];
352
            graphics->drawPattern(hMid, x, y, w, hMid->getHeight());
353
        }
354
355
        x += w;
356
        if (buttons[1].grid[SliderGrid::HEND] != nullptr)
357
            graphics->drawImage(buttons[1].grid[SliderGrid::HEND], x, y);
358
359
        const Image *const img = buttons[1].grid[SliderGrid::HGRIP];
360
        if (img != nullptr)
361
        {
362
            graphics->drawImage(img, getMarkerPosition(),
363
                (mDimension.height - img->getHeight()) / 2);
364
        }
365
    }
366
367
    BLOCK_END("Slider::draw")
368
}
369
370
void Slider::mouseEntered(MouseEvent& event A_UNUSED)
371
{
372
    mHasMouse = true;
373
    mRedraw = true;
374
}
375
376
void Slider::mouseExited(MouseEvent& event A_UNUSED)
377
{
378
    mHasMouse = false;
379
    mRedraw = true;
380
}
381
382
void Slider::mousePressed(MouseEvent &event)
383
{
384
    const int x = event.getX();
385
    const int y = event.getY();
386
    const int width = mDimension.width;
387
    const int height = mDimension.height;
388
389
    if (event.getButton() == MouseButton::LEFT
390
        && x >= 0 && x <= width && y >= 0 && y <= height)
391
    {
392
        event.consume();
393
        if (mOrientation == Orientation::HORIZONTAL)
394
            setValue(markerPositionToValue(x - mMarkerLength / 2));
395
        else
396
            setValue(markerPositionToValue(height - y - mMarkerLength / 2));
397
        distributeActionEvent();
398
    }
399
}
400
401
void Slider::mouseDragged(MouseEvent &event)
402
{
403
    if (mOrientation == Orientation::HORIZONTAL)
404
    {
405
        setValue(markerPositionToValue(event.getX() - mMarkerLength / 2));
406
    }
407
    else
408
    {
409
        setValue(markerPositionToValue(
410
            mDimension.height - event.getY() - mMarkerLength / 2));
411
    }
412
413
    distributeActionEvent();
414
415
    event.consume();
416
}
417
418
void Slider::mouseWheelMovedUp(MouseEvent &event)
419
{
420
    setValue(mValue + mStepLength);
421
    distributeActionEvent();
422
    event.consume();
423
}
424
425
void Slider::mouseWheelMovedDown(MouseEvent &event)
426
{
427
    setValue(mValue - mStepLength);
428
    distributeActionEvent();
429
    event.consume();
430
}
431
432
void Slider::keyPressed(KeyEvent& event)
433
{
434
    const InputActionT action = event.getActionId();
435
436
    if (mOrientation == Orientation::HORIZONTAL)
437
    {
438
        if (action == InputAction::GUI_RIGHT)
439
        {
440
            setValue(mValue + mStepLength);
441
            distributeActionEvent();
442
            event.consume();
443
        }
444
        else if (action == InputAction::GUI_LEFT)
445
        {
446
            setValue(mValue - mStepLength);
447
            distributeActionEvent();
448
            event.consume();
449
        }
450
    }
451
    else
452
    {
453
        if (action == InputAction::GUI_UP)
454
        {
455
            setValue(mValue + mStepLength);
456
            distributeActionEvent();
457
            event.consume();
458
        }
459
        else if (action == InputAction::GUI_DOWN)
460
        {
461
            setValue(mValue - mStepLength);
462
            distributeActionEvent();
463
            event.consume();
464
        }
465
    }
466
}
467
468
void Slider::setScale(const double scaleStart, const double scaleEnd)
469
{
470
    mScaleStart = scaleStart;
471
    mScaleEnd = scaleEnd;
472
}
473
474
28
void Slider::setValue(const double value)
475
{
476
28
    mRedraw = true;
477





28
    if (value > mScaleEnd)
478
        mValue = mScaleEnd;
479





28
    else if (value < mScaleStart)
480
        mValue = mScaleStart;
481
    else
482
28
        mValue = value;
483
56
    mValue = CAST_S32((mValue - mScaleStart) / mStepLength)
484
28
        * mStepLength + mScaleStart;
485
28
}
486
487
double Slider::markerPositionToValue(const int v) const
488
{
489
    int w;
490
    if (mOrientation == Orientation::HORIZONTAL)
491
        w = mDimension.width;
492
    else
493
        w = mDimension.height;
494
495
    const double pos = v / (static_cast<double>(w) - mMarkerLength);
496
    return (1.0 - pos) * mScaleStart + pos * mScaleEnd;
497
}
498
499
int Slider::valueToMarkerPosition(const double value) const
500
{
501
    int v;
502


7
    if (mOrientation == Orientation::HORIZONTAL)
503
7
        v = mDimension.width;
504
    else
505
        v = mDimension.height;
506
507
7
    const int w = CAST_S32((v - mMarkerLength)
508
7
            * (value  - mScaleStart)
509
7
            / (mScaleEnd - mScaleStart));
510
511


7
    if (w < 0)
512
        return 0;
513
514


7
    if (w > v - mMarkerLength)
515
        return v - mMarkerLength;
516
517
    return w;
518

3
}