
/*
 * CINELERRA
 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "bcpixmap.h"
#include "bcresources.h"
#include "bcslider.h"
#include "bccolors.h"
#include "fonts.h"
#include "keys.h"
#include "units.h"
#include "vframe.h"



#include <ctype.h>
#include <string.h>



BC_Slider::BC_Slider(int x, int y, int pixels, int pointer_motion_range, VFrame **images,
		int show_number, int vertical, int use_caption)
 : BC_SubWindow(x, y, 0, 0, -1)
{
	this->images = images;
	this->show_number = show_number;
	this->vertical = vertical;
	this->pointer_motion_range = pointer_motion_range;
	this->pixels = pixels;
	this->button_pixel = button_pixel;
	this->use_caption = use_caption;

	status = SLIDER_UP;
	pixmaps = new BC_Pixmap*[SLIDER_IMAGES];
	for(int i = 0; i < SLIDER_IMAGES; i++)
	{
		pixmaps[i] = 0;
	}
	button_down = 0;
	enabled = 1;
	active = 0;
}

BC_Slider::~BC_Slider()
{
	for(int i = 0; i < SLIDER_IMAGES; i++) {
		if(pixmaps[i]) delete pixmaps[i];
	}
	if(pixmaps) delete [] pixmaps;
}

int BC_Slider::initialize()
{
	if(!images) {
		this->images = vertical ?
			BC_WindowBase::get_resources()->vertical_slider_data :
			BC_WindowBase::get_resources()->horizontal_slider_data;
	}

	set_images(images);

	if(vertical) {
		w = images[SLIDER_BG_UP]->get_w();
		h = pixels;
	}
	else
	{
		w = pixels;
		h = images[SLIDER_BG_UP]->get_h();
	}

	text_height = get_text_height(SMALLFONT);
	button_pixel = value_to_pixel();

	BC_SubWindow::initialize();
	draw_face(0);
	show_window(0);
	return 0;
}

int BC_Slider::get_span(int vertical)
{
	if(vertical)
	{
		return BC_WindowBase::get_resources()->vertical_slider_data[0]->get_w();
	}
	else
	{
		return BC_WindowBase::get_resources()->horizontal_slider_data[0]->get_h();
	}
}

int BC_Slider::draw_face(int flush)
{
// Clear background
	draw_top_background(parent_window, 0, 0, get_w(), get_h());


	if(vertical)
	{
		draw_3segmentv(0,
			0,
			get_h(),
			pixmaps[SLIDER_IMAGES / 2 + status]);
		draw_pixmap(pixmaps[status], 0, button_pixel);
		if(use_caption)
		{
			set_color(RED);
			set_font(SMALLFONT);
			draw_text(0, h, get_caption());
		}
	}
	else
	{
		//int y = get_h() / 2 - pixmaps[SLIDER_IMAGES / 2 + status]->get_h() / 2;
		draw_3segmenth(0, 0, get_w(), pixmaps[SLIDER_IMAGES / 2 + status]);
		draw_pixmap(pixmaps[status], button_pixel, 0);
		if(use_caption)
		{
			set_color(RED);
			set_font(SMALLFONT);
			draw_text(0, h, get_caption());
		}
	}

	flash(flush);
	return 0;
}

int BC_Slider::set_images(VFrame **images)
{
	for(int i = 0; i < SLIDER_IMAGES; i++)
	{
		if(pixmaps[i]) delete pixmaps[i];
		pixmaps[i] = new BC_Pixmap(parent_window, images[i], PIXMAP_ALPHA);
	}
	return 0;
}

int BC_Slider::get_button_pixels()
{
	return vertical ? pixmaps[SLIDER_UP]->get_h() :
		pixmaps[SLIDER_UP]->get_w();
}

void BC_Slider::show_value_tooltip()
{
	if( !show_number ) return;
//printf("BC_Slider::show_value_tooltip %s\n", get_caption());
	set_tooltip(get_caption());
	keypress_tooltip_timer = 2000;
	show_tooltip(xS(50));
}


int BC_Slider::repeat_event(int64_t duration)
{
	if(duration == top_level->get_resources()->tooltip_delay)
	{
		if(tooltip_on)
		{
			if(keypress_tooltip_timer > 0)
			{
				keypress_tooltip_timer -= get_resources()->tooltip_delay;
			}
			else
			if(status != SLIDER_HI && status != SLIDER_DN)
			{
				hide_tooltip();
			}
		}
		else
		if(status == SLIDER_HI && tooltip_text && show_number)
		{
			if(!tooltip_text[0] || isdigit(tooltip_text[0]))
			{
				set_tooltip(get_caption());
				show_tooltip(50);
			}
			else
			{
//printf("BC_Slider::repeat_event 1 %s\n", tooltip_text);
				set_tooltip(get_caption());
				show_tooltip();
			}
			return 1;
		}
	}
	return 0;
}


int BC_Slider::keypress_event()
{
	int result = 0;
	if(!active || !enabled) return context_help_check_and_show();
	if(ctrl_down() || shift_down()) return context_help_check_and_show();

	switch(get_keypress())
	{
		case UP:
			increase_value_big();
			result = 1;
			break;
		case DOWN:
			decrease_value_big();
			result = 1;
			break;
		case LEFT:
			decrease_value();
			result = 1;
			break;
		case RIGHT:
			increase_value();
			result = 1;
			break;
	}

	if(result)
	{
		handle_event();
		show_value_tooltip();
		draw_face(1);
		return result;
	}

	return context_help_check_and_show();
}

int BC_Slider::cursor_enter_event()
{
//printf("BC_Slider::cursor_enter_event 1\n");
	if(top_level->event_win == win && status == SLIDER_UP)
	{
		status = SLIDER_HI;
		draw_face(1);
	}
//printf("BC_Slider::cursor_enter_event 2\n");
	return 0;
}

int BC_Slider::cursor_leave_event()
{
	if(status == SLIDER_HI)
	{
		status = SLIDER_UP;
		draw_face(1);
		hide_tooltip();
	}
	return 0;
}

int BC_Slider::deactivate()
{
	active = 0;
	return 0;
}

int BC_Slider::activate()
{
	top_level->active_subwindow = this;
	active = 1;
	return 0;
}

void BC_Slider::enable()
{
	enabled = 1;
	draw_face(1);
}

void BC_Slider::disable()
{
	enabled = 0;
	draw_face(1);
}

void BC_Slider::enable_show_value(int v)
{
	show_number = v;
}

int BC_Slider::button_press_event()
{
	int result = 0;
	if(is_event_win() && enabled)
	{
		if(!tooltip_on) top_level->hide_tooltip();
		if(status == SLIDER_HI)
		{
			if(get_buttonpress() == 4)
			{
				increase_value();
				handle_event();
				show_value_tooltip();
				draw_face(1);
			}
			else
			if(get_buttonpress() == 5)
			{
				decrease_value();
				handle_event();
				show_value_tooltip();
				draw_face(1);
			}
			else
			if(get_buttonpress() == 1)
			{
				button_down = 1;
				status = SLIDER_DN;
				draw_face(1);
				init_selection(top_level->cursor_x, top_level->cursor_y);
				top_level->deactivate();
				activate();
				show_value_tooltip();
			}
			result = 1;
		}
	}
	return result;
}

int BC_Slider::button_release_event()
{
	if(button_down)
	{
		button_down = 0;
		if(cursor_inside())
			status = SLIDER_HI;
		else
		{
			status = SLIDER_UP;
			top_level->hide_tooltip();
		}
		draw_face(1);
		return 1;
	}
	return 0;
}

int BC_Slider::cursor_motion_event()
{
	if(button_down)
	{
		int old_pixel = button_pixel;
		int result = update_selection(top_level->cursor_x, top_level->cursor_y);
		if(button_pixel != old_pixel) draw_face(1);
		if(result)
		{
			handle_event();
			set_tooltip(get_caption());
		}
		return 1;
	}
	return 0;
}

int BC_Slider::reposition_window(int x, int y, int w, int h)
{
	BC_SubWindow::reposition_window(x, y, w, h);
	button_pixel = value_to_pixel();
	draw_face(0);
	return 0;
}


int BC_Slider::get_pointer_motion_range()
{
	return pointer_motion_range;
}

void BC_Slider::set_pointer_motion_range(int value)
{
	pointer_motion_range = value;
}


BC_ISlider::BC_ISlider(int x, int y, int vertical, int pixels, int pointer_motion_range,
			int64_t minvalue, int64_t maxvalue, int64_t value, int use_caption,
			VFrame **data, int *output)
 : BC_Slider(x, y, pixels, pointer_motion_range, data, 1, vertical, use_caption)
{
	this->minvalue = minvalue;
	this->maxvalue = maxvalue;
	this->value = value;
	this->output = output;
}

int BC_ISlider::value_to_pixel()
{
	if(maxvalue == minvalue) return 0;
	else
	{
		if(vertical)
			return (int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) *
				(get_h() - get_button_pixels()));
		else
			return (int)((double)(value - minvalue) / (maxvalue - minvalue) *
				(get_w() - get_button_pixels()));
	}
}

int BC_ISlider::update(int64_t value)
{
	if(this->value != value)
	{
		this->value = value;
		int old_pixel = button_pixel;
		button_pixel = value_to_pixel();
		if(button_pixel != old_pixel) draw_face(1);
	}
	return 0;
}

int BC_ISlider::update(int pointer_motion_range,
	int64_t value,
	int64_t minvalue,
	int64_t maxvalue)
{
	this->minvalue = minvalue;
	this->maxvalue = maxvalue;
	this->value = value;
	this->pointer_motion_range = pointer_motion_range;

	int old_pixel = button_pixel;
	button_pixel = value_to_pixel();
	if(button_pixel != old_pixel) draw_face(1);
	return 0;
}


int64_t BC_ISlider::get_value()
{
	return value;
}

int64_t BC_ISlider::get_length()
{
	return maxvalue - minvalue;
}

char* BC_ISlider::get_caption()
{
	sprintf(caption, "%jd", value);
	return caption;
}

int BC_ISlider::increase_value()
{
	value++;
	if(value > maxvalue) value = maxvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_ISlider::decrease_value()
{
	value--;
	if(value < minvalue) value = minvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_ISlider::increase_value_big()
{
	value+=10;
	if(value > maxvalue) value = maxvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_ISlider::decrease_value_big()
{
	value-=10;
	if(value < minvalue) value = minvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_ISlider::init_selection(int cursor_x, int cursor_y)
{
	if(vertical)
	{
		min_pixel = -(int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) * pointer_motion_range);
		min_pixel += cursor_y;
	}
	else
	{
		min_pixel = -(int)((double)(value - minvalue) / (maxvalue - minvalue) * pointer_motion_range);
		min_pixel += cursor_x;
	}
	max_pixel = min_pixel + pointer_motion_range;
	return 0;
}

int BC_ISlider::update_selection(int cursor_x, int cursor_y)
{
	int64_t old_value = value;

	if(vertical)
	{
		value = (int64_t)((1.0 - (double)(cursor_y - min_pixel) /
			pointer_motion_range) *
			(maxvalue - minvalue) +
			minvalue);
	}
	else
	{
		value = (int64_t)((double)(cursor_x - min_pixel) /
			pointer_motion_range *
			(maxvalue - minvalue) +
			minvalue);
	}

	if(value > maxvalue) value = maxvalue;
	if(value < minvalue) value = minvalue;
	button_pixel = value_to_pixel();

	if(old_value != value)
	{
		return 1;
	}
	return 0;
}

int BC_ISlider::handle_event()
{
	if(output) *output = get_value();
	return 1;
}


BC_FSlider::BC_FSlider(int x, int y, int vertical, int pixels, int pointer_motion_range,
			float minvalue, float maxvalue, float value, int use_caption,
			VFrame **data)
 : BC_Slider(x, y, pixels, pointer_motion_range, data, 1, vertical, use_caption)
{
	this->minvalue = minvalue;
	this->maxvalue = maxvalue;
	this->value = value;
	this->precision = 0.1;
	this->small_change = 0.1;
	this->big_change = 1.0;
}

int BC_FSlider::value_to_pixel()
{
//printf("BC_FSlider::value_to_pixel %f %f\n", maxvalue, minvalue);
	if(maxvalue == minvalue) return 0;
	{
		if(vertical)
			return (int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) *
				(get_h() - get_button_pixels()));
		else
			return (int)((double)(value - minvalue) / (maxvalue - minvalue) *
				(get_w() - get_button_pixels()));
	}
}

int BC_FSlider::update(float value)
{
	if(this->value != value)
	{
		this->value = value;
		int old_pixel = button_pixel;
		button_pixel = value_to_pixel();
//printf("BC_FSlider::update 1 %f %d\n", value, button_pixel);
		if(button_pixel != old_pixel) draw_face(1);
	}
	return 0;
}

int BC_FSlider::update(int pointer_motion_range, float value, float minvalue, float maxvalue)
{
	this->minvalue = minvalue;
	this->maxvalue = maxvalue;
	this->value = value;
	this->pointer_motion_range = pointer_motion_range;
	int old_pixel = button_pixel;
	button_pixel = value_to_pixel();
	if(button_pixel != old_pixel) draw_face(1);
	return 0;
}


float BC_FSlider::get_value()
{
	return value;
}

float BC_FSlider::get_length()
{
	return maxvalue - minvalue;
}

char* BC_FSlider::get_caption()
{
	sprintf(caption, "%.02f", value);
	return caption;
}

int BC_FSlider::increase_value()
{
	value += small_change;
	if(value > maxvalue) value = maxvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_FSlider::decrease_value()
{
	value -= small_change;
	if(value < minvalue) value = minvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_FSlider::increase_value_big()
{
	value += big_change;
	if(value > maxvalue) value = maxvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_FSlider::decrease_value_big()
{
	value -= big_change;
	if(value < minvalue) value = minvalue;
	button_pixel = value_to_pixel();
	return 0;
}

int BC_FSlider::init_selection(int cursor_x, int cursor_y)
{
	if(vertical)
	{
		min_pixel = -(int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) * pointer_motion_range);
		min_pixel += cursor_y;
	}
	else
	{
		min_pixel = -(int)((double)(value - minvalue) / (maxvalue - minvalue) * pointer_motion_range);
		min_pixel += cursor_x;
	}
	max_pixel = min_pixel + pointer_motion_range;
	return 0;
}

int BC_FSlider::update_selection(int cursor_x, int cursor_y)
{
	float old_value = value;


	if(vertical)
	{
		value = ((1.0 - (double)(cursor_y - min_pixel) /
			pointer_motion_range) *
			(maxvalue - minvalue) +
			minvalue);
	}
	else
	{
		value = ((double)(cursor_x - min_pixel) /
			pointer_motion_range *
			(maxvalue - minvalue) +
			minvalue);
	}

	value = Units::quantize(value, precision);
	if(value > maxvalue) value = maxvalue;
	if(value < minvalue) value = minvalue;
	button_pixel = value_to_pixel();
// printf("BC_FSlider::update_selection 1 %d %d %d %d %f %f\n",
// pointer_motion_range, min_pixel, max_pixel, cursor_x, precision, value);

	if(old_value != value)
	{
		return 1;
	}
	return 0;
}

void BC_FSlider::set_precision(float value)
{
	this->precision = value;
}

void BC_FSlider::set_pagination(float small_change, float big_change)
{
	this->small_change = small_change;
	this->big_change = big_change;
}


BC_PercentageSlider::BC_PercentageSlider(int x, int y, int vertical, int pixels, int pointer_motion_range,
		float minvalue, float maxvalue, float value, int use_caption,
		VFrame **data)
 : BC_FSlider(x, y, vertical, pixels, pointer_motion_range, minvalue, maxvalue, value, use_caption, data)
{
}

char* BC_PercentageSlider::get_caption()
{
	sprintf(caption, "%.0f%%", floor((value - minvalue) / (maxvalue - minvalue) * 100));
	return caption;
}

