1 /*
2 * Copyright 2010-2014 OpenXcom Developers.
3 *
4 * This file is part of OpenXcom.
5 *
6 * OpenXcom is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenXcom is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "Slider.h"
20 #include "../fmath.h"
21 #include <algorithm>
22 #include "../Engine/Action.h"
23 #include "../Interface/TextButton.h"
24 #include "../Interface/Text.h"
25 #include "../Interface/Frame.h"
26
27 namespace OpenXcom
28 {
29
30 /**
31 * Sets up a slider with the specified size and position.
32 * @param width Width in pixels.
33 * @param height Height in pixels.
34 * @param x X position in pixels.
35 * @param y Y position in pixels.
36 */
Slider(int width,int height,int x,int y)37 Slider::Slider(int width, int height, int x, int y) : InteractiveSurface(width, height, x, y), _pos(0.0), _min(0), _max(100), _pressed(false), _change(0), _offsetX(0)
38 {
39 _thickness = 5;
40 _textness = 8;
41 _txtMinus = new Text(_textness, height - 2, x - 1, y);
42 _txtPlus = new Text(_textness, height - 2, x + width - _textness, y);
43 _frame = new Frame(width - _textness*2, _thickness, x + _textness, y + (height - _thickness) / 2);
44 _button = new TextButton(10, height, x, y);
45
46 _frame->setThickness(_thickness);
47
48 _txtMinus->setAlign(ALIGN_CENTER);
49 _txtMinus->setVerticalAlign(ALIGN_MIDDLE);
50 _txtMinus->setText(L"-");
51
52 _txtPlus->setAlign(ALIGN_CENTER);
53 _txtPlus->setVerticalAlign(ALIGN_MIDDLE);
54 _txtPlus->setText(L"+");
55
56 _minX = _frame->getX();
57 _maxX = _frame->getX() + _frame->getWidth() - _button->getWidth();
58
59 setValue(_pos);
60 }
61
62 /**
63 * Deletes contents.
64 */
~Slider()65 Slider::~Slider()
66 {
67 delete _txtMinus;
68 delete _txtPlus;
69 delete _frame;
70 delete _button;
71 }
72
73 /**
74 * Changes the position of the surface in the X axis.
75 * @param x X position in pixels.
76 */
setX(int x)77 void Slider::setX(int x)
78 {
79 Surface::setX(x);
80 _txtMinus->setX(x - 1);
81 _txtPlus->setX(x + getWidth() - _textness);
82 _frame->setX(getX() + _textness);
83
84 _minX = _frame->getX();
85 _maxX = _frame->getX() + _frame->getWidth() - _button->getWidth();
86 setValue(_pos);
87 }
88
89 /**
90 * Changes the position of the surface in the Y axis.
91 * @param y Y position in pixels.
92 */
setY(int y)93 void Slider::setY(int y)
94 {
95 Surface::setY(y);
96 _txtMinus->setY(y);
97 _txtPlus->setY(y);
98 _frame->setY(getY() + (getHeight() - _thickness) / 2);
99 _button->setY(getY());
100 }
101
102 /**
103 * Changes the various resources needed for text rendering.
104 * The different fonts need to be passed in advance since the
105 * text size can change mid-text, and the language affects
106 * how the text is rendered.
107 * @param big Pointer to large-size font.
108 * @param small Pointer to small-size font.
109 * @param lang Pointer to current language.
110 */
initText(Font * big,Font * small,Language * lang)111 void Slider::initText(Font *big, Font *small, Language *lang)
112 {
113 _txtMinus->initText(big, small, lang);
114 _txtPlus->initText(big, small, lang);
115 _button->initText(big, small, lang);
116 }
117
118 /**
119 * Enables/disables high contrast color. Mostly used for
120 * Battlescape.
121 * @param contrast High contrast setting.
122 */
setHighContrast(bool contrast)123 void Slider::setHighContrast(bool contrast)
124 {
125 _txtMinus->setHighContrast(contrast);
126 _txtPlus->setHighContrast(contrast);
127 _frame->setHighContrast(contrast);
128 _button->setHighContrast(contrast);
129 }
130
131 /**
132 * Changes the color used to render the slider.
133 * @param color Color value.
134 */
setColor(Uint8 color)135 void Slider::setColor(Uint8 color)
136 {
137 _txtMinus->setColor(color);
138 _txtPlus->setColor(color);
139 _frame->setColor(color);
140 _button->setColor(color);
141 }
142
143 /**
144 * Returns the color used to render the slider.
145 * @return Color value.
146 */
getColor() const147 Uint8 Slider::getColor() const
148 {
149 return _button->getColor();
150 }
151
152 /**
153 * Replaces a certain amount of colors in the slider's palette.
154 * @param colors Pointer to the set of colors.
155 * @param firstcolor Offset of the first color to replace.
156 * @param ncolors Amount of colors to replace.
157 */
setPalette(SDL_Color * colors,int firstcolor,int ncolors)158 void Slider::setPalette(SDL_Color *colors, int firstcolor, int ncolors)
159 {
160 Surface::setPalette(colors, firstcolor, ncolors);
161 _txtMinus->setPalette(colors, firstcolor, ncolors);
162 _txtPlus->setPalette(colors, firstcolor, ncolors);
163 _frame->setPalette(colors, firstcolor, ncolors);
164 _button->setPalette(colors, firstcolor, ncolors);
165 }
166
167 /**
168 * Automatically updates the slider
169 * when the mouse moves.
170 * @param action Pointer to an action.
171 * @param state State that the action handlers belong to.
172 */
handle(Action * action,State * state)173 void Slider::handle(Action *action, State *state)
174 {
175 InteractiveSurface::handle(action, state);
176 //_button->handle(action, state);
177 if (_pressed && (action->getDetails()->type == SDL_MOUSEMOTION || action->getDetails()->type == SDL_MOUSEBUTTONDOWN))
178 {
179 int cursorX = action->getAbsoluteXMouse();
180 double buttonX = std::min(std::max(_minX, cursorX + _offsetX), _maxX);
181 double pos = (buttonX - _minX) / (_maxX - _minX);
182 int value = _min + (int)Round((_max - _min) * pos);
183 setValue(value);
184 if (_change)
185 {
186 (state->*_change)(action);
187 }
188 }
189 }
190
191 /**
192 * Moves the slider to the new position.
193 * @param value New value.
194 */
setPosition(double pos)195 void Slider::setPosition(double pos)
196 {
197 _pos = pos;
198 _button->setX((int)floor(_minX + (_maxX - _minX) * _pos));
199 }
200
201 /**
202 * Changes the range of values the slider
203 * can contain.
204 * @param min Minimum value.
205 * @param max Maximum value.
206 */
setRange(int min,int max)207 void Slider::setRange(int min, int max)
208 {
209 _min = min;
210 _max = max;
211 setValue(_value);
212 }
213
214 /**
215 * Changes the current value of the slider and
216 * positions it appropriately.
217 * @param value New value.
218 */
setValue(int value)219 void Slider::setValue(int value)
220 {
221 if (_min < _max)
222 {
223 _value = std::min(std::max(_min, value), _max);
224 }
225 else
226 {
227 _value = std::min(std::max(_max, value), _min);
228 }
229 double pos = (double)(_value - _min) / (double)(_max - _min);
230 setPosition(pos);
231 }
232
233 /**
234 * Returns the current value of the slider.
235 * @return Value.
236 */
getValue() const237 int Slider::getValue() const
238 {
239 return _value;
240 }
241
242 /**
243 * Blits the slider contents
244 * @param surface Pointer to surface to blit onto.
245 */
blit(Surface * surface)246 void Slider::blit(Surface *surface)
247 {
248 Surface::blit(surface);
249 if (_visible && !_hidden)
250 {
251 _txtMinus->blit(surface);
252 _txtPlus->blit(surface);
253 _frame->blit(surface);
254 _button->blit(surface);
255 }
256 }
257
258 /**
259 * The slider only moves while the button is pressed.
260 * @param action Pointer to an action.
261 * @param state State that the action handlers belong to.
262 */
mousePress(Action * action,State * state)263 void Slider::mousePress(Action *action, State *state)
264 {
265 InteractiveSurface::mousePress(action, state);
266 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
267 {
268 _pressed = true;
269 int cursorX = action->getAbsoluteXMouse();
270 if (cursorX >= _button->getX() && cursorX < _button->getX() + _button->getWidth())
271 {
272 _offsetX = _button->getX() - cursorX;
273 }
274 else
275 {
276 _offsetX = -_button->getWidth() / 2;
277 }
278 }
279 }
280
281 /**
282 * The slider stops moving when the button is released.
283 * @param action Pointer to an action.
284 * @param state State that the action handlers belong to.
285 */
mouseRelease(Action * action,State * state)286 void Slider::mouseRelease(Action *action, State *state)
287 {
288 InteractiveSurface::mouseRelease(action, state);
289 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
290 {
291 _pressed = false;
292 _offsetX = 0;
293 }
294 }
295
296 /**
297 * Sets a function to be called every time the slider's value changes.
298 * @param handler Action handler.
299 */
onChange(ActionHandler handler)300 void Slider::onChange(ActionHandler handler)
301 {
302 _change = handler;
303 }
304
305 }
306