/*
* Copyright 2010-2016 OpenXcom Developers.
*
* This file is part of OpenXcom.
*
* OpenXcom is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenXcom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScrollBar.h"
#include "../fmath.h"
#include <algorithm>
#include "../Engine/Action.h"
#include "TextList.h"
#include "../Engine/Palette.h"
namespace OpenXcom
{
/**
* Sets up a scrollbar with the specified size and position.
* @param width Width in pixels.
* @param height Height in pixels.
* @param x X position in pixels.
* @param y Y position in pixels.
*/
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)
{
_track = new Surface(width-2, height, x+1, y);
_thumb = new Surface(width, height, x, y);
_thumbRect.x = 0;
_thumbRect.y = 0;
_thumbRect.w = 0;
_thumbRect.h = 0;
}
/**
* Deletes contents.
*/
ScrollBar::~ScrollBar()
{
delete _track;
delete _thumb;
}
/**
* Changes the position of the surface in the X axis.
* @param x X position in pixels.
*/
void ScrollBar::setX(int x)
{
Surface::setX(x);
_track->setX(x+1);
_thumb->setX(x);
}
/**
* Changes the position of the surface in the Y axis.
* @param y Y position in pixels.
*/
void ScrollBar::setY(int y)
{
Surface::setY(y);
_track->setY(y);
_thumb->setY(y);
}
/**
* Changes the height of the scrollbar.
* @param height New height in pixels.
*/
void ScrollBar::setHeight(int height)
{
Surface::setHeight(height);
_track->setHeight(height);
_thumb->setHeight(height);
_redraw = true;
}
/**
* Changes the color used to render the scrollbar.
* @param color Color value.
*/
void ScrollBar::setColor(Uint8 color)
{
_color = color;
}
/**
* Returns the color used to render the scrollbar.
* @return Color value.
*/
Uint8 ScrollBar::getColor() const
{
return _color;
}
/**
* Enables/disables high contrast color. Mostly used for
* Battlescape text.
* @param contrast High contrast setting.
*/
void ScrollBar::setHighContrast(bool contrast)
{
_contrast = contrast;
}
/**
* Changes the list associated with the scrollbar.
* This makes the button scroll that list.
* @param list Pointer to text list.
*/
void ScrollBar::setTextList(TextList *list)
{
_list = list;
}
/**
* Changes the surface used to draw the background of the track.
* @param bg New background.
*/
void ScrollBar::setBackground(Surface *bg)
{
_bg = bg;
}
/**
* Replaces a certain amount of colors in the scrollbar's palette.
* @param colors Pointer to the set of colors.
* @param firstcolor Offset of the first color to replace.
* @param ncolors Amount of colors to replace.
*/
void ScrollBar::setPalette(SDL_Color *colors, int firstcolor, int ncolors)
{
Surface::setPalette(colors, firstcolor, ncolors);
_track->setPalette(colors, firstcolor, ncolors);
_thumb->setPalette(colors, firstcolor, ncolors);
}
/**
* Automatically updates the scrollbar
* when the mouse moves.
* @param action Pointer to an action.
* @param state State that the action handlers belong to.
*/
void ScrollBar::handle(Action *action, State *state)
{
InteractiveSurface::handle(action, state);
if (_pressed && (action->getDetails()->type == SDL_MOUSEMOTION || action->getDetails()->type == SDL_MOUSEBUTTONDOWN))
{
int cursorY = action->getAbsoluteYMouse() - getY();
int y = Clamp(cursorY + _offset, 0, getHeight() - _thumbRect.h + 1);
double scale = (double)_list->getRows() / getHeight();
int scroll = (int)Round(y * scale);
_list->scrollTo(scroll);
}
}
/**
* Blits the scrollbar contents.
* @param surface Pointer to surface to blit onto.
*/
void ScrollBar::blit(Surface *surface)
{
Surface::blit(surface);
if (_visible && !_hidden)
{
_track->blit(surface);
_thumb->blit(surface);
invalidate();
}
}
/**
* The scrollbar only moves while the button is pressed.
* @param action Pointer to an action.
* @param state State that the action handlers belong to.
*/
void ScrollBar::mousePress(Action *action, State *state)
{
InteractiveSurface::mousePress(action, state);
if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
{
int cursorY = action->getAbsoluteYMouse() - getY();
if (cursorY >= _thumbRect.y && cursorY < _thumbRect.y + _thumbRect.h)
{
_offset = _thumbRect.y - cursorY;
}
else
{
_offset = -_thumbRect.h / 2;
}
_pressed = true;
}
else if (action->getDetails()->button.button == SDL_BUTTON_WHEELUP)
{
_list->scrollUp(false, true);
}
else if (action->getDetails()->button.button == SDL_BUTTON_WHEELDOWN)
{
_list->scrollDown(false, true);
}
}
/**
* The scrollbar stops moving when the button is released.
* @param action Pointer to an action.
* @param state State that the action handlers belong to.
*/
void ScrollBar::mouseRelease(Action *action, State *state)
{
InteractiveSurface::mouseRelease(action, state);
if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
{
_pressed = false;
_offset = 0;
}
}
/**
* Updates the thumb according to the current list position.
*/
void ScrollBar::draw()
{
Surface::draw();
drawTrack();
drawThumb();
}
/**
* Draws the track (background bar) semi-transparent.
*/
void ScrollBar::drawTrack()
{
if (_bg)
{
_track->copy(_bg);
if (_list->getComboBox())
{
_track->offset(+1, Palette::backPos);
}
else
{
_track->offsetBlock(-5);
}
}
}
/**
* Draws the thumb (button) as a hollow square.
*/
void ScrollBar::drawThumb()
{
double scale = (double)getHeight() / _list->getRows();
_thumbRect.x = 0;
_thumbRect.y = (int)floor(_list->getScroll() * scale);
_thumbRect.w = _thumb->getWidth();
_thumbRect.h = (int)ceil(_list->getVisibleRows() * scale);
// Draw base button
_thumb->clear();
_thumb->lock();
SDL_Rect square = _thumbRect;
int color = _color + 2;
square.w--;
square.h--;
_thumb->drawRect(&square, color);
square.x++;
square.y++;
color = _color + 5;
_thumb->drawRect(&square, color);
square.w--;
square.h--;
color = _color + 4;
_thumb->drawRect(&square, color);
_thumb->setPixel(_thumbRect.x, _thumbRect.y, _color + 1);
_thumb->setPixel(_thumbRect.x, _thumbRect.y + _thumbRect.h - 1, _color + 4);
_thumb->setPixel(_thumbRect.x + _thumbRect.w - 1, _thumbRect.y, _color + 4);
// Hollow it out
if ((int)square.h - 4 > 0)
{
color = _color + 5;
square.x++;
square.y++;
square.w -= 3;
square.h -= 3;
_thumb->drawRect(&square, color);
square.x++;
square.y++;
color = _color + 2;
_thumb->drawRect(&square, color);
square.w--;
square.h--;
color = 0;
_thumb->drawRect(&square, color);
_thumb->setPixel(_thumbRect.x + 2 + _thumbRect.w - 1 - 4, _thumbRect.y + 2 + _thumbRect.h - 1 - 4, _color + 1);
_thumb->setPixel(_thumbRect.x + 2, _thumbRect.y + 2 + _thumbRect.h - 1 - 4, _color + 4);
_thumb->setPixel(_thumbRect.x + 2 + _thumbRect.w - 1 - 4, _thumbRect.y + 2, _color + 4);
}
_thumb->unlock();
}
}
↑ V807 Decreased performance. Consider creating a reference to avoid using the 'action->getDetails()->button' expression repeatedly.