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