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 "ScrollBar.h"
20 #include "../fmath.h"
21 #include <algorithm>
22 #include "../Engine/Action.h"
23 #include "../Interface/TextList.h"
24 #include "../Engine/Palette.h"
25
26 namespace OpenXcom
27 {
28
29 /**
30 * Sets up a scrollbar with the specified size and position.
31 * @param width Width in pixels.
32 * @param height Height in pixels.
33 * @param x X position in pixels.
34 * @param y Y position in pixels.
35 */
ScrollBar(int width,int height,int x,int y)36 ScrollBar::ScrollBar(int width, int height, int x, int y) : InteractiveSurface(width, height, x, y), _list(0), _color(0), _pressed(false), _contrast(false), _offset(0), _bg(0)
37 {
38 _track = new Surface(width-2, height, x+1, y);
39 _thumb = new Surface(width, height, x, y);
40 _thumbRect.x = 0;
41 _thumbRect.y = 0;
42 _thumbRect.w = 0;
43 _thumbRect.h = 0;
44 }
45
46 /**
47 * Deletes contents.
48 */
~ScrollBar()49 ScrollBar::~ScrollBar()
50 {
51 delete _track;
52 delete _thumb;
53 }
54
55 /**
56 * Changes the position of the surface in the X axis.
57 * @param x X position in pixels.
58 */
setX(int x)59 void ScrollBar::setX(int x)
60 {
61 Surface::setX(x);
62 _track->setX(x+1);
63 _thumb->setX(x);
64 }
65
66 /**
67 * Changes the position of the surface in the Y axis.
68 * @param y Y position in pixels.
69 */
setY(int y)70 void ScrollBar::setY(int y)
71 {
72 Surface::setY(y);
73 _track->setY(y);
74 _thumb->setY(y);
75 }
76
77 /**
78 * Changes the height of the scrollbar.
79 * @param height New height in pixels.
80 */
setHeight(int height)81 void ScrollBar::setHeight(int height)
82 {
83 Surface::setHeight(height);
84 _track->setHeight(height);
85 _thumb->setHeight(height);
86 _redraw = true;
87 }
88
89 /**
90 * Changes the color used to render the scrollbar.
91 * @param color Color value.
92 */
setColor(Uint8 color)93 void ScrollBar::setColor(Uint8 color)
94 {
95 _color = color;
96 }
97
98 /**
99 * Returns the color used to render the scrollbar.
100 * @return Color value.
101 */
getColor() const102 Uint8 ScrollBar::getColor() const
103 {
104 return _color;
105 }
106
107 /**
108 * Enables/disables high contrast color. Mostly used for
109 * Battlescape text.
110 * @param contrast High contrast setting.
111 */
setHighContrast(bool contrast)112 void ScrollBar::setHighContrast(bool contrast)
113 {
114 _contrast = contrast;
115 }
116
117 /**
118 * Changes the list associated with the scrollbar.
119 * This makes the button scroll that list.
120 * @param list Pointer to text list.
121 */
setTextList(TextList * list)122 void ScrollBar::setTextList(TextList *list)
123 {
124 _list = list;
125 }
126
127 /**
128 * Changes the surface used to draw the background of the track.
129 * @param bg New background.
130 */
setBackground(Surface * bg)131 void ScrollBar::setBackground(Surface *bg)
132 {
133 _bg = bg;
134 }
135
136 /**
137 * Replaces a certain amount of colors in the scrollbar's palette.
138 * @param colors Pointer to the set of colors.
139 * @param firstcolor Offset of the first color to replace.
140 * @param ncolors Amount of colors to replace.
141 */
setPalette(SDL_Color * colors,int firstcolor,int ncolors)142 void ScrollBar::setPalette(SDL_Color *colors, int firstcolor, int ncolors)
143 {
144 Surface::setPalette(colors, firstcolor, ncolors);
145 _track->setPalette(colors, firstcolor, ncolors);
146 _thumb->setPalette(colors, firstcolor, ncolors);
147 }
148
149 /**
150 * Automatically updates the scrollbar
151 * when the mouse moves.
152 * @param action Pointer to an action.
153 * @param state State that the action handlers belong to.
154 */
handle(Action * action,State * state)155 void ScrollBar::handle(Action *action, State *state)
156 {
157 InteractiveSurface::handle(action, state);
158 if (_pressed && (action->getDetails()->type == SDL_MOUSEMOTION || action->getDetails()->type == SDL_MOUSEBUTTONDOWN))
159 {
160 int cursorY = action->getAbsoluteYMouse() - getY();
161 int y = std::min(std::max(cursorY + _offset, 0), getHeight() - _thumbRect.h + 1);
162 double scale = (double)_list->getRows() / getHeight();
163 int scroll = (int)Round(y * scale);
164 _list->scrollTo(scroll);
165 }
166 }
167
168 /**
169 * Blits the scrollbar contents.
170 * @param surface Pointer to surface to blit onto.
171 */
blit(Surface * surface)172 void ScrollBar::blit(Surface *surface)
173 {
174 Surface::blit(surface);
175 if (_visible && !_hidden)
176 {
177 _track->blit(surface);
178 _thumb->blit(surface);
179 invalidate();
180 }
181 }
182
183 /**
184 * The scrollbar only moves while the button is pressed.
185 * @param action Pointer to an action.
186 * @param state State that the action handlers belong to.
187 */
mousePress(Action * action,State * state)188 void ScrollBar::mousePress(Action *action, State *state)
189 {
190 InteractiveSurface::mousePress(action, state);
191 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
192 {
193 int cursorY = action->getAbsoluteYMouse() - getY();
194 if (cursorY >= _thumbRect.y && cursorY < _thumbRect.y + _thumbRect.h)
195 {
196 _offset = _thumbRect.y - cursorY;
197 }
198 else
199 {
200 _offset = -_thumbRect.h / 2;
201 }
202 _pressed = true;
203 }
204 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP)
205 {
206 _list->scrollUp(false, true);
207 }
208 else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN)
209 {
210 _list->scrollDown(false, true);
211 }
212 }
213
214 /**
215 * The scrollbar stops moving when the button is released.
216 * @param action Pointer to an action.
217 * @param state State that the action handlers belong to.
218 */
mouseRelease(Action * action,State * state)219 void ScrollBar::mouseRelease(Action *action, State *state)
220 {
221 InteractiveSurface::mouseRelease(action, state);
222 if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
223 {
224 _pressed = false;
225 _offset = 0;
226 }
227 }
228
229 /**
230 * Updates the thumb according to the current list position.
231 */
draw()232 void ScrollBar::draw()
233 {
234 Surface::draw();
235 drawTrack();
236 drawThumb();
237 }
238
239 /**
240 * Draws the track (background bar) semi-transparent.
241 */
drawTrack()242 void ScrollBar::drawTrack()
243 {
244 if (_bg)
245 {
246 _track->copy(_bg);
247 if (_contrast)
248 {
249 _track->offset(-5, 1);
250 }
251 else if (_list->getComboBox())
252 {
253 _track->offset(+1, Palette::backPos);
254 }
255 else
256 {
257 _track->offset(-5, Palette::backPos);
258 }
259 }
260 }
261
262 /**
263 * Draws the thumb (button) as a hollow square.
264 */
drawThumb()265 void ScrollBar::drawThumb()
266 {
267 double scale = (double)getHeight() / _list->getRows();
268 _thumbRect.x = 0;
269 _thumbRect.y = (int)floor(_list->getScroll() * scale);
270 _thumbRect.w = _thumb->getWidth();
271 _thumbRect.h = (int)ceil(_list->getVisibleRows() * scale);
272
273 // Draw base button
274 _thumb->clear();
275 _thumb->lock();
276
277 SDL_Rect square = _thumbRect;
278 int color = _color + 2;
279
280 square.w--;
281 square.h--;
282
283 _thumb->drawRect(&square, color);
284
285 square.x++;
286 square.y++;
287 color = _color + 5;
288
289 _thumb->drawRect(&square, color);
290
291 square.w--;
292 square.h--;
293 color = _color + 4;
294
295 _thumb->drawRect(&square, color);
296
297 _thumb->setPixel(_thumbRect.x, _thumbRect.y, _color + 1);
298 _thumb->setPixel(_thumbRect.x, _thumbRect.y + _thumbRect.h - 1, _color + 4);
299 _thumb->setPixel(_thumbRect.x + _thumbRect.w - 1, _thumbRect.y, _color + 4);
300
301 // Hollow it out
302 color = _color + 5;
303
304 square.x++;
305 square.y++;
306 square.w-=3;
307 square.h-=3;
308
309 _thumb->drawRect(&square, color);
310
311 square.x++;
312 square.y++;
313 color = _color + 2;
314
315 _thumb->drawRect(&square, color);
316
317 square.w--;
318 square.h--;
319 color = 0;
320
321 _thumb->drawRect(&square, color);
322
323 _thumb->setPixel(_thumbRect.x + 2 + _thumbRect.w - 1 - 4, _thumbRect.y + 2 + _thumbRect.h - 1 - 4, _color + 1);
324 _thumb->setPixel(_thumbRect.x + 2, _thumbRect.y + 2 + _thumbRect.h - 1 - 4, _color + 4);
325 _thumb->setPixel(_thumbRect.x + 2 + _thumbRect.w - 1 - 4, _thumbRect.y + 2, _color + 4);
326
327 _thumb->unlock();
328 }
329
330 }
331