/*  $Id: listbox_silver.cpp,v 1.9 2004/01/04 17:40:51 sphair Exp $
**
**  ClanLib Game SDK
**  Copyright (C) 2003  The ClanLib Team
**  For a total list of contributers see the file CREDITS.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This library 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
**  Lesser General Public License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
**
*/

#include "API/Display/font.h"
#include "API/Display/display.h"
#include "API/Display/keys.h"
#include "API/GUI/scrollbar.h"
#include "API/GUI/listitem.h"
#include "API/GUIStyleSilver/listbox_silver.h"
#include "API/GUIStyleSilver/stylemanager_silver.h"

/////////////////////////////////////////////////////////////////////////////
// Construction:

CL_ListBox_Silver::CL_ListBox_Silver(
	CL_ListBox *listbox,
	CL_StyleManager_Silver *style)
:
	CL_ComponentStyle(listbox),
	listbox(listbox),
	style(style)
{
	resources = style->get_resources();
	font = new CL_Font("ListBox/font", resources);

	// Create a vertical scrollbar
	scrollbar = new CL_ScrollBar(false, listbox);
	visible_scrollbar = true;

	int font_height = font->get_height();
	listbox->set_item_height(font_height);

	CL_Component *client_area = listbox->get_client_area();

	slots.connect(listbox->sig_set_options(), this, &CL_ListBox_Silver::on_set_options);
	slots.connect(listbox->sig_paint(), this, &CL_ListBox_Silver::on_paint_background);
	slots.connect(client_area->sig_mouse_down(), this, &CL_ListBox_Silver::on_mouse_down);
	slots.connect(client_area->sig_paint(), this, &CL_ListBox_Silver::on_paint_listbox);
	slots.connect(listbox->sig_resize(), this, &CL_ListBox_Silver::on_resize);
	slots.connect(listbox->sig_item_added(), this, &CL_ListBox_Silver::on_item_added);
	slots.connect(listbox->sig_item_removed(), this, &CL_ListBox_Silver::on_item_removed);
	slots.connect(listbox->sig_clear(), this, &CL_ListBox_Silver::on_clear);
	slots.connect(scrollbar->sig_value_changed(), this, &CL_ListBox_Silver::on_scroll_change);

	on_resize(0,0);
}

CL_ListBox_Silver::~CL_ListBox_Silver()
{
	delete font;
	delete scrollbar;
}

/////////////////////////////////////////////////////////////////////////////
// Callbacks:

void CL_ListBox_Silver::on_item_added(int index)
{
	update_scrollbar(true);
}

void CL_ListBox_Silver::on_item_removed(int index)
{
	update_scrollbar(true);
}

void CL_ListBox_Silver::on_clear()
{
	update_scrollbar(true);
}

void CL_ListBox_Silver::on_set_options(const CL_DomElement &options)
{
}

void CL_ListBox_Silver::on_scroll_change(int new_offset)
{
	listbox->set_top_item(new_offset);
}

void CL_ListBox_Silver::on_mouse_down(const CL_InputEvent &key)
{
	if(key.id == CL_MOUSE_WHEEL_UP)
	{
		listbox->set_top_item(listbox->get_top_item() - 5);
		update_scrollbar(true);
		return;
	}
	if(key.id == CL_MOUSE_WHEEL_DOWN)
	{
		listbox->set_top_item(listbox->get_top_item() + 5);
		update_scrollbar(true);
		return;
	}
}

void CL_ListBox_Silver::on_resize(int old_width, int old_height)
{
	// Position the listbox item-box
	CL_Rect rect(4, 4, 4 + listbox->get_width() - 8 , 4 + listbox->get_height() - 8);
	listbox->get_client_area()->set_position(rect);

	update_scrollbar(false);

	// Scrollbar was added, shrink clientarea
	if(visible_scrollbar)
	{
		listbox->get_client_area()->set_width(listbox->get_client_area()->get_width() - 19);

		// Position the scrollbar
		rect = CL_Rect(listbox->get_width() - 19, 3, listbox->get_width() - 3, listbox->get_height() - 3);
		scrollbar->set_position(rect);
	}
}

void CL_ListBox_Silver::on_paint_background()
{
	int width = listbox->get_width();
	int height = listbox->get_height();

	// Outline
	CL_Display::draw_rect(CL_Rect(0, 0, width, height), CL_Color(128, 142, 159));

	// Background
	CL_Display::fill_rect(CL_Rect(1, 1, width - 1, height - 1), CL_Color::white);
}

void CL_ListBox_Silver::on_paint_listbox()
{
	int width = listbox->get_client_area()->get_width();

	int pos = 0;

	int font_height = font->get_height();

	std::vector<CL_ListItem *> items = listbox->get_items();
	std::vector<CL_ListItem *>::iterator it;
	int offset = listbox->get_top_item();
	for (it = items.begin(); it != items.end(); it++)
	{
		if(pos < listbox->get_top_item())
		{
			++pos;
			continue;
		}

		if((*it)->selected)
		{
			CL_Display::fill_rect(
				CL_Rect(
					0,
					(pos - offset) * font_height,
					width,
					(pos + 1 - offset) * font_height),
				CL_Gradient(
					CL_Color(254, 207, 147),
					CL_Color::white,
					CL_Color(254, 207, 147),
					CL_Color::white));
		}

		font->draw(
			0,
			(pos - offset) * font_height,
			(*it)->str);

		pos++;
	}
}

/////////////////////////////////////////////////////////////////////////////
// Implementation:

void CL_ListBox_Silver::update_scrollbar(bool resize)
{	
	int max_visible_items = (listbox->get_client_area()->get_height() - 4) / listbox->get_item_height();

	if(listbox->get_count() > max_visible_items)
	{
		if(visible_scrollbar == false)
		{
			visible_scrollbar = true;
			listbox->add_child(scrollbar, false);

			if(resize)
				on_resize(0,0);
		}

		scrollbar->set_max_value(listbox->get_count() - max_visible_items);
		scrollbar->set_value(listbox->get_top_item());
	}
	else
	{
		if(visible_scrollbar)
		{
			visible_scrollbar = false;
			scrollbar->set_value(0);
			listbox->remove_child(scrollbar);

			if(resize)
				on_resize(0,0);
		}
	}
}
