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