ManaPlus
dropdown.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2006-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/dropdown.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 
33 
35 #include "gui/widgets/popuplist.h"
36 
37 #include "render/graphics.h"
38 
39 #include "resources/imagerect.h"
40 
41 #include "debug.h"
42 
43 int DropDown::instances = 0;
46 float DropDown::mAlpha = 1.0;
47 Skin *DropDown::mSkin = nullptr;
48 
49 static std::string const dropdownFiles[2] =
50 {
51  "dropdown.xml",
52  "dropdown_pressed.xml"
53 };
54 
55 DropDown::DropDown(const Widget2 *const widget,
56  ListModel *const listModel,
57  const bool extended,
58  const Modal modal,
59  ActionListener *const listener,
60  const std::string &eventId) :
62  BasicContainer(widget),
63  KeyListener(),
64  MouseListener(),
65  FocusListener(),
67  mPopup(CREATEWIDGETR(PopupList, this, listModel, extended, modal)),
68  mShadowColor(getThemeColor(ThemeColorId::DROPDOWN_SHADOW)),
69  mHighlightColor(getThemeColor(ThemeColorId::HIGHLIGHT)),
70  mPadding(1),
71  mImagePadding(2),
72  mSpacing(0),
73  mFoldedUpHeight(0),
74  mSelectionListeners(),
75  mExtended(extended),
76  mDroppedDown(false),
77  mPushed(false),
78  mIsDragged(false)
79 {
80  mAllowLogic = false;
81  mFrameSize = 2;
83 
84  mPopup->setHeight(100);
85 
86  // Initialize graphics
87  if (instances == 0 && (theme != nullptr))
88  {
89  // Load the background skin
90  for (int i = 0; i < 2; i ++)
91  {
92  Skin *const skin = theme->load(dropdownFiles[i], "dropdown.xml");
93  if (skin != nullptr)
94  {
95  if (i == 0)
96  mSkin = skin;
97  const ImageRect &rect = skin->getBorder();
98  for (int f = 0; f < 2; f ++)
99  {
100  if (rect.grid[f] != nullptr)
101  {
102  rect.grid[f]->incRef();
103  buttons[f][i] = rect.grid[f];
104  buttons[f][i]->setAlpha(mAlpha);
105  }
106  else
107  {
108  buttons[f][i] = nullptr;
109  }
110  }
111  if (i != 0)
112  theme->unload(skin);
113  }
114  else
115  {
116  for (int f = 0; f < 2; f ++)
117  buttons[f][i] = nullptr;
118  }
119  }
120 
121  // get the border skin
122  theme->loadRect(skinRect, "dropdown_background.xml", "");
123  }
124 
125  instances++;
126 
127  setWidth(100);
128  setFocusable(true);
129  setListModel(listModel);
130 
131  if (mPopup->getSelected() < 0)
132  mPopup->setSelected(0);
133 
134  addMouseListener(this);
135  addKeyListener(this);
136  addFocusListener(this);
137 
138  adjustHeight();
139 // mPopup->setForegroundColorAll(getThemeColor(ThemeColorId::DROPDOWN),
140 // getThemeColor(ThemeColorId::DROPDOWN_OUTLINE));
143 
144  if (!eventId.empty())
145  setActionEventId(eventId);
146 
147  if (listener != nullptr)
148  addActionListener(listener);
149 
150  mPopup->adjustSize();
151 
152  if (mSkin != nullptr)
153  {
154  mSpacing = mSkin->getOption("spacing");
155  mFrameSize = CAST_U32(mSkin->getOption("frameSize"));
157  mImagePadding = mSkin->getOption("imagePadding");
158  }
159  adjustHeight();
160 }
161 
163 {
164  if (gui != nullptr)
165  gui->removeDragged(this);
166 
167  instances--;
168  if (instances == 0)
169  {
170  for (int f = 0; f < 2; f ++)
171  {
172  for (int i = 0; i < 2; i ++)
173  {
174  if (buttons[f][i] != nullptr)
175  buttons[f][i]->decRef();
176  }
177  }
178  if (theme != nullptr)
179  {
180  theme->unload(mSkin);
182  }
183  }
184 }
185 
187 {
188  const float alpha = std::max(settings.guiAlpha,
190 
191  if (mAlpha != alpha)
192  {
193  mAlpha = alpha;
194 
195  if (buttons[0][0] != nullptr)
196  buttons[0][0]->setAlpha(mAlpha);
197  if (buttons[0][1] != nullptr)
198  buttons[0][1]->setAlpha(mAlpha);
199  if (buttons[1][0] != nullptr)
200  buttons[1][0]->setAlpha(mAlpha);
201  if (buttons[1][1] != nullptr)
202  buttons[1][1]->setAlpha(mAlpha);
203 
204  for (int a = 0; a < 9; a++)
205  {
206  if (skinRect.grid[a] != nullptr)
208  }
209  }
210 }
211 
212 void DropDown::draw(Graphics *const graphics)
213 {
214  BLOCK_START("DropDown::draw")
215  int h;
216 
217  if (mDroppedDown)
218  h = mFoldedUpHeight;
219  else
220  h = mDimension.height;
221 
222  updateAlpha();
223 
224  const unsigned int alpha = CAST_U32(mAlpha * 255.0F);
225  const int pad = 2 * mPadding;
226  mHighlightColor.a = alpha;
227  mShadowColor.a = alpha;
228 
229  ListModel *const model = mPopup->getListModel();
230  if ((model != nullptr) && mPopup->getSelected() >= 0)
231  {
232  Font *const font = getFont();
233  if (mExtended)
234  {
235  const int sel = mPopup->getSelected();
236  ExtendedListModel *const model2
237  = static_cast<ExtendedListModel *>(model);
238  const Image *const image = model2->getImageAt(sel);
239  if (image == nullptr)
240  {
241  font->drawString(graphics,
244  model->getElementAt(sel),
245  mPadding, mPadding);
246  }
247  else
248  {
249  graphics->drawImage(image,
251  (mDimension.height - image->getHeight()) / 2 + mPadding);
252  font->drawString(graphics,
255  model->getElementAt(sel),
256  image->getWidth() + mImagePadding + mSpacing, mPadding);
257  }
258  }
259  else
260  {
261  font->drawString(graphics,
264  model->getElementAt(mPopup->getSelected()),
265  mPadding, mPadding);
266  }
267  }
268 
269  if (isFocused())
270  {
271  graphics->setColor(mHighlightColor);
272  graphics->drawRectangle(Rect(mPadding, mPadding,
273  mDimension.width - h - pad, h - pad));
274  }
275 
276  drawButton(graphics);
277 
278  if (mDroppedDown)
279  {
280  // Draw two lines separating the ListBox with selected
281  // element view.
282  const int w = mDimension.width;
283  graphics->setColor(mHighlightColor);
284  graphics->drawLine(0, h, w, h);
285  graphics->setColor(mShadowColor);
286  graphics->drawLine(0, h + 1, w, h + 1);
287  }
288  BLOCK_END("DropDown::draw")
289 }
290 
291 void DropDown::safeDraw(Graphics *const graphics)
292 {
293  DropDown::draw(graphics);
294 }
295 
296 void DropDown::drawFrame(Graphics *const graphics)
297 {
298  BLOCK_START("DropDown::drawFrame")
299  const int bs2 = CAST_S32(getFrameSize());
300  const Rect &rect = mDimension;
301  graphics->drawImageRect(0, 0,
302  rect.width + bs2, rect.height + bs2,
303  skinRect);
304  BLOCK_END("DropDown::drawFrame")
305 }
306 
307 void DropDown::safeDrawFrame(Graphics *const graphics)
308 {
309  BLOCK_START("DropDown::drawFrame")
310  const int bs2 = CAST_S32(getFrameSize());
311  const Rect &rect = mDimension;
312  graphics->drawImageRect(0, 0,
313  rect.width + bs2, rect.height + bs2,
314  skinRect);
315  BLOCK_END("DropDown::drawFrame")
316 }
317 
318 void DropDown::drawButton(Graphics *const graphics)
319 {
320  const int height = mDroppedDown ? mFoldedUpHeight : mDimension.height;
321 
322  Image *image = buttons[mDroppedDown][mPushed];
323  if (image != nullptr)
324  {
325  graphics->drawImage(image,
326  mDimension.width - image->getWidth() - mImagePadding,
327  (height - image->getHeight()) / 2);
328  }
329 }
330 
332 {
333  if (event.isConsumed())
334  return;
335 
336  const InputActionT actionId = event.getActionId();
337  PRAGMA45(GCC diagnostic push)
338  PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
339  switch (actionId)
340  {
343  dropDown();
344  break;
345 
346  case InputAction::GUI_UP:
347  setSelected(getSelected() - 1);
348  break;
349 
351  setSelected(getSelected() + 1);
352  break;
353 
355  setSelected(0);
356  break;
357 
359  if (mPopup->getListModel() != nullptr)
360  {
362  getNumberOfElements() - 1);
363  }
364  break;
365 
366  default:
367  return;
368  }
369  PRAGMA45(GCC diagnostic pop)
370 
371  event.consume();
372 }
373 
374 void DropDown::hideDrop(bool event)
375 {
376  if (event)
379 }
380 
382 {
383  event.consume();
384  // If we have a mouse press on the widget.
385  if (event.getButton() == MouseButton::LEFT
386  && !mDroppedDown && event.getSource() == this)
387  {
388  mPushed = true;
389  dropDown();
390  }
391  else
392  {
393  mPushed = false;
394  foldUp();
395  hideDrop();
396  }
397 }
398 
400 {
401  if (mIsDragged)
402  mPushed = false;
403 
404  const MouseButtonT button = event.getButton();
405  const int x = event.getX();
406  const int y = event.getY();
407  // Released outside of widget. Can happen when we have modal
408  // input focus.
409  if ((0 > y || y >= mDimension.height || x < 0 || x >= mDimension.width)
410  && button == MouseButton::LEFT)
411  {
412  if (mIsDragged)
413  foldUp();
414  }
415  else if (button == MouseButton::LEFT)
416  {
417  mPushed = false;
418  }
419 
420  mIsDragged = false;
421 }
422 
424 {
425  mIsDragged = true;
426  event.consume();
427 }
428 
430 {
431  setSelected(getSelected() - 1);
432  event.consume();
433 }
434 
436 {
437  setSelected(getSelected() + 1);
438  event.consume();
439 }
440 
441 void DropDown::setSelectedString(const std::string &str)
442 {
443  ListModel *const listModel = mPopup->getListModel();
444  if (listModel == nullptr)
445  return;
446 
447  for (int f = 0; f < listModel->getNumberOfElements(); f ++)
448  {
449  if (listModel->getElementAt(f) == str)
450  {
451  setSelected(f);
452  break;
453  }
454  }
455 }
456 
457 std::string DropDown::getSelectedString() const
458 {
459  ListModel *const listModel = mPopup->getListModel();
460  if (listModel == nullptr)
461  return "";
462 
463  return listModel->getElementAt(getSelected());
464 }
465 
467 {
468  setHeight(getFont()->getHeight() + 2 * mPadding);
469 }
470 
472 {
473  if (!mDroppedDown)
474  {
475  if (mParent == nullptr)
476  return;
477  mDroppedDown = true;
479  adjustHeight();
480 
481  int x = 0;
482  int y = 0;
483  getAbsolutePosition(x, y);
484  const int frame = CAST_S32(mParent->getFrameSize());
485  const int pad = mPopup->getPadding();
486  const int pad2 = pad * 2;
487 
488  // here width should be adjusted on some other parameters
489  mPopup->setWidth(mDimension.width - pad2 + 8);
490  mPopup->show(x - mPadding - frame - 1, y + mDimension.height);
492  mPopup->requestFocus();
493  }
494 }
495 
497 {
498  if (mDroppedDown)
499  {
500  mDroppedDown = false;
501  adjustHeight();
502  }
503 }
504 
506 {
507  return mPopup->getSelected();
508 }
509 
510 void DropDown::setSelected(int selected)
511 {
512  if (selected >= 0)
513  mPopup->setSelected(selected);
514 }
515 
516 void DropDown::setListModel(ListModel *const listModel)
517 {
518  mPopup->setListModel(listModel);
519 
520  if (mPopup->getSelected() < 0)
521  mPopup->setSelected(0);
522 
523  adjustHeight();
524 }
525 
527 {
528  return mPopup->getListModel();
529 }
530 
531 void DropDown::action(const ActionEvent &actionEvent A_UNUSED)
532 {
533  foldUp();
535 }
536 
538 {
539  if (mDroppedDown)
540  {
541  // Calculate the children area (with the one pixel border in mind)
542  return Rect(1, mFoldedUpHeight + 1,
544  }
545 
546  return Rect();
547 }
548 
550 {
551 }
552 
554 {
555  mDroppedDown = false;
556  mPushed = false;
559 }
560 
562 {
563  mSelectionListeners.push_back(selectionListener);
564 }
565 
567 {
568  mSelectionListeners.remove(listener);
569 }
570 
572 {
574  iter != mSelectionListeners.end();
575  ++iter)
576  {
577  SelectionEvent event(this);
578  (*iter)->valueChanged(event);
579  }
580 }
#define CAST_U32
Definition: cast.h:30
void removeSelectionListener(SelectionListener *selectionListener)
Definition: dropdown.cpp:566
int getPadding() const
Definition: popup.h:134
Font * getFont() const
Definition: widget.cpp:330
void setSelected(const int selected)
Definition: popuplist.cpp:106
int mFoldedUpHeight
Definition: dropdown.h:147
int width
Definition: rect.h:218
void safeDrawFrame(Graphics *const graphics)
Definition: dropdown.cpp:307
int getSelected() const
Definition: popuplist.cpp:114
Definition: skin.h:35
void setWidth(const int width)
Definition: widget.cpp:132
void unload(Skin *const skin)
Definition: theme.cpp:249
static void unloadRect(const ImageRect &rect, const int start=0, const int end=8)
Definition: theme.cpp:1118
Gui * gui
Definition: gui.cpp:110
Definition: font.h:88
Color mHighlightColor
Definition: dropdown.h:143
unsigned int a
Definition: color.h:250
const Color & getThemeColor(const ThemeColorIdT type, const unsigned int alpha=255U) const A_INLINE
Definition: widget2.h:44
PRAGMA45(GCC diagnostic push) PRAGMA45(GCC diagnostic ignored "-Wunused-result") int TestLauncher
Color mShadowColor
Definition: dropdown.h:142
virtual void drawImageRect(const int x, const int y, const int w, const int h, const ImageRect &imgRect)=0
void drawButton(Graphics *const graphics)
Definition: dropdown.cpp:318
void action(const ActionEvent &actionEvent)
Definition: dropdown.cpp:531
void addActionListener(ActionListener *const actionListener)
Definition: widget.cpp:251
void setVisible(Visible visible)
Definition: widget.cpp:224
void show(int x, int y)
Definition: popuplist.cpp:81
MouseButtonT getButton() const
Definition: mouseevent.h:113
float getMinimumOpacity() const
Definition: theme.h:124
Definition: rect.h:72
virtual void requestMoveToTop()
Definition: widget.cpp:212
SelectionListenerList mSelectionListeners
Definition: dropdown.h:150
#define BLOCK_START(name)
Definition: perfomance.h:78
void addFocusListener(FocusListener *const focusListener)
Definition: widget.cpp:281
void mousePressed(MouseEvent &event)
Definition: dropdown.cpp:381
ListModel * getListModel()
Definition: dropdown.cpp:526
SelectionListenerList::iterator SelectionListenerIterator
Definition: dropdown.h:151
void updateAlpha()
Definition: dropdown.cpp:186
#define BLOCK_END(name)
Definition: perfomance.h:79
virtual int getNumberOfElements()=0
void setActionEventId(const std::string &actionEventId)
Definition: widget.h:595
void mouseWheelMovedDown(MouseEvent &event)
Definition: dropdown.cpp:435
void setListModel(ListModel *const model)
Definition: popuplist.cpp:122
Color mForegroundColor
Definition: widget.h:1085
virtual void drawRectangle(const Rect &rectangle)=0
void keyPressed(KeyEvent &event)
Definition: dropdown.cpp:331
int getOption(const std::string &name) const
Definition: skin.h:105
virtual bool isFocused() const
Definition: widget.cpp:183
static int instances
Definition: dropdown.h:159
unsigned int getFrameSize() const
Definition: widget.h:183
void draw(Graphics *const graphics)
Definition: dropdown.cpp:212
void distributeActionEvent()
Definition: widget.cpp:492
static Skin * mSkin
Definition: dropdown.h:163
PopupList * mPopup
Definition: dropdown.h:141
void setSelectedString(const std::string &str)
Definition: dropdown.cpp:441
Settings settings
Definition: settings.cpp:31
virtual void setAlpha(const float alpha)
Definition: image.cpp:285
int getPadding() const
Definition: skin.h:99
bool mDroppedDown
Definition: dropdown.h:154
void setListModel(ListModel *const listModel)
Definition: dropdown.cpp:516
virtual void setColor(const Color &color)
Definition: graphics.h:319
#define CAST_S32
Definition: cast.h:29
virtual void requestFocus()
Definition: widget.cpp:203
int mPadding
Definition: dropdown.h:144
const ImageRect & getBorder() const
Definition: skin.h:67
void updateSelection()
Definition: dropdown.cpp:553
Image * grid[9]
Definition: imagerect.h:41
void adjustHeight()
Definition: dropdown.cpp:466
const bool Visible_false
Definition: visible.h:29
Widget * mParent
Definition: widget.h:1127
virtual const Image * getImageAt(int i)=0
DropDown(const Widget2 *const widget, ListModel *const listModel, const bool extended=false, const Modal modal=Modal_false, ActionListener *const listener=0, const std::string &eventId="")
Definition: dropdown.cpp:55
unsigned int mFrameSize
Definition: widget.h:1137
void drawString(Graphics *const graphics, Color col, const Color &col2, const std::string &text, const int x, const int y)
Definition: font.cpp:253
void drawFrame(Graphics *const graphics)
Definition: dropdown.cpp:296
InputAction ::T InputActionT
Definition: inputaction.h:714
bool mAllowLogic
Definition: widget.h:1159
void addMouseListener(MouseListener *const mouseListener)
Definition: widget.cpp:291
void dropDown()
Definition: dropdown.cpp:471
void loadRect(ImageRect &image, const std::string &name, const std::string &name2, const int start=0, const int end=8)
Definition: theme.cpp:1092
int height
Definition: rect.h:223
void addKeyListener(KeyListener *const keyListener)
Definition: widget.cpp:271
void mouseDragged(MouseEvent &event)
Definition: dropdown.cpp:423
virtual void getAbsolutePosition(int &x, int &y) const
Definition: widget.cpp:311
bool isConsumed() const
virtual std::string getElementAt(int i)=0
bool mIsDragged
Definition: dropdown.h:156
std::string getSelectedString() const
Definition: dropdown.cpp:457
void foldUp()
Definition: dropdown.cpp:496
bool mPushed
Definition: dropdown.h:155
void setHeight(const int height)
Definition: widget.cpp:139
virtual void incRef()
Definition: resource.cpp:37
Skin * load(const std::string &filename, const std::string &filename2, const bool full=true, const std::string &defaultPath=getThemePath())
Definition: theme.cpp:178
void mouseWheelMovedUp(MouseEvent &event)
Definition: dropdown.cpp:429
Theme * theme
Definition: theme.cpp:61
#define A_UNUSED
Definition: localconsts.h:171
void setFocusable(const bool focusable)
Definition: widget.cpp:191
void addSelectionListener(SelectionListener *listener)
Definition: dropdown.cpp:561
Rect getChildrenArea()
Definition: dropdown.cpp:537
Color mForegroundColor2
Definition: widget2.h:112
virtual void drawImage(const Image *const image, int dstX, int dstY)=0
void removeDragged(const Widget *const widget)
Definition: gui.cpp:1144
virtual void drawLine(int x1, int y1, int x2, int y2)=0
static ImageRect skinRect
Definition: dropdown.h:161
void mouseReleased(MouseEvent &event)
Definition: dropdown.cpp:399
Definition: image.h:61
int getHeight() const
Definition: widget.h:239
int getWidth() const A_INLINE
Definition: image.h:116
void distributeValueChangedEvent()
Definition: dropdown.cpp:571
static Image * buttons[2][2]
Definition: dropdown.h:160
ListModel * getListModel() const
Definition: popuplist.h:62
void valueChanged(const SelectionEvent &event) A_CONST
Definition: dropdown.cpp:549
#define CREATEWIDGETR(type,...)
Definition: createwidget.h:35
void adjustSize()
Definition: popuplist.cpp:129
float guiAlpha
Definition: settings.h:129
void hideDrop(bool event=true)
Definition: dropdown.cpp:374
MouseButton ::T MouseButtonT
Definition: mousebutton.h:77
Rect mDimension
Definition: widget.h:1100
void setSelected(int selected)
Definition: dropdown.cpp:510
int mSpacing
Definition: dropdown.h:146
void decRef()
Definition: image.cpp:521
bool mExtended
Definition: dropdown.h:153
int getSelected() const
Definition: dropdown.cpp:505
static float mAlpha
Definition: dropdown.h:162
void safeDraw(Graphics *const graphics)
Definition: dropdown.cpp:291
int mImagePadding
Definition: dropdown.h:145
int getHeight() const A_INLINE
Definition: image.h:122