
/*
 * 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 "bctextbox.h"
#include "bctumble.h"
#include "math.h"
#include "vframe.h"


#define TUMBLE_UP 0
#define TUMBLE_UPHI 1
#define TUMBLEBOTTOM_DN 2
#define TUMBLETOP_DN 3
#define TOTAL_STATES 4

BC_Tumbler::BC_Tumbler(int x, int y, VFrame **data, int orient)
 : BC_SubWindow(x, y, 0, 0, -1)
{
	for(int i = 0; i < TOTAL_STATES; i++)
		images[i] = 0;
	status = TUMBLE_UP;
	repeat_count = 0;
	this->data = data;
	this->orient = orient;
}


BC_Tumbler::~BC_Tumbler()
{
	for(int i = 0; i < TOTAL_STATES; i ++)
		delete images[i];
}


int BC_Tumbler::calculate_w(VFrame **data)
{
	VFrame **vfrms = data ? data : BC_WindowBase::get_resources()->tumble_data;
	return vfrms[0]->get_w();
}

int BC_Tumbler::calculate_h(VFrame **data)
{
	VFrame **vfrms = data ? data : BC_WindowBase::get_resources()->tumble_data;
	return vfrms[0]->get_h();
}


int BC_Tumbler::initialize()
{
// Get the image
	set_images(data ? data : get_resources()->tumble_data);
	w = images[TUMBLE_UP]->get_w();
	h = images[TUMBLE_UP]->get_h();

// Create the subwindow
	BC_SubWindow::initialize();

// Display the bitmap
	draw_face(0);
	return 0;
}

int BC_Tumbler::reposition_window(int x, int y, int w, int h)
{
	BC_WindowBase::reposition_window(x, y);
	draw_face(0);
	return 0;
}


int BC_Tumbler::update_bitmaps(VFrame **data)
{
	set_images(data);
	draw_top_background(parent_window, 0, 0, w, h);
	draw_face(1);
	return 0;
}

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

int BC_Tumbler::draw_face(int flush)
{
	draw_top_background(parent_window, 0, 0, w, h);
	pixmap->draw_pixmap(images[status], 0, 0, w, h, 0, 0);
	flash(flush);
	return 0;
}

int BC_Tumbler::repeat_event(int64_t duration)
{
//printf("BC_Tumbler::repeat_event 1 %d\n", duration);
	if( duration == top_level->get_resources()->tooltip_delay ) {
		if( tooltip_text && tooltip_text[0] != 0 && status == TUMBLE_UPHI ) {
			show_tooltip();
			return 1;
		}
	}
	else if( duration == top_level->get_resources()->tumble_duration ) {
//printf("BC_Tumbler::repeat_event 2\n");
// delay the 1st repeat
		if( ++repeat_count > 1 && repeat_count < 5 ) return 0;
		if( status == TUMBLETOP_DN ) { handle_up_event(); return 1; }
		if( status == TUMBLEBOTTOM_DN) { handle_down_event(); return 1; }
	}
	return 0;
}

int BC_Tumbler::cursor_enter_event()
{
	if( top_level->event_win != win ) return 0;
	if( !top_level->button_down && status == TUMBLE_UP ) {
		status = TUMBLE_UPHI;
		draw_face(1);
	}
	return 0;
}

int BC_Tumbler::cursor_leave_event()
{
	hide_tooltip();
	if( status == TUMBLE_UPHI ) {
		status = TUMBLE_UP;
		draw_face(1);
	}
	return 0;
}

int BC_Tumbler::button_press_event()
{
	hide_tooltip();
	if( top_level->event_win != win ) return 0;
//printf("BC_Tumbler::button_press_event 1 %d\n", get_buttonpress());
	if( get_buttonpress() == WHEEL_UP ) {
		status = TUMBLETOP_DN;
		draw_face(1);
		handle_up_event();
	}
	else if( get_buttonpress() == WHEEL_DOWN ) {
			status = TUMBLEBOTTOM_DN;
			draw_face(1);
			handle_down_event();
		}
	else {
		status = orient == TUMBLER_HORZ ?
			top_level->cursor_x > get_w()/2 ? TUMBLETOP_DN : TUMBLEBOTTOM_DN :
			top_level->cursor_y < get_h()/2 ? TUMBLETOP_DN : TUMBLEBOTTOM_DN ;
		draw_face(1);

		top_level->set_repeat(top_level->get_resources()->tumble_duration);
		repeat_count = 0;
		repeat_event(top_level->get_resources()->tumble_duration);
//printf("BC_Tumbler::button_press_event 2 %d\n", get_buttonpress());
	}
	return 1;
}

int BC_Tumbler::button_release_event()
{
	hide_tooltip();
	if( top_level->event_win != win ) return 0;
	if( status == TUMBLEBOTTOM_DN || status == TUMBLETOP_DN ) {
		top_level->unset_repeat(top_level->get_resources()->tumble_duration);
		status = cursor_inside() ? TUMBLE_UPHI : TUMBLE_UP;
		draw_face(1);
	}
	return 0;
}

int BC_Tumbler::cursor_motion_event()
{
	if( top_level->event_win != win ) return 0;
	if( top_level->button_down && !cursor_inside() &&
	    !(status == TUMBLETOP_DN || status == TUMBLEBOTTOM_DN) ) {
		status = TUMBLE_UP;
		draw_face(1);
	}
	return 0;
}


BC_ITumbler::BC_ITumbler(BC_TextBox *textbox, int64_t min, int64_t max, int x, int y)
 : BC_Tumbler(x, y)
{
	this->textbox = textbox;
	this->min = min;
	this->max = max;
	this->increment = 1;
}

BC_ITumbler::~BC_ITumbler()
{
}

void BC_ITumbler::set_increment(float value)
{
	this->increment = (int64_t)value;
	if(increment < 1) increment = 1;
}

int BC_ITumbler::handle_up_event()
{
	int64_t value = atol(textbox->get_text());
	value += increment;
	if(value > max) value = max;
	textbox->update(value);
	textbox->handle_event();
	return 1;
}

int BC_ITumbler::handle_down_event()
{
	int64_t value = atol(textbox->get_text());
	value -= increment;
	if(value < min) value = min;
	textbox->update(value);
	textbox->handle_event();
	return 1;
}

void BC_ITumbler::set_boundaries(int64_t min, int64_t max)
{
	this->min = min;
	this->max = max;
}


BC_FTumbler::BC_FTumbler(BC_TextBox *textbox,
	float min,
	float max,
	int x,
	int y)
 : BC_Tumbler(x, y)
{
	this->textbox = textbox;
	this->min = min;
	this->max = max;
	this->increment = 1.0;
	this->log_floatincrement = 0;
}

BC_FTumbler::~BC_FTumbler()
{
}

int BC_FTumbler::handle_up_event()
{
	float value = atof(textbox->get_text());
	if (log_floatincrement) {
		// round off to to current precision (i.e. 250 -> 200)
		float cp = floor(log(value)/log(10) + 0.0001);
		value = floor((value/pow(10,cp))+ 0.0001)*pow(10,cp);
		value += pow(10,cp);
	}
	else
	value += increment;
	if(value > max) value = max;
	textbox->update(value);
	textbox->handle_event();
	return 1;
}

int BC_FTumbler::handle_down_event()
{
	float value = atof(textbox->get_text());
	if (log_floatincrement) {
		// round off to to current precision (i.e. 250 -> 200)
		float cp = floor(log(value)/log(10));
		value = floor(value/pow(10,cp))*pow(10,cp);
		// Need to make it so that: [.001 .01 .1 1 10 100] => [.0001 .001 .01 .1 1 10]
		cp = floor(log(value)/log(10)-.01);
		value -= pow(10,cp);
	}
	else
	value -= increment;
	if(value < min) value = min;
	textbox->update(value);
	textbox->handle_event();
	return 1;
}

void BC_FTumbler::set_boundaries(float min, float max)
{
	this->min = min;
	this->max = max;
}

void BC_FTumbler::set_increment(float value)
{
	this->increment = value;
}

void BC_FTumbler::set_log_floatincrement(int value)
{
	this->log_floatincrement = value;
}
