/**************************************************************

cmpack_curve_plot.h (C-Munipack project)
Widget which can draw a curve (derived from GtkWidget)
Copyright (C) 2011 David Motl, dmotl@volny.cz

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.

$Id: cmpack_curve_plot.h,v 1.2 2015/08/29 09:18:01 dmotl Exp $

**************************************************************/

#ifndef CMPACK_CURVE_PLOT_H
#define CMPACK_CURVE_PLOT_H

#include <gtk/gtk.h>

#include "cmpack_graph_data.h"

G_BEGIN_DECLS

#define CMPACK_TYPE_CURVE_PLOT            (cmpack_curve_plot_get_type ())
#define CMPACK_CURVE_PLOT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CMPACK_TYPE_CURVE_PLOT, CmpackCurvePlot))
#define CMPACK_CURVE_PLOT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CMPACK_TYPE_CURVE_PLOT, CmpackCurvePlotClass))
#define CMPACK_IS_CURVE_PLOT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CMPACK_TYPE_CURVE_PLOT))
#define CMPACK_IS_CURVE_PLOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CMPACK_TYPE_CURVE_PLOT))
#define CMPACK_CURVE_PLOT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CMPACK_TYPE_CURVE_PLOT, CmpackCurvePlotClass))

typedef struct _CmpackCurvePlot				CmpackCurvePlot;
typedef struct _CmpackCurvePlotClass		CmpackCurvePlotClass;
typedef struct _CmpackPlotXAxis				CmpackPlotXAxis;
typedef struct _CmpackPlotYAxis				CmpackPlotYAxis;
typedef struct _CmpackCurvePlotItem			CmpackCurvePlotItem;

typedef void (*CmpackCurvePlotForeachFunc)(CmpackCurvePlot *icon_view, gint row, gpointer data); 

/* Curve plot style */
typedef enum {
	PLOT_POINTS,
	PLOT_LINES,
	PLOT_LINES_POINTS,
	PLOT_STEPS,
	PLOT_HISTOGRAM
} CmpackPlotStyle;

/* Scale format */
typedef enum {
	PLOT_FIXED,			// Decimal numbers
	PLOT_INT,			// Integer numbers
	PLOT_EXP,			// Exponential numbers
	PLOT_TIME			// Date and time
} CmpackPlotFormat;

/* Mouse control mode */
typedef enum {
	PLOT_MOUSE_NONE,
	PLOT_MOUSE_ZOOM,
	PLOT_MOUSE_SELECT,
	PLOT_MOUSE_SHIFT
} CmpackPlotMouseMode;

/* X axis parameters */
struct _CmpackPlotXAxis
{
	gchar		*Name;				// Displayed name
	gdouble		ChannelWidth;		// Displayed channel width
	gdouble		ZeroOffset;			// Displayed value for first channel
	gdouble		ProjWidth;			// Scroll area width in projection units
	gdouble		ProjEps;			// Minimum viewfield in projection units
	gboolean	ShowLabels;			// Show labels
	gboolean	ShowGrid;			// Show grid lines
	gboolean	LabelsOpposite;		// Labels are on the top side
	CmpackPlotFormat Format;		// Format of labels
	gint		MinPrec;			// Minimum number of decimal places
	gint		MaxPrec;			// Maximum number of decimal places
	gdouble		ZoomPos;			// Actual zoom position
	gdouble		ZoomMax;			// Zoom position limits
	gdouble		PxlSize;			// Size of device unit in projection units
	gdouble		ProjPos;			// Center of viewfield in projection units
	gdouble		Center;				// Center of viewfield in device units
};

/* Y axis parameters */
struct _CmpackPlotYAxis
{
	gchar		*Name;				// Displayed name
	gboolean	Log;				// Log mapping
	gboolean	Reverse;			// Reverse mapping
	gdouble		Min, Max;			// Limits in physical units
	gdouble		ProjMin, ProjMax;	// Limits in projection units
	gdouble		ProjEps;			// Minimum viewfield in projection units
	gboolean	ShowLabels;			// Show labels
	gboolean	ShowGrid;			// Show grid lines
	gboolean	LabelsOpposite;		// Labels are on the top/right side
	CmpackPlotFormat Format;		// Format of labels
	gint		MinPrec;			// Minimum number of decimal places
	gint		MaxPrec;			// Maximum number of decimal places
	gdouble		ZoomPos;			// Actual zoom position
	gdouble		ZoomMax;			// Zoom position limits
	gdouble		PxlSize;			// Size of device unit in projection units
	gdouble		ProjPos;			// Center of viewfield in projection units
	gdouble		Center;				// Center of viewfield in device units
};

/* Graph view */
struct _CmpackCurvePlot
{
	GtkWidget parent;

	/* Private data */
	gint width, height;
	GtkSelectionMode selection_mode;
	CmpackActivationMode activation_mode;
	gboolean mouse_ctrl;
	gint select_first, select_last;
	gint selected_before_rubberbanding[2];
	CmpackPlotStyle style;
	gboolean dirty;
	GdkPixmap *offscreen_pixmap;

	CmpackGraphData *model;

	CmpackCurvePlotItem *items;
	gint item_count, item_capacity;
	gint last_single_clicked; 

	GtkAdjustment *hadjustment;
	GtkAdjustment *vadjustment;

	CmpackPlotMouseMode mouse_mode;
	gint mouse_x1, mouse_y1;
	gint mouse_x2, mouse_y2;
	gdouble mouse_posx, mouse_posy;
	gint last_mouse_x, last_mouse_y;

	gdouble		zoom_base;			
	CmpackPlotXAxis x;
	CmpackPlotYAxis y;				

	GdkRectangle canvas_rc;
	GdkRectangle graph_rc;
	GdkRectangle xscale_rc;
	GdkRectangle xname_rc;
	GdkRectangle yscale_rc;
	GdkRectangle yname_rc;

	GdkColor	*int_colors;
};

/* Graph view class */
struct _CmpackCurvePlotClass
{
  GtkWidgetClass parent_class;

  /* Signals */
  void (*set_scroll_adjustments)(CmpackCurvePlot *curve_plot, 
	  GtkAdjustment *hadjustment, GtkAdjustment *vadjustment);
  void (*item_activated)(CmpackCurvePlot *curve_plot, gint row);
  void (*selection_changed)(CmpackCurvePlot *curve_plot);
  void (*mouse_moved)(CmpackCurvePlot *curve_plot);
  void (*mouse_left)(CmpackCurvePlot *chart_view);
};

GType cmpack_curve_plot_get_type(void) G_GNUC_CONST;

/* -------------------------   PUBLIC FUNCTIONS   --------------------------------- */

/* Create a new graph view (makes a new data model) 
 * Returns floating reference to the graph view
 */
GtkWidget *cmpack_curve_plot_new(void);

/* Create a new graph view and link it to given data model
 * params:
 *	graph_data				- [in] data model
 * Returns floating reference to the graph view
 */
GtkWidget *cmpack_curve_plot_new_with_model(CmpackGraphData *graph_data);

/* Change the data model which the view is connected to
 * params:
 *	curve_plot				- [in] graph view
 *	graph_data				- [in] new data model
 */
void cmpack_curve_plot_set_model(CmpackCurvePlot *curve_plot, 
	CmpackGraphData *graph_data);

/* Get the data model with the view is connected to
 * params:
 *	curve_plot				- [in] graph view
 * Returns borrowed reference to the current data model
 */
CmpackGraphData* cmpack_curve_plot_get_model(CmpackCurvePlot *curve_plot);

/* Change the style of the plot
 * params:
 *	curve_plot				- [in] graph view
 *	style					- [in] new style
 */
void cmpack_curve_plot_set_style(CmpackCurvePlot *curve_plot, CmpackPlotStyle style);

/* Set data channel and for independent axis
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] which axis shall be modified
 *	log_scale				- [in] logarithm scale
 *	reverse					- [in] reverse scale
 *	min, max				- [in] physical limits of the scroll area
 *	eps						- [in] minimum resolution in projection units (zoom limit)
 *	format					- [in] format of displayed numbers
 *	minprec					- [in] minimum number of decimal places
 *	maxprec					- [in] maximum number of decimal places
 *	name 					- [in] displayed name
 */
void cmpack_curve_plot_set_x_axis(CmpackCurvePlot *curve_plot, gdouble channel_width,
	gdouble zero_offset, gdouble eps, CmpackPlotFormat format, 
	gint minprec, gint maxprec, const gchar *caption);

/* Set data channel and for specified axis
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] which axis shall be modified
 *	log_scale				- [in] logarithm scale
 *	reverse					- [in] reverse scale
 *	min, max				- [in] physical limits of the scroll area
 *	eps						- [in] minimum resolution in projection units (zoom limit)
 *	format					- [in] format of displayed numbers
 *	minprec					- [in] minimum number of decimal places
 *	maxprec					- [in] maximum number of decimal places
 *	name 					- [in] displayed name
 */
void cmpack_curve_plot_set_y_axis(CmpackCurvePlot *curve_plot, gboolean log_scale, 
	gboolean reverse, gdouble min, gdouble max, gdouble eps, CmpackPlotFormat format, 
	gint minprec, gint maxprec, const gchar *caption);

/* Set scale visibility and position for specified axis
 * params:
 *	curve_plot				- [in] graph view
 *	x_axis					- [in] show horizontal scale
 *	y_axis					- [in] show vertical scale
 */
void cmpack_curve_plot_set_scales(CmpackCurvePlot *curve_plot, 
	gboolean x_axis, gboolean y_axis);

/* Set grid visibility for specified axis
 * params:
 *	curve_plot				- [in] graph view
 *	x_axis					- [in] show x-axis grid
 *	y_axis					- [in] show y-axis grid
 */
void cmpack_curve_plot_set_grid(CmpackCurvePlot *curve_plot, 
	gboolean x_axis, gboolean y_axis);

/* Change zoom
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] which axis shall be modified
 *	zoom					- [in] new zoom coefficient
 */
void cmpack_curve_plot_set_zoom(CmpackCurvePlot *curve_plot, 
	CmpackGraphAxis axis, gdouble zoom);

/* Get current zoom
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] axis in question
 * Returns current zoom coefficient
 */
gdouble cmpack_curve_plot_get_zoom(CmpackCurvePlot *curve_plot, 
	CmpackGraphAxis axis);

/* Change zoom to given size
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] which axis shall be modified
 *	viewfield				- [in] new viewfield in projection units
 */
void cmpack_curve_plot_set_viewfield(CmpackCurvePlot *curve_plot, 
	CmpackGraphAxis axis, gdouble viewfield);

/* Get current width of viewfield
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] axis in question
 * Returns current width of viewfield in projection units
 */
gdouble cmpack_curve_plot_get_viewfield(CmpackCurvePlot *curve_plot, 
	CmpackGraphAxis axis);

/* Move graph
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] which axis shall be modified
 *	position				- [in] new position of the center of the viewfield
 */
void cmpack_curve_plot_set_center(CmpackCurvePlot *curve_plot, 
	CmpackGraphAxis axis, gdouble center);

/* Get position
 * params:
 *	curve_plot				- [in] graph view
 *	axis					- [in] axis in question
 * Returns current position of the center of the viewfield in physical units
 */
gdouble cmpack_curve_plot_get_center(CmpackCurvePlot *curve_plot, 
	CmpackGraphAxis axis);

/* Auto zoom the view to available data
 * params:
 *	curve_plot				- [in] graph view
 *	x						- [in] apply to x axis
 *	y						- [in] apply to y axis
 */
void cmpack_curve_plot_auto_zoom(CmpackCurvePlot *curve_plot, 
	gboolean x, gboolean y);

/* Enable/disable changing of zoom by mouse wheel or area selection 
 * params:
 *	curve_plot				- [in] graph view
 *	enable					- [in] TRUE=enable, FALSE=disable
 */
void cmpack_curve_plot_set_mouse_control(CmpackCurvePlot *curve_plot, gboolean enable);

/* Set zoom to show the whole projection area
 * params:
 *	curve_plot				- [in] graph view
 *	x						- [in] apply to x axis
 *	y						- [in] apply to y axis
 */
void cmpack_curve_plot_reset_zoom(CmpackCurvePlot *curve_plot, 
	gboolean x, gboolean y);

/* Set selection mode
 * params:
 *	curve_plot				- [in] graph view
 *	mode					- [in] new selection mode
*/
void cmpack_curve_plot_set_selection_mode(CmpackCurvePlot*curve_plot, 
	GtkSelectionMode mode);

/* Get current selection mode
 * params:
 *	curve_plot				- [in] graph view
 * Returns one of GTK_SELECTION_xxx constants
*/
GtkSelectionMode cmpack_curve_plot_get_selection_mode(CmpackCurvePlot *curve_plot);

/* Set activation mode. Items can be activated by single or double click. The default
 * is double-click activation.
 * params:
 *	curve_plot				- [in] graph view
 *	mode					- [in] activation mode, one of CmpackActivationXXX constants
 */
void cmpack_curve_plot_set_activation_mode(CmpackCurvePlot *curve_plot, CmpackActivationMode mode);

/* Get current activation mode.
 * params:
 *	curve_plot				- [in] graph view
 * Returns one of CmpackActivationXXX constants
 */
CmpackActivationMode cmpack_curve_plot_get_activation_mode(CmpackCurvePlot *curve_plot);

/* Get number of selected items
 * params:
 *	curve_plot				- [in] graph view
 * Returns number of selected rows
*/
gint cmpack_curve_plot_get_selected_count(CmpackCurvePlot *curve_plot);

/* Get list of selected rows
 * params:
 *	curve_plot				- [in] graph view
 * Returns index of item or negative value if no item is selected
*/
gboolean cmpack_curve_plot_get_selected_range(CmpackCurvePlot *curve_plot,
	gint *first, gint *last);

/* Get index of selected item (meaningful in single selection mode)
 * params:
 *	curve_plot				- [in] graph view
 * Returns index of item or negative value if no item is selected
*/
gint cmpack_curve_plot_get_selected(CmpackCurvePlot *curve_plot);

/* Emits the signal that an item was activated.
 * params:
 *	curve_plot				- [in] graph view
 *	row						- [in] row index
*/
void cmpack_curve_plot_item_activate(CmpackCurvePlot *curve_plot, gint row);

/* Call user function for each selected item
 * params:
 *	curve_plot				- [in] graph view
 *	func					- [in] function to be called
 *	data					- [in] data passed to the function
*/
void cmpack_curve_plot_selected_foreach(CmpackCurvePlot *curve_plot,
	CmpackCurvePlotForeachFunc func, gpointer data);

/* Select an item / add item to selection
 * params:
 *	curve_plot				- [in] graph view
 *	row						- [in] row index
*/
void cmpack_curve_plot_select(CmpackCurvePlot *curve_plot, gint row);

/* Unselect an item / remove item from selection
 * params:
 *	curve_plot				- [in] graph view
 *	row						- [in] row index
*/
void cmpack_curve_plot_select_range(CmpackCurvePlot *curve_plot, 
	gint first, gint last);

/* Returns nonzero if the item is selected
 * params:
 *	curve_plot				- [in] graph view
 *	row						- [in] row index
*/
gboolean cmpack_curve_plot_is_selected(CmpackCurvePlot *curve_plot, gint row);

/* Select all items
 * params:
 *	curve_plot				- [in] graph view
*/
void cmpack_curve_plot_select_all(CmpackCurvePlot *curve_plot);

/* Unselect all items
 * params:
 *	curve_plot				- [in] graph view
*/
void cmpack_curve_plot_unselect_all(CmpackCurvePlot *curve_plot);

/* Get coordinates of mouse position
 * params:
 *	graph_xy				- [in] graph view
 *  x, y					- [out] physical coordinates
*/
gint cmpack_curve_plot_mouse_pos(CmpackCurvePlot *graph_xy);

G_END_DECLS

#endif
