GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/skilllistbox.h Lines: 0 118 0.0 %
Date: 2021-03-17 Branches: 0 100 0.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
#ifndef GUI_WIDGETS_SKILLLISTBOX_H
25
#define GUI_WIDGETS_SKILLLISTBOX_H
26
27
#include "const/resources/skill.h"
28
29
#include "dragdrop.h"
30
31
#include "gui/skin.h"
32
#include "gui/viewport.h"
33
34
#include "gui/widgets/listbox.h"
35
36
#include "gui/fonts/font.h"
37
38
#include "gui/models/skillmodel.h"
39
40
#include "gui/popups/popupmenu.h"
41
#include "gui/popups/skillpopup.h"
42
43
#include "utils/delete2.h"
44
45
#include "render/graphics.h"
46
47
#include "localconsts.h"
48
49
class SkillModel;
50
51
class SkillListBox final : public ListBox
52
{
53
    public:
54
        SkillListBox(const Widget2 *const widget,
55
                     SkillModel *const model) :
56
            ListBox(widget, model, "skilllistbox.xml"),
57
            mModel(model),
58
            mTextColor(getThemeColor(ThemeColorId::TEXT, 255U)),
59
            mTextColor2(getThemeColor(ThemeColorId::TEXT_OUTLINE, 255U)),
60
            mCooldownColor(getThemeColor(ThemeColorId::SKILL_COOLDOWN, 255U)),
61
            mTextPadding(mSkin != nullptr ?
62
                mSkin->getOption("textPadding", 34) : 34),
63
            mSpacing(mSkin != nullptr ? mSkin->getOption("spacing", 0) : 0),
64
            mSkillClicked(false)
65
        {
66
            mRowHeight = getFont()->getHeight() * 2 + mSpacing + 2 * mPadding;
67
            mHighlightColor = getThemeColor(ThemeColorId::HIGHLIGHT, 255U);
68
69
            if (mRowHeight < 34)
70
                mRowHeight = 34;
71
        }
72
73
        A_DELETE_COPY(SkillListBox)
74
75
        ~SkillListBox() override final
76
        {
77
            delete2(mModel)
78
        }
79
80
        SkillInfo *getSelectedInfo() const
81
        {
82
            const int selected = getSelected();
83
            if ((mListModel == nullptr) || selected < 0
84
                || selected > mListModel->getNumberOfElements())
85
            {
86
                return nullptr;
87
            }
88
89
            return static_cast<SkillModel*>(mListModel)->getSkillAt(selected);
90
        }
91
92
        void draw(Graphics *const graphics) override final A_NONNULL(2)
93
        {
94
            if (mListModel == nullptr)
95
                return;
96
97
            SkillModel *const model = static_cast<SkillModel*>(mListModel);
98
            updateAlpha();
99
100
            mHighlightColor.a = CAST_S32(mAlpha * 255.0F);
101
            graphics->setColor(mHighlightColor);
102
103
            const int width1 = getWidth();
104
            const int usableWidth = width1 - 2 * mPadding;
105
106
            // Draw filled rectangle around the selected list element
107
            if (mSelected >= 0)
108
            {
109
                graphics->fillRectangle(Rect(mPadding, getRowHeight()
110
                    * mSelected + mPadding, usableWidth,
111
                    getRowHeight()));
112
            }
113
114
            // Draw the list elements
115
            Font *const font = getFont();
116
            const int space = font->getHeight() + mSpacing;
117
            const int width2 = width1 - mPadding;
118
119
            graphics->setColor(mCooldownColor);
120
            for (int i = 0, y = 1 + mPadding;
121
                 i < model->getNumberOfElements();
122
                 ++i, y += getRowHeight())
123
            {
124
                SkillInfo *const e = model->getSkillAt(i);
125
                if (e != nullptr)
126
                {
127
                    if (e->cooldown != 0)
128
                    {
129
                        graphics->fillRectangle(Rect(mPadding, y,
130
                            usableWidth * 100 / e->cooldown, 10));
131
                    }
132
                }
133
            }
134
135
            for (int i = 0, y = 1 + mPadding;
136
                 i < model->getNumberOfElements();
137
                 ++i, y += getRowHeight())
138
            {
139
                SkillInfo *const e = model->getSkillAt(i);
140
                if (e != nullptr)
141
                {
142
                    const SkillData *const data = e->data;
143
                    const std::string &description = data->description;
144
                    graphics->drawImage(data->icon, mPadding, y);
145
                    font->drawString(graphics,
146
                        mTextColor,
147
                        mTextColor2,
148
                        data->name,
149
                        mTextPadding, y);
150
                    if (!description.empty())
151
                    {
152
                        font->drawString(graphics,
153
                            mTextColor,
154
                            mTextColor2,
155
                            description,
156
                            mTextPadding,
157
                            y + space);
158
                    }
159
160
                    if (e->skillLevelWidth < 0)
161
                    {
162
                        // Add one for padding
163
                        e->skillLevelWidth = font->getWidth(e->skillLevel) + 1;
164
                    }
165
166
                    font->drawString(graphics,
167
                        mTextColor,
168
                        mTextColor2,
169
                        e->skillLevel,
170
                        width2 - e->skillLevelWidth,
171
                        y);
172
                }
173
            }
174
        }
175
176
        void safeDraw(Graphics *const graphics) override final A_NONNULL(2)
177
        {
178
            SkillListBox::draw(graphics);
179
        }
180
181
        unsigned int getRowHeight() const override final
182
        { return mRowHeight; }
183
184
        const SkillInfo *getSkillByEvent(const MouseEvent &event) const
185
        {
186
            const int y = (event.getY() + mPadding) / getRowHeight();
187
            if (mModel == nullptr || y >= mModel->getNumberOfElements())
188
                return nullptr;
189
            const SkillInfo *const skill = mModel->getSkillAt(y);
190
            if (skill == nullptr)
191
                return nullptr;
192
            return skill;
193
        }
194
195
        void mouseMoved(MouseEvent &event) override final
196
        {
197
            ListBox::mouseMoved(event);
198
            if ((viewport == nullptr) || !dragDrop.isEmpty())
199
                return;
200
201
            const SkillInfo *const skill = getSkillByEvent(event);
202
            if (skill == nullptr)
203
                return;
204
            skillPopup->show(skill,
205
                skill->customSelectedLevel,
206
                skill->customCastType,
207
                skill->customOffsetX,
208
                skill->customOffsetY);
209
            skillPopup->position(viewport->mMouseX,
210
                viewport->mMouseY);
211
        }
212
213
        void mouseDragged(MouseEvent &event) override final
214
        {
215
            if (event.getButton() == MouseButton::LEFT)
216
            {
217
                if (dragDrop.isEmpty())
218
                {
219
                    if (mSkillClicked)
220
                    {
221
                        mSkillClicked = false;
222
                        const SkillInfo *const skill = getSkillByEvent(event);
223
                        if (skill == nullptr)
224
                            return;
225
                        dragDrop.dragSkill(skill, DragDropSource::Skills, 0);
226
                        dragDrop.setItem(skill->id + SKILL_MIN_ID);
227
                        dragDrop.setItemData(skill->toDataStr());
228
                    }
229
                    ListBox::mouseDragged(event);
230
                }
231
            }
232
            else
233
            {
234
                ListBox::mouseDragged(event);
235
            }
236
        }
237
238
        void mousePressed(MouseEvent &event) override final
239
        {
240
            ListBox::mousePressed(event);
241
            const MouseButtonT button = event.getButton();
242
            if (button == MouseButton::LEFT ||
243
                button == MouseButton::RIGHT)
244
            {
245
                const SkillInfo *const skill = getSkillByEvent(event);
246
                if (skill == nullptr)
247
                    return;
248
                event.consume();
249
                mSkillClicked = true;
250
                SkillModel *const model = static_cast<SkillModel*>(
251
                    mListModel);
252
                if ((model != nullptr) &&
253
                    mSelected >= 0 &&
254
                    model->getSkillAt(mSelected) == skill)
255
                {
256
                    skillPopup->hide();
257
                    if (button == MouseButton::LEFT &&
258
                        event.getX() >
259
                        getWidth() - mPadding - skill->skillLevelWidth)
260
                    {
261
                        popupMenu->showSkillLevelPopup(skill);
262
                    }
263
                    else if (button == MouseButton::RIGHT)
264
                    {
265
                        popupMenu->showSkillPopup(skill);
266
                    }
267
                }
268
            }
269
        }
270
271
        void mouseReleased(MouseEvent &event) override final
272
        {
273
            ListBox::mouseReleased(event);
274
        }
275
276
        void mouseExited(MouseEvent &event A_UNUSED) override final
277
        {
278
            skillPopup->hide();
279
        }
280
281
    private:
282
        SkillModel *mModel;
283
        Color mTextColor;
284
        Color mTextColor2;
285
        Color mCooldownColor;
286
        int mTextPadding;
287
        int mSpacing;
288
        bool mSkillClicked;
289
};
290
291
#endif  // GUI_WIDGETS_SKILLLISTBOX_H