ManaPlus
slider.cpp
Go to the documentation of this file.
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 
84 
85 #include "debug.h"
86 
88 float Slider::mAlpha = 1.0;
89 int Slider::mInstances = 0;
90 
91 static std::string const data[2] =
92 {
93  "slider.xml",
94  "slider_highlighted.xml"
95 };
96 
97 Slider::Slider(Widget2 *const widget,
98  const double scaleEnd,
99  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  mVertexes(new ImageCollection),
109  mMarkerLength(10),
110  mHasMouse(false)
111 {
112  init();
113 }
114 
115 Slider::Slider(Widget2 *const widget,
116  const double scaleStart,
117  const double scaleEnd,
118  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  mVertexes(new ImageCollection),
128  mMarkerLength(10),
129  mHasMouse(false)
130 {
131  init();
132 }
133 
135 {
136  if (gui != nullptr)
137  gui->removeDragged(this);
138 
140  mInstances--;
141  if (mInstances == 0)
142  {
143  for (int mode = 0; mode < 2; mode ++)
144  Theme::unloadRect(buttons[mode], 0, 8);
145  }
146 }
147 
149 {
150  mAllowLogic = false;
151  setFocusable(true);
152  setFrameSize(1);
153 
154  addMouseListener(this);
155  addKeyListener(this);
156 
157  setFrameSize(0);
158 
159  // Load resources
160  if (mInstances == 0)
161  {
162  if (theme != nullptr)
163  {
164  for (int mode = 0; mode < 2; mode ++)
165  theme->loadRect(buttons[mode], data[mode], "slider.xml", 0, 8);
166  }
167  updateAlpha();
168  }
169 
170  mInstances++;
171 
172  if (buttons[0].grid[SliderGrid::HGRIP] != nullptr)
174 }
175 
177 {
178  const float alpha = std::max(settings.guiAlpha,
180 
181  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 }
194 
195 void Slider::draw(Graphics *const graphics)
196 {
197  BLOCK_START("Slider::draw")
198  if ((buttons[0].grid[SliderGrid::HSTART] == nullptr) ||
199  (buttons[1].grid[SliderGrid::HSTART] == nullptr) ||
200  (buttons[0].grid[SliderGrid::HEND] == nullptr))
201  {
202  BLOCK_END("Slider::draw")
203  return;
204  }
205 
206  int w = getWidth();
207  const int h = getHeight();
208  const int y = mHasMouse ?
209  (h - buttons[1].grid[SliderGrid::HSTART]->getHeight()) / 2 :
210  (h - buttons[0].grid[SliderGrid::HSTART]->getHeight()) / 2;
211 
212  updateAlpha();
213 
214  if (mRedraw || graphics->getRedraw())
215  {
216  int x = 0;
217  mRedraw = false;
218  mVertexes->clear();
219  if (!mHasMouse)
220  {
221  graphics->calcTileCollection(mVertexes,
222  buttons[0].grid[SliderGrid::HSTART],
223  x, y);
224 
225  const int width = buttons[0].grid[SliderGrid::HSTART]->getWidth();
226  w -= width + buttons[0].grid[SliderGrid::HEND]->getWidth();
227  x += width;
228 
229  if (buttons[0].grid[SliderGrid::HMID] != nullptr)
230  {
231  const Image *const hMid = buttons[0].grid[SliderGrid::HMID];
232  graphics->calcPattern(mVertexes,
233  hMid,
234  x, y,
235  w, hMid->getHeight());
236  }
237 
238  x += w;
239  graphics->calcTileCollection(mVertexes,
240  buttons[0].grid[SliderGrid::HEND],
241  x, y);
242 
243  const Image *const img = buttons[0].grid[SliderGrid::HGRIP];
244  if (img != nullptr)
245  {
246  graphics->calcTileCollection(mVertexes,
247  img,
249  (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,
286  (mDimension.height - img->getHeight()) / 2);
287  }
288  }
289  graphics->finalize(mVertexes);
290  }
291  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 
371 {
372  mHasMouse = true;
373  mRedraw = true;
374 }
375 
377 {
378  mHasMouse = false;
379  mRedraw = true;
380 }
381 
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();
395  else
398  }
399 }
400 
402 {
404  {
406  }
407  else
408  {
410  mDimension.height - event.getY() - mMarkerLength / 2));
411  }
412 
414 
415  event.consume();
416 }
417 
419 {
422  event.consume();
423 }
424 
426 {
429  event.consume();
430 }
431 
433 {
434  const InputActionT action = event.getActionId();
435 
437  {
438  if (action == InputAction::GUI_RIGHT)
439  {
442  event.consume();
443  }
444  else if (action == InputAction::GUI_LEFT)
445  {
448  event.consume();
449  }
450  }
451  else
452  {
453  if (action == InputAction::GUI_UP)
454  {
457  event.consume();
458  }
459  else if (action == InputAction::GUI_DOWN)
460  {
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 void Slider::setValue(const double value)
475 {
476  mRedraw = true;
477  if (value > mScaleEnd)
478  mValue = mScaleEnd;
479  else if (value < mScaleStart)
481  else
482  mValue = value;
485 }
486 
487 double Slider::markerPositionToValue(const int v) const
488 {
489  int w;
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;
503  v = mDimension.width;
504  else
505  v = mDimension.height;
506 
507  const int w = CAST_S32((v - mMarkerLength)
508  * (value - mScaleStart)
509  / (mScaleEnd - mScaleStart));
510 
511  if (w < 0)
512  return 0;
513 
514  if (w > v - mMarkerLength)
515  return v - mMarkerLength;
516 
517  return w;
518 }
#define CAST_S32
Definition: cast.h:30
virtual void drawImage(const Image *const image, int dstX, int dstY)=0
virtual void drawTileCollection(const ImageCollection *const vertCol)=0
bool getRedraw() const
Definition: graphics.h:287
virtual void calcTileCollection(ImageCollection *const vertCol, const Image *const image, int x, int y)=0
virtual void calcPattern(ImageVertexes *const vert, const Image *const image, const int x, const int y, const int w, const int h) const =0
virtual void finalize(ImageCollection *const col)
Definition: graphics.h:465
virtual void drawPattern(const Image *const image, const int x, const int y, const int w, const int h)=0
void removeDragged(const Widget *const widget)
Definition: gui.cpp:1162
Image * grid[9]
Definition: imagerect.h:42
MouseButtonT getButton() const
Definition: mouseevent.h:116
int getX() const
Definition: mouseevent.h:127
int getY() const
Definition: mouseevent.h:138
int width
Definition: rect.h:219
int height
Definition: rect.h:224
float guiAlpha
Definition: settings.h:131
double markerPositionToValue(const int position) const
Definition: slider.cpp:487
int getMarkerPosition() const
Definition: slider.h:294
double mScaleEnd
Definition: slider.h:320
void setScale(const double scaleStart, const double scaleEnd)
Definition: slider.cpp:468
OrientationT mOrientation
Definition: slider.h:326
static ImageRect buttons[2]
Definition: slider.h:297
void mouseExited(MouseEvent &event)
Definition: slider.cpp:376
void init()
Definition: slider.cpp:148
void draw(Graphics *const graphics)
Definition: slider.cpp:195
double mStepLength
Definition: slider.h:310
void safeDraw(Graphics *const graphics)
Definition: slider.cpp:296
void setValue(const double value)
Definition: slider.cpp:474
ImageCollection * mVertexes
Definition: slider.h:328
void mouseEntered(MouseEvent &event)
Definition: slider.cpp:370
void setMarkerLength(const int length)
Definition: slider.h:222
static int mInstances
Definition: slider.h:299
void updateAlpha()
Definition: slider.cpp:176
static float mAlpha
Definition: slider.h:298
void mouseWheelMovedUp(MouseEvent &event)
Definition: slider.cpp:418
~Slider()
Definition: slider.cpp:134
bool mHasMouse
Definition: slider.h:335
void keyPressed(KeyEvent &event)
Definition: slider.cpp:432
void mouseDragged(MouseEvent &event)
Definition: slider.cpp:401
double mScaleStart
Definition: slider.h:315
Slider(Widget2 *const widget, const double scaleEnd, const double stepLength)
Definition: slider.cpp:97
double mValue
Definition: slider.h:304
void mousePressed(MouseEvent &event)
Definition: slider.cpp:382
void mouseWheelMovedDown(MouseEvent &event)
Definition: slider.cpp:425
int valueToMarkerPosition(const double value) const
Definition: slider.cpp:499
int mMarkerLength
Definition: slider.h:333
static void unloadRect(const ImageRect &rect, const int start, const int end)
Definition: theme.cpp:915
void loadRect(ImageRect &image, const std::string &name, const std::string &name2, const int start, const int end)
Definition: theme.cpp:883
float getMinimumOpacity() const
Definition: theme.h:124
Definition: widget.h:99
void setFrameSize(const unsigned int frameSize)
Definition: widget.h:168
void setFocusable(const bool focusable)
Definition: widget.cpp:192
void distributeActionEvent()
Definition: widget.cpp:493
Rect mDimension
Definition: widget.h:1101
bool mAllowLogic
Definition: widget.h:1160
void addMouseListener(MouseListener *const mouseListener)
Definition: widget.cpp:292
void addKeyListener(KeyListener *const keyListener)
Definition: widget.cpp:272
bool mRedraw
Definition: widget.h:1164
int getHeight() const
Definition: widget.h:240
int getWidth() const
Definition: widget.h:221
#define new
Definition: debug_new.h:147
#define delete2(var)
Definition: delete2.h:25
Gui * gui
Definition: gui.cpp:111
InputAction ::T InputActionT
Definition: inputaction.h:717
#define A_UNUSED
Definition: localconsts.h:160
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
Settings settings
Definition: settings.cpp:32
static std::string const data[2]
Definition: slider.cpp:91
Theme * theme
Definition: theme.cpp:62