
/*
 * CINELERRA
 * Copyright (C) 1997-2011 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 "clip.h"
#include "edl.h"
#include "edlsession.h"
#include "language.h"
#include "meterpanel.h"
#include "mwindow.h"
#include "preferences.h"
#include "theme.h"
#include "vframe.h"



MeterPanel::MeterPanel(MWindow *mwindow, 
	BC_WindowBase *subwindow, 
	int x, 
	int y,
	int w,
	int h,
	int meter_count,
	int visible,
	int use_headroom,
	int use_titles)
{
	this->subwindow = subwindow;
	this->mwindow = mwindow;
	this->x = x;
	this->y = y;
	this->w = w;
	this->h = h;
	this->meter_count = meter_count;
	this->visible = visible;
	this->use_headroom = use_headroom;
	this->use_titles = use_titles;
}


MeterPanel::~MeterPanel()
{
	meters.remove_all_objects();
	meter_titles.remove_all_objects();
}

void MeterPanel::create_objects()
{
	set_meters(meter_count, visible);
}

int MeterPanel::set_meters(int meter_count, int visible)
{
	if(meter_count != meters.total || visible != this->visible)
	{
// Delete old meters
		meters.remove_all_objects();
		meter_titles.remove_all_objects();
		meter_peaks.remove_all();

		this->meter_count = meter_count;
		this->visible = visible;
//		if(!visible) this->meter_count = 0;

		if(meter_count)
		{
			int x1 = this->x;
			int y1 = this->y;
			int h1 = get_meter_h();
			int border = mwindow->theme->widget_border;
			for(int i = 0; i < meter_count; i++)
			{
//printf("MeterPanel::set_meters %d %d %d %d\n", __LINE__, i, x1, get_meter_w(i));
				y1 = this->y;
				
				if(use_titles)
				{
					BC_Title *new_title;
					subwindow->add_subwindow(new_title = new BC_Title(
						get_title_x(i, "0"), 
						y1,
						"0",
						SMALLFONT));
					y1 += new_title->get_h() + border;
					meter_titles.append(new_title);
				}

				MeterMeter *new_meter;
				subwindow->add_subwindow(new_meter = new MeterMeter(mwindow,
					this,
					x1, 
					y1, 
					this->w > 0 ? get_meter_w(i) : -1,
					h1, 
					(i == 0)));
				meters.append(new_meter);
        		x1 += get_meter_w(i) + border;
				
				meter_peaks.append(0);
			}
		}
	}

	return 0;
}

void MeterPanel::reposition_window(int x, int y, int w, int h)
{
	this->x = x;
	this->y = y;
	this->w = w;
	this->h = h;

//printf("MeterPanel::reposition_window 0 %d\n", meter_count);

	int border = mwindow->theme->widget_border;
	int x1 = x;
	for(int i = 0; i < meter_count; i++)
	{
		if(use_titles)
		{
			meter_titles.get(i)->reposition_window(
				get_title_x(i, meter_titles.get(i)->get_text()),
				meter_titles.get(i)->get_y());
		}
//printf("MeterPanel::reposition_window %d %d %d %d\n", __LINE__, i, x1, get_meter_w(i));
		meters.get(i)->reposition_window(x1, 
			meters.get(i)->get_y(),
			get_meter_w(i), 
			get_meter_h());
		x1 += get_meter_w(i) + border;
	}
}

int MeterPanel::change_status_event()
{
//printf("MeterPanel::change_status_event\n");
	return 1;
}

int MeterPanel::get_reset_x()
{
	return x + 
		get_meters_width(mwindow->theme, meter_count, visible) - 
		mwindow->theme->over_button[0]->get_w();
}

int MeterPanel::get_reset_y()
{
	return y + h - mwindow->theme->over_button[0]->get_h();
}

int MeterPanel::get_title_x(int number, const char *text)
{
	int border = mwindow->theme->widget_border;
	int x1 = x;

	for(int i = 0; i < meter_count; i++)
	{
		if(i == number)
		{
			int text_w = subwindow->get_text_width(SMALLFONT, text);
			int title_x = x1;
			int meter_w = (i == 0) ? 
				get_meter_w(i) - BC_Meter::get_title_w() : 
				get_meter_w(i);
			title_x += (i == 0) ? BC_Meter::get_title_w() : 0;
			title_x += meter_w / 2 - 
				text_w / 2;
			title_x = MAX(title_x, x1);
			if(i == 0) title_x = MAX(title_x, x1 + BC_Meter::get_title_w());
			return title_x;
		}
		
		
		x1 += get_meter_w(i) + border;
	}
}

int MeterPanel::get_meters_width(Theme *theme, int meter_count, int visible)
{
//printf("MeterPanel::get_meters_width %d %d\n", BC_Meter::get_title_w(), BC_Meter::get_meter_w());
	return visible ? 
		(BC_Meter::get_title_w() + 
			theme->widget_border + 
			BC_Meter::get_meter_w() * meter_count +
			theme->widget_border * (meter_count - 1)) : 
		0;
}


int MeterPanel::get_meter_w(int number)
{
	int border = mwindow->theme->widget_border;
	if(w > 0)
	{
		int meter_w = (w - BC_Meter::get_title_w() - 
				(meter_count - 1) * border) / 
			meter_count;
		if(number == 0)
		{
			return BC_Meter::get_title_w() + meter_w;
		}
		else
		{
			return meter_w;
		}
	}
	else
	{
		return (number == 0) ? 
			BC_Meter::get_title_w() + BC_Meter::get_meter_w() : 
			BC_Meter::get_meter_w();
	}
}

int MeterPanel::get_meter_h()
{
	int border = mwindow->theme->widget_border;
	if(use_titles)
	{
		return h - border - subwindow->get_text_height(SMALLFONT);
	}
	else
	{
		return h;
	}
}

void MeterPanel::update(double *levels)
{
	if(subwindow->get_hidden()) return;


	for(int i = 0; 
		i < meter_count; 
		i++)
	{
		meters.values[i]->update(levels[i], levels[i] > 1.0);

		if(use_titles &&
			levels[i] > meter_peaks.get(i))
		{
			update_peak(i, levels[i]);
		}
	}
}

void MeterPanel::update_peak(int number, float value)
{
	if(use_titles && number < meter_count)
	{
		meter_peaks.set(number, value);
		
		float db_value = DB::todb(value);
		char string[BCTEXTLEN] = { 0 };
		if(db_value <= mwindow->edl->session->min_meter_db)
		{
			sprintf(string, "oo");
		}
		else
		if(db_value > 0)
		{
			sprintf(string, "+%.1f", 
				db_value);
		}
		else
		{
			sprintf(string, "%.1f", 
				db_value);
		}

		meter_titles.get(number)->update(string);
		meter_titles.get(number)->reposition_window(get_title_x(number, string), 
			meter_titles.get(number)->get_y());
	}
}

void MeterPanel::stop_meters()
{
	for(int i = 0; 
		i < meter_count; 
		i++)
	{
		meters.values[i]->reset();
// Reset peak without drawing
		meter_peaks.set(i, 0);
	}
}


void MeterPanel::reset_meters()
{
	for(int i = 0; i < meters.size(); i++)
		meters.values[i]->reset_over();

	for(int i = 0; i < meter_titles.size(); i++)
	{
		update_peak(i, 0);
	}
}


void MeterPanel::change_format(int mode, int min, int max)
{
	for(int i = 0; i < meters.total; i++)
	{
		if(use_headroom)
			meters.values[i]->change_format(mode, min, 0);
		else
			meters.values[i]->change_format(mode, min, max);
	}
}









MeterReset::MeterReset(MWindow *mwindow, MeterPanel *panel, int x, int y)
 : BC_Button(x, y, mwindow->theme->over_button)
{
	this->mwindow = mwindow;
	this->panel = panel;
}

MeterReset::~MeterReset()
{
}
	
int MeterReset::handle_event()
{
	for(int i = 0; i < panel->meters.total; i++)
		panel->meters.values[i]->reset_over();
	return 1;
}





MeterMeter::MeterMeter(MWindow *mwindow, 
	MeterPanel *panel, 
	int x, 
	int y, 
	int w,
	int h, 
	int titles)
 : BC_Meter(x,
 	y,
	METER_VERT,
	h,
	mwindow->edl->session->min_meter_db, 
	panel->use_headroom ? 0 : mwindow->edl->session->max_meter_db, 
	mwindow->edl->session->meter_format,
	titles,
	w)
{
	this->mwindow = mwindow;
	this->panel = panel;
	set_delays(TRACKING_RATE * 10,
		TRACKING_RATE);
}

MeterMeter::~MeterMeter()
{
}


int MeterMeter::button_press_event()
{
	if(is_event_win() && BC_WindowBase::cursor_inside())
	{
		panel->reset_meters();
		mwindow->reset_meters();
		return 1;
	}

	return 0;
}





MeterShow::MeterShow(MWindow *mwindow, MeterPanel *panel, int x, int y)
 : BC_Toggle(x, 
 		y, 
		mwindow->theme->get_image_set("meters"), 
		panel->visible)
{
	this->mwindow = mwindow;
	this->panel = panel;
	set_tooltip(_("Show meters"));
}


MeterShow::~MeterShow()
{
}


int MeterShow::handle_event()
{
//printf("MeterShow::MeterShow 1 %d\n",panel->visible );
	panel->visible = get_value();
	panel->change_status_event();
	return 1;
}
