/*  $Id: inputbox_silver.cpp,v 1.12 2004/05/08 09:22: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/font.h"
#include "API/Display/display.h"
#include "API/Core/System/system.h"
#include "API/Core/Resources/resource_manager.h"
#include "API/GUI/gui_manager.h"
#include "API/GUIStyleSilver/inputbox_silver.h"
#include "API/GUIStyleSilver/stylemanager_silver.h"

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

CL_InputBox_Silver::CL_InputBox_Silver(
	CL_InputBox *inputbox,
	CL_StyleManager_Silver *style)
: 
	CL_ComponentStyle(inputbox),
	inputbox(inputbox),
	style(style)
{
	resources = style->get_resources();
	
	font = new CL_Font("InputBox/font", resources);
	font_disabled = new CL_Font("InputBox/font_disabled", resources);

	show_cursor = false;
	character_offset = 0;
	cursor_blink_time = CL_System::get_time();

	set_border_size(3);

	slot_paint = inputbox->sig_paint().connect(
		this, &CL_InputBox_Silver::on_paint);
	slot_activity = inputbox->sig_activity().connect(
		this, &CL_InputBox_Silver::on_activity);
	slot_get_preferred_size = inputbox->sig_get_preferred_size().connect(
		this, &CL_InputBox_Silver::on_get_preferred_size);
}

CL_InputBox_Silver::~CL_InputBox_Silver()
{
	delete font;
	delete font_disabled;
}

/////////////////////////////////////////////////////////////////////////////
// Operations:

void CL_InputBox_Silver::set_border_size(int size)
{
	border_size = size;

	// Override height for font-height
	CL_Rect position = inputbox->get_position();
	position.bottom = position.top + font->get_height() + border_size * 2;
	inputbox->set_position(position);
}

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

void CL_InputBox_Silver::on_paint()
{
	int width = inputbox->get_width();
	int height = inputbox->get_height();

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

	// Outline
	if(inputbox->is_enabled() && inputbox->has_focus())
	{
		CL_Display::draw_rect(
			CL_Rect(0, 0, width, height), CL_Color(254, 207, 147));
		CL_Display::draw_rect(
			CL_Rect(1, 1, width - 1, height - 1), CL_Color(255, 147, 22));
	}
	else
	{
		CL_Display::draw_rect(CL_Rect(0, 0, width, height), CL_Color(128, 142, 159));
	}

	// For easy reference, put inputfield-text into local variable
	const char *text = inputbox->get_text().c_str();

	// Calculate scroll offset
	int character_offset = 0;
	int pixel_offset = 0;
	int text_width = (int) inputbox->in_password_mode() ? font->get_width('*')*strlen(text) : font->get_width(text);
	if (text_width > width - border_size * 2)
	{
		while (
			text_width >= width - border_size * 2 &&
			character_offset + 1 < inputbox->get_cursor_position())
		{
			int w = inputbox->in_password_mode() ? font->get_width('*') : font->get_width(text[character_offset]);
			character_offset++;
			pixel_offset += w;
			text_width -= w;
		}
	}

	// Display marked text, if any
	if(inputbox->has_focus()) 
	{
		if (inputbox->has_marked_text())
		{
			int start = inputbox->get_selection_start();
			int end = start + inputbox->get_selection_length();

			int mark_x1 = 0, mark_x2 = 0;

			int i;
			if (inputbox->in_password_mode())
			{
				int w = font->get_width('*');

				if (start > 0)
					mark_x1 += start*w;

				if (end > start)
					mark_x2 += (end-start)*w;
			}
			else
			{
				for(i = 0; i < start; i++)
					mark_x1 += font->get_width(text[i]);

				for(i = start; i < end; i++)
					mark_x2 += font->get_width(text[i]);
			}

			CL_Display::fill_rect(
				CL_Rect(
					border_size + mark_x1 - 1,
					border_size,
					border_size + mark_x1 + mark_x2,
					border_size + font->get_height()),
				CL_Color(204, 208, 232));
		}
	}

	// Display text
	if(inputbox->is_enabled() == false)
		if (inputbox->in_password_mode())
			font_disabled->draw(border_size, 2, std::string(strlen(text+character_offset), '*'));
		else
			font_disabled->draw(border_size, 2, &text[character_offset]);
	else
		if (inputbox->in_password_mode())
			font->draw(border_size, 2, std::string(strlen(text+character_offset), '*'));
		else
			font->draw(border_size, 2, &text[character_offset]);

	// Show blinking cursor
	if(inputbox->has_focus() && inputbox->is_enabled()) 
	{
		if (show_cursor)
		{
			int cursor_x = border_size - pixel_offset;

			if (inputbox->in_password_mode())
				cursor_x += inputbox->get_cursor_position() * font->get_width('*');
			else
				for(int i = 0; i < inputbox->get_cursor_position(); i++)
					cursor_x += font->get_width(text[i]);
			
			CL_Display::draw_line(cursor_x, border_size, cursor_x, border_size + font->get_height() - 1, CL_Color::black);
		}

		unsigned int cur_time = CL_System::get_time();
		if (cur_time >= cursor_blink_time)
		{
			cursor_blink_time = cur_time + 400;
			show_cursor = !show_cursor;
		}
	}
}

void CL_InputBox_Silver::on_activity()
{
	cursor_blink_time = CL_System::get_time() + 400;
	show_cursor = true;
}

void CL_InputBox_Silver::on_get_preferred_size(CL_Size &size)
{
	border_size = 3;
	
	// Override height for font-height
	CL_Rect position = inputbox->get_position();
	position.bottom = position.top + font->get_height() + border_size * 2;

	size.width = position.get_width();
	size.height = position.get_height();
}

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

/*
int CL_InputBox_Silver::get_mouse_position(int x, int y)
{
	int delta_x = x - border_size;
	unsigned int i;
	for (i = 0; i < inputbox->get_text().size(); i++)
	{
		char buf[2];
		buf[0] = inputbox->get_text()[i];
		buf[1] = 0;
		int w = font->get_width(buf);
		delta_x -= w;
		if (delta_x <= -w/2)
		{
			return i + character_offset;
		}
	}
	return i;
}
*/
