/*
 * 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 "ArrowButton.h"
#include "TextList.h"
#include "../Engine/Timer.h"
#include "../Engine/Action.h"
 
namespace OpenXcom
{
 
/**
 * Sets up an arrow button with the specified size and position.
 * @param shape Shape of the arrow.
 * @param width Width in pixels.
 * @param height Height in pixels.
 * @param x X position in pixels.
 * @param y Y position in pixels.
 */
ArrowButton::ArrowButton(ArrowShape shape, int width, int height, int x, int y) : ImageButton(width, height, x, y), _shape(shape), _list(0)
{
	_timer = new Timer(50);
	_timer->onTimer((SurfaceHandler)&ArrowButton::scroll);
}
 
/**
 * Deletes timers.
 */
ArrowButton::~ArrowButton()
{
	delete _timer;
}
 
bool ArrowButton::isButtonHandled(Uint8 button)
{
	if (_list != 0)
	{
		return (button == SDL_BUTTON_LEFT || button == SDL_BUTTON_RIGHT);
	}
	else
	{
		return ImageButton::isButtonHandled(button);
	}
}
 
/**
 * Changes the color for the image button.
 * @param color Color value.
 */
void ArrowButton::setColor(Uint8 color)
{
	ImageButton::setColor(color);
	_redraw = true;
}
 
/**
 * Changes the shape for the arrow button.
 * @param shape Shape of the arrow.
 */
void ArrowButton::setShape(ArrowShape shape)
{
	_shape = shape;
	_redraw = true;
}
 
/**
 * Changes the list associated with the arrow button.
 * This makes the button scroll that list.
 * @param list Pointer to text list.
 */
void ArrowButton::setTextList(TextList *list)
{
	_list = list;
}
 
/**
 * Draws the button with the specified arrow shape.
 */
void ArrowButton::draw()
{
	ImageButton::draw();
	lock();
 
	// Draw button
	SDL_Rect square;
	int color = _color + 2;
 
	square.x = 0;
	square.y = 0;
	square.w = getWidth() - 1;
	square.h = getHeight() - 1;
 
	drawRect(&square, color);
 
	square.x++;
	square.y++;
	color = _color + 5;
 
	drawRect(&square, color);
 
	square.w--;
	square.h--;
	color = _color + 4;
 
	drawRect(&square, color);
 
	setPixel(0, 0, _color + 1);
	setPixel(0, getHeight() - 1, _color + 4);
	setPixel(getWidth() - 1, 0, _color + 4);
 
	color = _color + 1;
 
	switch (_shape)
	{
	case OpenXcom::ARROW_BIG_UP:
		// Draw arrow square
		square.x = 5;
		square.y = 8;
		square.w = 3;
		square.h = 3;
 
		drawRect(&square, color);
 
		// Draw arrow triangle
		square.x = 2;
		square.y = 7;
		square.w = 9;
		square.h = 1;
 
		for (; square.w > 1; square.w -= 2)
		{
			drawRect(&square, color);
			square.x++;
			square.y--;
		}
		drawRect(&square, color);
		break;
	case OpenXcom::ARROW_BIG_DOWN:
		// Draw arrow square
		square.x = 5;
		square.y = 3;
		square.w = 3;
		square.h = 3;
 
		drawRect(&square, color);
 
		// Draw arrow triangle
		square.x = 2;
		square.y = 6;
		square.w = 9;
		square.h = 1;
 
		for (; square.w > 1; square.w -= 2)
		{
			drawRect(&square, color);
			square.x++;
			square.y++;
		}
		drawRect(&square, color);
		break;
	case OpenXcom::ARROW_SMALL_UP:
		// Draw arrow triangle 1
		square.x = 1;
		square.y = 5;
		square.w = 9;
		square.h = 1;
 
		for (; square.w > 1; square.w -= 2)
		{
			drawRect(&square, color + 2);
			square.x++;
			square.y--;
		}
		drawRect(&square, color + 2);
 
		// Draw arrow triangle 2
		square.x = 2;
		square.y = 5;
		square.w = 7;
		square.h = 1;
 
		for (; square.w > 1; square.w -= 2)
		{
			drawRect(&square, color);
			square.x++;
			square.y--;
		}
		drawRect(&square, color);
		break;
	case OpenXcom::ARROW_SMALL_DOWN:
		// Draw arrow triangle 1
		square.x = 1;
		square.y = 2;
		square.w = 9;
		square.h = 1;
 
		for (; square.w > 1; square.w -= 2)
		{
			drawRect(&square, color + 2);
			square.x++;
			square.y++;
		}
		drawRect(&square, color + 2);
 
		// Draw arrow triangle 2
		square.x = 2;
		square.y = 2;
		square.w = 7;
		square.h = 1;
 
		for (; square.w > 1; square.w -= 2)
		{
			drawRect(&square, color);
			square.x++;
			square.y++;
		}
		drawRect(&square, color);
		break;
	case OpenXcom::ARROW_SMALL_LEFT:
		// Draw arrow triangle 1
		square.x = 2;
		square.y = 4;
		square.w = 2;
		square.h = 1;
 
		for (; square.h < 5; square.h += 2)
		{
			drawRect(&square, color + 2);
			square.x += 2;
			square.y--;
		}
		square.w = 1;
		drawRect(&square, color + 2);
 
		// Draw arrow triangle 2
		square.x = 3;
		square.y = 4;
		square.w = 2;
		square.h = 1;
 
		for (; square.h < 5; square.h += 2)
		{
			drawRect(&square, color);
			square.x += 2;
			square.y--;
		}
		square.w = 1;
		drawRect(&square, color);
		break;
	case OpenXcom::ARROW_SMALL_RIGHT:
		// Draw arrow triangle 1
		square.x = 7;
		square.y = 4;
		square.w = 2;
		square.h = 1;
 
		for (; square.h < 5; square.h += 2)
		{
			drawRect(&square, color + 2);
			square.x -= 2;
			square.y--;
		}
		square.x++;
		square.w = 1;
		drawRect(&square, color + 2);
 
		// Draw arrow triangle 2
		square.x = 6;
		square.y = 4;
		square.w = 2;
		square.h = 1;
 
		for (; square.h < 5; square.h += 2)
		{
			drawRect(&square, color);
			square.x -= 2;
			square.y--;
		}
		square.x++;
		square.w = 1;
		drawRect(&square, color);
		break;
	default:
		break;
	}
 
	unlock();
}
 
/**
 * Keeps the scrolling timers running.
 */
void ArrowButton::think()
{
	_timer->think(0, this);
}
 
/**
 * Scrolls the list.
 */
void ArrowButton::scroll()
{
	if (_shape == ARROW_BIG_UP)
	{
		_list->scrollUp(false);
	}
	else if (_shape == ARROW_BIG_DOWN)
	{
		_list->scrollDown(false);
	}
}
 
/**
 * Starts scrolling the associated list.
 * @param action Pointer to an action.
 * @param state State that the action handlers belong to.
 */
void ArrowButton::mousePress(Action *action, State *state)
{
	ImageButton::mousePress(action, state);
	if (_list != 0)
	{
		if (action->getDetails()->button.button == SDL_BUTTON_LEFT)
		{
			_timer->start();
		}
		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);
	}
}
 
/*
 * Stops scrolling the associated list.
 * @param action Pointer to an action.
 * @param state State that the action handlers belong to.
 */
void ArrowButton::mouseRelease(Action *action, State *state)
{
	ImageButton::mouseRelease(action, state);
	if (_list != 0 && action->getDetails()->button.button == SDL_BUTTON_LEFT)
	{
		_timer->stop();
	}
}
 
/*
 * Scrolls the associated list to top or bottom.
 * @param action Pointer to an action.
 * @param state State that the action handlers belong to.
 */
void ArrowButton::mouseClick(Action *action, State *state)
{
	ImageButton::mouseClick(action, state);
	if (_list != 0 && SDL_BUTTON_RIGHT == action->getDetails()->button.button) {
		if (_shape == ARROW_BIG_UP) _list->scrollUp(true);
		else if (_shape == ARROW_BIG_DOWN) _list->scrollDown(true);
	}
}
 
}

V807 Decreased performance. Consider creating a reference to avoid using the 'action->getDetails()->button' expression repeatedly.