Blob Blame Raw
/* === S Y N F I G ========================================================= */
/*!	\file widgets/widget_timegraphbase.h
**	\brief Base class for widgets that are graph-like representations with time axis
**
**	$Id$
**
**	\legal
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**	......... ... 2019 Rodolfo Ribeiro Gomes
**
**	This package 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 package 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.
**	\endlegal
*/

#ifdef USING_PCH
#	include "pch.h"
#else
#ifdef HAVE_CONFIG_H
#	include <config.h>
#endif

#include "widget_timegraphbase.h"

#include <canvasview.h>
#include <gui/timeplotdata.h>

#include <Mlt.h>
#include <gui/selectdraghelper.h>

#include <cairomm/cairomm.h>
#include <gdkmm.h>
#include <cstring>
#endif

using namespace studio;

#define DEFAULT_ZOOM_CHANGING_FACTOR 1.25
#define DEFAULT_PAGE_SIZE 2.0

Widget_TimeGraphBase::Widget_TimeGraphBase()
	: Gtk::DrawingArea(),
	  range_adjustment(Gtk::Adjustment::create(-1.0, -1.0, 1.0, 0.1, 0.1, DEFAULT_PAGE_SIZE)),
	  zoom_changing_factor(DEFAULT_ZOOM_CHANGING_FACTOR),
	  default_page_size(DEFAULT_PAGE_SIZE)
{
	time_plot_data = new TimePlotData(*this, range_adjustment);
}

Widget_TimeGraphBase::~Widget_TimeGraphBase()
{
	if (time_model_changed_connection.connected())
		time_model_changed_connection.disconnect();

	delete time_plot_data;
}

const etl::handle<TimeModel>& Widget_TimeGraphBase::get_time_model() const
{
	return time_plot_data->time_model;
}

void Widget_TimeGraphBase::set_time_model(const etl::handle<TimeModel>& x)
{
	if (x == time_plot_data->time_model)
		return;

	if (time_model_changed_connection.connected())
		time_model_changed_connection.disconnect();

	time_plot_data->set_time_model(x);

	if (x)
		time_model_changed_connection = x->signal_changed().connect(sigc::mem_fun(*this, &Widget_TimeGraphBase::on_time_model_changed));
}

void Widget_TimeGraphBase::zoom_in()
{
	set_zoom(get_zoom() * zoom_changing_factor);
}

void Widget_TimeGraphBase::zoom_out()
{
	set_zoom(get_zoom() / zoom_changing_factor);
}

void Widget_TimeGraphBase::zoom_100()
{
	set_zoom(1.0);
}

void Widget_TimeGraphBase::set_zoom(double new_zoom_factor)
{
	int x, y;
	get_pointer(x, y);
	double perc_y = y/(get_height()+0.0);
	double y_value = perc_y * range_adjustment->get_page_size() + range_adjustment->get_value();
	double new_range_page_size = default_page_size / new_zoom_factor;
	double new_range_value = y_value - perc_y * new_range_page_size;
	ConfigureAdjustment(range_adjustment)
			.set_page_size(new_range_page_size)
			.set_value(new_range_value)
			.finish();
}

double Widget_TimeGraphBase::get_zoom() const {
	return default_page_size / range_adjustment->get_page_size();
}

void Widget_TimeGraphBase::scroll_up()
{
	ConfigureAdjustment(range_adjustment)
			.set_value(range_adjustment->get_value() - range_adjustment->get_step_increment())
			.finish();
}

void Widget_TimeGraphBase::scroll_down()
{
	ConfigureAdjustment(range_adjustment)
			.set_value(range_adjustment->get_value() + range_adjustment->get_step_increment())
			.finish();
}

void Widget_TimeGraphBase::pan(int dx, int dy, int /*total_dx*/, int /*total_dy*/)
{
	synfig::Time dt(-dx*time_plot_data->dt);
	time_plot_data->time_model->move_by(dt);

	double real_dy = (range_adjustment->get_page_size()*dy)/get_height();

	ConfigureAdjustment(range_adjustment)
			.set_value(range_adjustment->get_value() - real_dy)
			.finish();
}

void Widget_TimeGraphBase::set_default_page_size(double new_value)
{
	if (new_value < 0 || synfig::approximate_zero(new_value))
		return;
	default_page_size = new_value;
	set_zoom(get_zoom());
}

double Widget_TimeGraphBase::get_default_page_size() const
{
	return default_page_size;
}

bool Widget_TimeGraphBase::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
	int w = get_width();
	int h = get_height();
	if (w <= 0 || h <= 0)
		return true;

	get_style_context()->render_background(cr, 0, 0, w, h);

	if (!time_plot_data->time_model)
		return true;

	if (time_plot_data->is_invalid())
		return true;

	return false;
}

void Widget_TimeGraphBase::on_time_model_changed()
{

}

void Widget_TimeGraphBase::draw_current_time(const Cairo::RefPtr<Cairo::Context>& cr)
{
	cr->save();
	cr->set_line_width(1.0);
	cr->set_source_rgb(0, 0, 1);
	cr->rectangle(time_plot_data->get_pixel_t_coord(time_plot_data->time), 0, 0, get_height());
	cr->stroke();
	cr->restore();
}