ManaPlus
skillrectanglelistbox.h
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2011-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef GUI_WIDGETS_SKILLRECTANGLELISTBOX_H
23 #define GUI_WIDGETS_SKILLRECTANGLELISTBOX_H
24 
25 #include "const/resources/skill.h"
26 
27 #include "dragdrop.h"
28 #include "settings.h"
29 
30 #include "gui/skin.h"
31 #include "gui/viewport.h"
32 
33 #include "gui/fonts/font.h"
34 
35 #include "gui/models/skillmodel.h"
36 
37 #include "gui/popups/popupmenu.h"
38 #include "gui/popups/skillpopup.h"
39 
40 #include "utils/delete2.h"
41 
42 #include "render/graphics.h"
43 
44 #include "localconsts.h"
45 
46 class SkillModel;
47 
49  public MouseListener
50 {
51  public:
52  SkillRectangleListBox(const Widget2 *const widget,
53  SkillModel *const model) :
54  Widget(widget),
55  MouseListener(),
56  mHighlightColor(getThemeColor(ThemeColorId::HIGHLIGHT, 255U)),
58  mTextColor2(getThemeColor(ThemeColorId::TEXT_OUTLINE, 255U)),
61  ThemeColorId::LISTBOX_SELECTED, 255U)),
63  ThemeColorId::LISTBOX_SELECTED_OUTLINE, 255U)),
64  mModel(model),
65  mSkin(nullptr),
66  mSelected(-1),
67  mPadding(2),
68  mBoxWidth(80),
69  mBoxHeight(70),
70  mIconXOffset(24),
71  mIconYOffset(10),
72  mTextXOffset(0),
73  mTextYOffset(44),
74  mSkillClicked(false)
75  {
76  if (theme != nullptr)
77  {
78  mSkin = theme->load("skillrectanglelistbox.xml",
79  "listbox.xml",
80  true,
82  }
83 
84  if (mSkin != nullptr)
85  {
87  mBoxWidth = mSkin->getOption("boxWidth", 80);
88  mBoxHeight = mSkin->getOption("boxHeight", 70);
89  mIconXOffset = mSkin->getOption("iconXOffset", 24);
90  mIconYOffset = mSkin->getOption("iconYOffset", 10);
91  mTextXOffset = mSkin->getOption("textXOffset", 0);
92  mTextYOffset = mSkin->getOption("textYOffset", 44);
93  }
94  Font *const font = getFont();
95  int minWidth = font->getWidth("Lvl: 10/10") + mTextXOffset + 2;
96  int minHeight = font->getHeight() + mTextYOffset + 2;
97  if (mBoxWidth < minWidth)
98  mBoxWidth = minWidth;
99  if (mBoxHeight < minHeight)
100  mBoxHeight = minHeight;
101  int maxX = 0;
102  int maxY = 0;
103  for (int i = 0;
104  i < model->getNumberOfElements();
105  ++i)
106  {
107  SkillInfo *const e = model->getSkillAt(i);
108  if (e != nullptr)
109  {
110  if (e->x > maxX)
111  maxX = e->x;
112  if (e->y > maxY)
113  maxY = e->y;
114  }
115  }
116  maxX ++;
117  maxY ++;
118  setWidth(maxX * mBoxWidth);
119  setHeight(maxY * mBoxHeight);
120  addMouseListener(this);
121  }
122 
124 
126  {
127  delete2(mModel)
128  }
129 
131  {
132  if (mModel == nullptr)
133  return nullptr;
134  const int selected = mSelected;
135  if (selected < 0 ||
136  selected > mModel->getNumberOfElements())
137  {
138  return nullptr;
139  }
140 
141  return mModel->getSkillAt(selected);
142  }
143 
144  void draw(Graphics *const graphics) override final A_NONNULL(2)
145  {
146  if (mModel == nullptr)
147  return;
148 
149  SkillModel *const model = mModel;
150  updateAlpha();
151 
152  int maxX = 0;
153  int maxY = 0;
154  mHighlightColor.a = CAST_S32(mAlpha * 255.0F);
155  graphics->setColor(mHighlightColor);
156  Font *const font = getFont();
157  if (mSelected >= 0)
158  {
159  SkillInfo *const e = model->getSkillAt(mSelected);
160  if (e != nullptr)
161  {
162  const int x = e->x * mBoxWidth + mPadding;
163  const int y = e->y * mBoxHeight + mPadding;
164 
165  graphics->fillRectangle(Rect(x, y,
167 
168  const int xOffset = (mBoxWidth -
169  font->getWidth(e->skillLevel)) / 2;
170  font->drawString(graphics,
173  e->skillLevel,
174  x + mTextXOffset + xOffset,
175  y + mTextYOffset);
176  }
177  }
178 
179  // +++ need split drawing icons and text
180  for (int i = 0;
181  i < model->getNumberOfElements();
182  ++i)
183  {
184  SkillInfo *const e = model->getSkillAt(i);
185  if (e != nullptr)
186  {
187  if (e->x > maxX)
188  maxX = e->x;
189  if (e->y > maxY)
190  maxY = e->y;
191  const SkillData *const data = e->data;
192  const int x = e->x * mBoxWidth + mPadding;
193  const int y = e->y * mBoxHeight + mPadding;
194 
195  graphics->drawImage(data->icon,
196  x + mIconXOffset,
197  y + mIconYOffset);
198 
199  if (i != mSelected)
200  {
201  const int width1 = font->getWidth(e->skillLevel);
202  const int xOffset = (mBoxWidth -
203  width1) / 2;
204  font->drawString(graphics,
205  mTextColor,
206  mTextColor2,
207  e->skillLevel,
208  x + mTextXOffset + xOffset,
209  y + mTextYOffset);
210  if (e->skillLevelWidth < 0)
211  {
212  // Add one for padding
213  e->skillLevelWidth = width1 + 1;
214  }
215  }
216  else
217  {
218  if (e->skillLevelWidth < 0)
219  {
220  // Add one for padding
221  e->skillLevelWidth = font->getWidth(
222  e->skillLevel) + 1;
223  }
224  }
225  }
226  }
227  maxX ++;
228  maxY ++;
229  setWidth(maxX * mBoxWidth);
230  setHeight(maxY * mBoxHeight);
231  }
232 
233  void safeDraw(Graphics *const graphics) override final A_NONNULL(2)
234  {
235  SkillRectangleListBox::draw(graphics);
236  }
237 
238  const SkillInfo *getSkillByEvent(const MouseEvent &event) const
239  {
240  if (mModel == nullptr)
241  return nullptr;
242  const int posX = (event.getX() - mPadding) / mBoxWidth;
243  const int posY = (event.getY() - mPadding) / mBoxHeight;
244  for (int i = 0;
246  ++i)
247  {
248  SkillInfo *const e = mModel->getSkillAt(i);
249  if (e != nullptr)
250  {
251  if (posX == e->x && posY == e->y)
252  return e;
253  }
254  }
255  return nullptr;
256  }
257 
258  int getSelectionByEvent(const MouseEvent &event) const
259  {
260  if (mModel == nullptr)
261  return -1;
262  const int posX = (event.getX() - mPadding) / mBoxWidth;
263  const int posY = (event.getY() - mPadding) / mBoxHeight;
264  for (int i = 0;
266  ++i)
267  {
268  SkillInfo *const e = mModel->getSkillAt(i);
269  if (e != nullptr)
270  {
271  if (posX == e->x && posY == e->y)
272  return i;
273  }
274  }
275  return -1;
276  }
277 
278  void mouseMoved(MouseEvent &event) override final
279  {
280  if ((viewport == nullptr) || !dragDrop.isEmpty())
281  return;
282 
283  const SkillInfo *const skill = getSkillByEvent(event);
284  if (skill == nullptr)
285  return;
287  skill->customSelectedLevel,
288  skill->customCastType,
289  skill->customOffsetX,
290  skill->customOffsetY);
292  viewport->mMouseY);
293  }
294 
295  void mouseDragged(MouseEvent &event) override final
296  {
297  if (event.getButton() != MouseButton::LEFT)
298  return;
299  setSelected(std::max(0, getSelectionByEvent(event)));
300 
301  if (dragDrop.isEmpty())
302  {
303  if (mSkillClicked)
304  {
305  mSkillClicked = false;
306  const SkillInfo *const skill = getSkillByEvent(event);
307  if (skill == nullptr)
308  return;
311  dragDrop.setItemData(skill->toDataStr());
312  }
313  }
314  }
315 
316  void mousePressed(MouseEvent &event) override final
317  {
318  const MouseButtonT button = event.getButton();
319  if (button == MouseButton::LEFT ||
320  button == MouseButton::RIGHT)
321  {
322  const SkillInfo *const skill = getSkillByEvent(event);
323  if (skill == nullptr)
324  return;
325  event.consume();
326  mSkillClicked = true;
327  SkillModel *const model = mModel;
328  if ((model != nullptr) &&
329  mSelected >= 0 &&
330  model->getSkillAt(mSelected) == skill)
331  {
332  skillPopup->hide();
333 
334  const int x = skill->x * mBoxWidth + mPadding;
335  const int y = skill->y * mBoxHeight + mPadding;
336  Font *const font = getFont();
337  const int height = font->getHeight();
338  const int eventX = event.getX();
339  const int eventY = event.getY() - mTextYOffset;
340  if (button == MouseButton::LEFT)
341  {
342  if (eventX >= x + mTextXOffset &&
343  eventX <= x + mBoxWidth - mTextXOffset &&
344  eventY >= y &&
345  eventY <= y + height)
346  {
348  }
349  }
350  else if (button == MouseButton::RIGHT)
351  {
353  }
354  }
355  }
356  }
357 
358  void mouseReleased(MouseEvent &event) override final
359  {
360  if (event.getButton() == MouseButton::LEFT)
361  {
362  setSelected(std::max(0, getSelectionByEvent(event)));
364  }
365  }
366 
367  void mouseExited(MouseEvent &event A_UNUSED) override final
368  {
369  skillPopup->hide();
370  }
371 
372  void updateAlpha()
373  {
374  const float alpha = std::max(settings.guiAlpha,
376 
377  if (mAlpha != alpha)
378  mAlpha = alpha;
379  }
380 
381  void setSelected(const int selected)
382  {
383  if (mModel == nullptr)
384  {
385  mSelected = -1;
386  }
387  else
388  {
389  if (selected < 0)
390  mSelected = -1;
391  else if (selected >= mModel->getNumberOfElements())
393  else
394  mSelected = selected;
395  }
396  }
397 
398  private:
408  int mPadding;
416  static float mAlpha;
417 };
418 
420 
421 #endif // GUI_WIDGETS_SKILLRECTANGLELISTBOX_H
#define CAST_S32
Definition: cast.h:30
Definition: color.h:76
unsigned int a
Definition: color.h:251
void setItem(const int item)
Definition: dragdrop.h:238
void dragSkill(const SkillInfo *const info, const DragDropSourceT source, const int tag)
Definition: dragdrop.h:152
bool isEmpty() const
Definition: dragdrop.h:196
void setItemData(const std::string &data)
Definition: dragdrop.h:78
Definition: font.h:90
int getHeight() const
Definition: font.cpp:362
int getWidth(const std::string &text) const
Definition: font.cpp:334
void drawString(Graphics *const graphics, Color col, const Color &col2, const std::string &text, const int x, const int y)
Definition: font.cpp:254
void showSkillLevelPopup(const SkillInfo *const info)
Definition: popupmenu.cpp:2356
void showSkillPopup(const SkillInfo *const info)
Definition: popupmenu.cpp:2263
void hide()
Definition: popup.cpp:265
void position(const int x, const int y)
Definition: popup.cpp:235
Definition: rect.h:74
float guiAlpha
Definition: settings.h:131
SkillInfo * getSkillAt(const int i) const
Definition: skillmodel.cpp:39
int getNumberOfElements()
Definition: skillmodel.h:46
void show(const SkillInfo *const skill, const int level, const CastTypeT type, const int offsetX, const int offsetY)
Definition: skillpopup.cpp:106
const SkillInfo * getSkillByEvent(const MouseEvent &event) const
void mouseMoved(MouseEvent &event)
void mousePressed(MouseEvent &event)
int getSelectionByEvent(const MouseEvent &event) const
void safeDraw(Graphics *const graphics)
void mouseDragged(MouseEvent &event)
void mouseExited(MouseEvent &event)
void mouseReleased(MouseEvent &event)
void setSelected(const int selected)
SkillRectangleListBox(const Widget2 *const widget, SkillModel *const model)
void draw(Graphics *const graphics)
SkillInfo * getSelectedInfo() const
Definition: skin.h:37
int getOption(const std::string &name) const
Definition: skin.h:106
int getPadding() const
Definition: skin.h:100
static std::string getThemePath()
Definition: theme.h:67
Skin * load(const std::string &filename, const std::string &filename2, const bool full, const std::string &defaultPath)
Definition: theme.cpp:179
float getMinimumOpacity() const
Definition: theme.h:124
int mMouseX
Definition: viewport.h:154
int mMouseY
Definition: viewport.h:155
const Color & getThemeColor(const ThemeColorIdT type, const unsigned int alpha) const A_INLINE
Definition: widget2.h:45
Definition: widget.h:99
void setWidth(const int width)
Definition: widget.cpp:133
void distributeActionEvent()
Definition: widget.cpp:493
void addMouseListener(MouseListener *const mouseListener)
Definition: widget.cpp:292
void setHeight(const int height)
Definition: widget.cpp:140
Font * getFont() const
Definition: widget.cpp:331
#define delete2(var)
Definition: delete2.h:25
DragDrop dragDrop
Viewport * viewport
Definition: viewport.cpp:36
#define override
Definition: localconsts.h:47
#define A_NONNULL(...)
Definition: localconsts.h:168
#define final
Definition: localconsts.h:46
#define A_DELETE_COPY(func)
Definition: localconsts.h:53
#define nullptr
Definition: localconsts.h:45
#define A_UNUSED
Definition: localconsts.h:160
uint32_t data
MouseButton ::T MouseButtonT
Definition: mousebutton.h:78
bool skill(InputEvent &event)
Definition: commands.cpp:97
@ SKILL_COOLDOWN
Definition: sp.h:256
PopupMenu * popupMenu
Definition: popupmenu.cpp:103
const int SKILL_MIN_ID
Definition: skill.h:25
Settings settings
Definition: settings.cpp:32
SkillPopup * skillPopup
Definition: skillpopup.cpp:42
int skillLevelWidth
Definition: skillinfo.h:68
std::string skillLevel
Definition: skillinfo.h:52
SkillData * data
Definition: skillinfo.h:63
Theme * theme
Definition: theme.cpp:62