/*  $Id: treeview_silver.cpp,v 1.10 2004/04/11 15:37:31 mbn 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/display.h"
#include "API/Display/font.h"
#include "API/Display/keys.h"
#include "API/GUI/scrollbar.h"
#include "API/GUIStyleSilver/treeview_silver.h"
#include "API/GUIStyleSilver/stylemanager_silver.h"

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

CL_TreeView_Silver::CL_TreeView_Silver(
	CL_TreeView *treeview,
	CL_StyleManager_Silver *style)
:
	CL_ComponentStyle(treeview),
	treeview(treeview),
	style(style)
{
	CL_ResourceManager *resources = style->get_resources();
	font = new CL_Font("TreeView/font", resources);

	CL_Component *client_area = treeview->get_client_area();

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

	slots.connect(treeview->sig_paint(), this, &CL_TreeView_Silver::on_paint);
	slots.connect(client_area->sig_paint(), this, &CL_TreeView_Silver::on_paint_client);
	slots.connect(treeview->sig_paint_node(), this, &CL_TreeView_Silver::on_paint_node);
	slots.connect(client_area->sig_mouse_down(), this, &CL_TreeView_Silver::on_mouse_down);
	slots.connect(treeview->sig_resize(), this, &CL_TreeView_Silver::on_resize);
	slots.connect(treeview->sig_item_added(), this, &CL_TreeView_Silver::on_item_changed);
	slots.connect(treeview->sig_item_removed(), this, &CL_TreeView_Silver::on_item_changed);
	slots.connect(treeview->sig_item_expanded(), this, &CL_TreeView_Silver::on_item_changed);
	slots.connect(treeview->sig_item_collapsed(), this, &CL_TreeView_Silver::on_item_changed);
	slots.connect(treeview->sig_column_added(), this, &CL_TreeView_Silver::on_column_added);
	slots.connect(treeview->sig_column_removed(), this, &CL_TreeView_Silver::on_column_removed);
	slots.connect(treeview->sig_clear(), this, &CL_TreeView_Silver::on_clear);

	on_resize(0,0);
}

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

void CL_TreeView_Silver::on_item_changed(const CL_TreeNode &node)
{
	update_scrollbar(true);
}

void CL_TreeView_Silver::on_column_added(int index)
{
}

void CL_TreeView_Silver::on_column_removed(int index)
{
}
                                                               
void CL_TreeView_Silver::on_clear()
{
	update_scrollbar(true);
}

void CL_TreeView_Silver::on_mouse_down(const CL_InputEvent &key)
{
	if(key.id == CL_MOUSE_WHEEL_UP)
	{
		scrollbar->decrease(16);
		return;
	}
	if(key.id == CL_MOUSE_WHEEL_DOWN)
	{
		scrollbar->increase(16);
		return;
	}
}

void CL_TreeView_Silver::on_resize(int old_width, int old_height)
{
	int width = treeview->get_width();
	int height = treeview->get_height();

	int offset = 1;
	if(treeview->is_header_visible())
		offset = 21;

	// Position the treeview client area
	CL_Rect rect(1, offset, width - 1, height - 1);
	treeview->get_client_area()->set_position(rect);

	update_scrollbar(false);

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

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

void CL_TreeView_Silver::on_paint()
{
	int width = treeview->get_width();
	int height = treeview->get_height();
	int header_height = 20;

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

	if(treeview->is_header_visible())
	{
		// Header background
		CL_Display::fill_rect(
			CL_Rect(1, 1, width - 1, header_height - 4),
			CL_Gradient(
				CL_Color(245, 246, 247), CL_Color(245, 246, 247),
				CL_Color(235, 238, 241), CL_Color(235, 238, 241)));

		CL_Display::fill_rect(
			CL_Rect(1, header_height - 4, width - 1, header_height),
			CL_Gradient(
				CL_Color(235, 238, 241), CL_Color(235, 238, 241),
				CL_Color(186, 187, 188), CL_Color(186, 187, 188)));

		// Draw columns
		int x = 0;
		int columns = treeview->get_column_count();
		for(int i = 0; i < columns; ++i)
		{
			font->draw(x + 6, 4, treeview->get_column_name(i));
			x += treeview->get_column_width(i);
			CL_Display::draw_line(x, 1, x,  header_height, CL_Color(128, 142, 159));
			CL_Display::draw_line(x + 1, 1, x + 1,  header_height, CL_Color::white);
		}
	}
}

void CL_TreeView_Silver::on_paint_client()
{
	int width = treeview->get_client_area()->get_width();
	int height = treeview->get_client_area()->get_height();

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

void CL_TreeView_Silver::on_paint_node(CL_TreeNode *node, CL_Point &point)
{
	CL_Component *component = node->get_component();
	
	int height = component->get_height();
	int mid = (height) / 2;

	bool draw_decoration = true;
	if(node->is_root())
		draw_decoration = node->get_treeview()->is_root_decoration_visible();

	point.y -= scrollbar->get_value();

	int offset = 0;
	if(draw_decoration)
	{
		offset = 12;

		// Draw collapse box
		if(node->has_children())
		{
			CL_Display::draw_rect(
				CL_Rect(point.x, point.y + mid - 5, point.x + 9, point.y + mid + 4),
				CL_Color(128, 142, 159));

			CL_Display::fill_rect(
				CL_Rect(point.x + 1, point.y + mid - 4, point.x + 8, point.y + mid + 3),
				CL_Gradient(CL_Color::white, CL_Color::white, CL_Color(230, 235, 240), CL_Color(230, 235, 240)));

			CL_Display::fill_rect(
				CL_Rect(point.x + 2, point.y + mid - 3, point.x + 7, point.y + mid + 2),
				CL_Gradient(CL_Color(217, 222, 227), CL_Color(217, 222, 227), CL_Color::white, CL_Color::white));

			// Horizontal line
			CL_Display::draw_line(point.x + 2, point.y + mid - 1, point.x + 7, point.y + mid - 1, CL_Color(0, 0, 0));

			// Vertical line
			if(node->is_collapsed())
				CL_Display::draw_line(point.x + 4, point.y + mid - 3, point.x + 4, point.y + mid + 2, CL_Color(0, 0, 0));
		}
	}

	// Size and place child component
	component->set_position(point.x + offset, point.y);
	node->set_placement_offset(point.x + offset);

	// Draw component
	CL_Display::push_translate(point.x + offset, point.y);
	component->sig_paint()();
	CL_Display::pop_modelview();

	point.y += scrollbar->get_value();

	// Move down for next component
	point.y += height;

	// If it has any children, adjust the x-position for the children
	if(node->is_collapsed() == false)
		point.x += 3 + offset;
}

void CL_TreeView_Silver::update_scrollbar(bool resize)
{
	int max_height = treeview->get_items_height();
	int component_height = treeview->get_client_area()->get_height();

	if(max_height > component_height)
	{
		if(visible_scrollbar == false)
		{
			visible_scrollbar = true;
			treeview->add_child(scrollbar, false);

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

		scrollbar->set_max_value(max_height - component_height + 1);
		scrollbar->set_value(0);
	}
	else
	{
		if(visible_scrollbar)
		{
			visible_scrollbar = false;
			scrollbar->set_range(0, 0);
			scrollbar->set_value(0);
			treeview->remove_child(scrollbar);

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