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

cmpack_graph_view.h (C-Munipack project)
Widget which can draw a XY graph (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_graph_view.h,v 1.3 2016/05/29 11:20:05 dmotl Exp $

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

#ifndef CMPACK_GRAPH_VIEW_H
#define CMPACK_GRAPH_VIEW_H

#include <gtk/gtk.h>

#include "cmpack_graph_data.h"

G_BEGIN_DECLS

#define CMPACK_TYPE_GRAPH_VIEW            (cmpack_graph_view_get_type ())
#define CMPACK_GRAPH_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CMPACK_TYPE_GRAPH_VIEW, CmpackGraphView))
#define CMPACK_GRAPH_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CMPACK_TYPE_GRAPH_VIEW, CmpackGraphViewClass))
#define CMPACK_IS_GRAPH_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CMPACK_TYPE_GRAPH_VIEW))
#define CMPACK_IS_GRAPH_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CMPACK_TYPE_GRAPH_VIEW))
#define CMPACK_GRAPH_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CMPACK_TYPE_GRAPH_VIEW, CmpackGraphViewClass))

typedef struct _CmpackGraphView				CmpackGraphView;
typedef struct _CmpackGraphViewClass		CmpackGraphViewClass;
typedef struct _CmpackGraphViewAxis			CmpackGraphViewAxis;
typedef struct _CmpackGraphViewItem			CmpackGraphViewItem;

typedef void (*CmpackGraphViewForeachFunc)(CmpackGraphView *icon_view, gint col, gint row, gpointer data); 

/* Scale format */
typedef enum {
	GRAPH_FIXED,		// Decimal numbers
	GRAPH_INT,			// Integer numbers
	GRAPH_EXP,			// Exponential numbers
	GRAPH_TIME			// Time format
} CmpackGraphFormat;

/* Mouse control mode */
typedef enum {
	GRAPH_MOUSE_NONE,
	GRAPH_MOUSE_ZOOM,
	GRAPH_MOUSE_SELECT,
	GRAPH_MOUSE_SHIFT,
	GRAPH_MOUSE_MOVE_CX,
	GRAPH_MOUSE_MOVE_CY
} CmpackGraphMouseMode;

/* Cursor definition */
typedef struct _CmpackGraphCursor
{
	gchar		*caption;
	gint		width, height;
	gdouble		xproj;
} CmpackGraphCursor;

/* Graph axis parameters */
struct _CmpackGraphViewAxis
{
	gchar		*Name;				// Axis 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
	CmpackGraphFormat 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
	gint		CursorCount;		// Number of cursors 
	gint		CursorSpace;		// Number of allocated items 
	CmpackGraphCursor *Cursor;		// Cursors
};

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

	/* Private data */
	gint width, height;
	GtkSelectionMode selection_mode;
	CmpackActivationMode activation_mode;
	gboolean mouse_ctrl;

	guint timer_id;
	guint cursor_phase;

	gboolean dirty;
	GdkPixmap *offscreen_pixmap;

	CmpackGraphData *model;

	CmpackGraphViewItem *data;
	gint data_nrow, data_ncol;
	gint focused_item;
	gint last_single_clicked; 

	GtkAdjustment *hadjustment;
	GtkAdjustment *vadjustment;

	CmpackGraphMouseMode mouse_mode;
	gint mouse_param;				// Cursor index
	gint mouse_x1, mouse_y1;
	gint mouse_x2, mouse_y2;
	gdouble mouse_posx, mouse_posy;
	gint last_mouse_x, last_mouse_y;
	GdkCursorType mouse_cursor;

	gdouble		zoom_base;			// Zoom base
	CmpackGraphViewAxis x, y;		// Axis parameters
	gboolean	error_bars;

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

	GdkColor	*int_colors;
};

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

  /* Signals */
  void (*set_scroll_adjustments)(CmpackGraphView *graph_view, 
	  GtkAdjustment *hadjustment, GtkAdjustment *vadjustment);
  void (*item_activated)(CmpackGraphView *graph_view, gint row);
  void (*selection_changed)(CmpackGraphView *graph_view);
  void (*mouse_moved)(CmpackGraphView *graph_view);
  void (*mouse_left)(CmpackGraphView *chart_view);
  void (*cursor_moved)(CmpackGraphView *graph_view, CmpackGraphAxis axis, gint cursor);
};

GType cmpack_graph_view_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_graph_view_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_graph_view_new_with_model(CmpackGraphData *graph_data);

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

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

/* Set data channel and for independent axis
 * params:
 *	graph_view				- [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_graph_view_set_x_axis(CmpackGraphView *graph_view, gboolean log_scale, 
	gboolean reverse, gdouble min, gdouble max, gdouble eps, CmpackGraphFormat format, 
	gint minprec, gint maxprec, const gchar *caption);

/* Set data channel and for specified axis
 * params:
 *	graph_view				- [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_graph_view_set_y_axis(CmpackGraphView *graph_view, gboolean log_scale, 
	gboolean reverse, gdouble min, gdouble max, gdouble eps, CmpackGraphFormat format, 
	gint minprec, gint maxprec, const gchar *caption);

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

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

/* Set error bars visibility 
 * params:
 *	graph_view				- [in] graph view
 *	visible					- [in] show error bars
*/
void cmpack_graph_view_set_error_bars(CmpackGraphView *graph_view, 
	gboolean visible);

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

/* Get current zoom
 * params:
 *	graph_view				- [in] graph view
 *	axis					- [in] axis in question
 * Returns current zoom coefficient
 */
gdouble cmpack_graph_view_get_zoom(CmpackGraphView *graph_view, 
	CmpackGraphAxis axis);

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

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

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

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

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

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

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

/* Set selection mode
 * params:
 *	graph_view				- [in] graph view
 *	mode					- [in] new selection mode
*/
void cmpack_graph_view_set_selection_mode(CmpackGraphView*graph_view, 
	GtkSelectionMode mode);

/* Get current selection mode
 * params:
 *	graph_view				- [in] graph view
 * Returns one of GTK_SELECTION_xxx constants
*/
GtkSelectionMode cmpack_graph_view_get_selection_mode(CmpackGraphView *graph_view);

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

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

/* Get number of selected rows
 * params:
 *	graph_view				- [in] graph view
 * Returns number of selected rows
*/
gint cmpack_graph_view_get_selected_count(CmpackGraphView *graph_view);

/* Get list of selected rows
 * params:
 *	graph_view				- [in] graph view
 * Returns list of item indices
*/
GList *cmpack_graph_view_get_selected_rows(CmpackGraphView *graph_view);

/* Get index of selected item (meaningful in single selection mode)
 * params:
 *	graph_view				- [in] graph view
 * Returns index of item or negative value if no item is selected
*/
gboolean cmpack_graph_view_get_selected(CmpackGraphView *graph_view, gint *col, gint *row);

/* Get index of focused item
 * params:
 *	graph_view				- [in] graph view
 * Returns index of item or negative value if no item is focused
*/
gboolean cmpack_graph_view_get_focused(CmpackGraphView *graph_view, gint *col, gint *row);

/* Emits the signal that an item was activated.
 * params:
 *	graph_view				- [in] graph view
 *	col						- [in] column index
 *	row						- [in] row index
*/
void cmpack_graph_view_item_activate(CmpackGraphView *graph_view, gint col, gint row);

/* Call user function for each selected item
 * params:
 *	graph_view				- [in] graph view
 *	func					- [in] function to be called
 *	data					- [in] data passed to the function
*/
void cmpack_graph_view_selected_foreach(CmpackGraphView *graph_view,
	CmpackGraphViewForeachFunc func, gpointer data);

/* Select an item / add item to selection
 * params:
 *	graph_view				- [in] graph view
 *	row						- [in] row index
*/
void cmpack_graph_view_select(CmpackGraphView *graph_view, gint col, gint row);

/* Unselect an item / remove item from selection
 * params:
 *	graph_view				- [in] graph view
 *	row						- [in] row index
*/
void cmpack_graph_view_unselect(CmpackGraphView *graph_view, gint col, gint row);

/* Returns nonzero if the item is selected
 * params:
 *	graph_view				- [in] graph view
 *	col						- [in] column index
 *	row						- [in] row index
*/
gboolean cmpack_graph_view_is_selected(CmpackGraphView *graph_view, gint col, gint row);

/* Select all items
 * params:
 *	graph_view				- [in] graph view
*/
void cmpack_graph_view_select_all(CmpackGraphView *graph_view);

/* Unselect all items
 * params:
 *	graph_view				- [in] graph view
*/
void cmpack_graph_view_unselect_all(CmpackGraphView *graph_view);

/* Get coordinates of mouse position
 * params:
 * graph_view				- [in] graph view
 *  x, y					- [out] physical coordinates
*/
gboolean cmpack_graph_view_mouse_pos(CmpackGraphView *graph_view, gdouble *x, gdouble *y);

/* Export image into a file in PNG format
 * params:
 * graph_view				- [in] graph view
 * filepath					- [in] target file path
 * format					- [in] description of the file format
*/
gboolean cmpack_graph_view_write_to_file(CmpackGraphView *graph_view,
	const gchar *filepath, const gchar *format);

/* Define/remove cursors
 * params:
 * graph_view				- [in] graph view
 * axis						- [in] x / y cursors
 * count					- [in] number of cursors defined
*/
void cmpack_graph_view_set_cursors(CmpackGraphView *graph_view, 
	CmpackGraphAxis axis, gint count);

/* Set cursor position
 * params:
 * graph_view				- [in] graph view
 * axis						- [in] x / y cursors
 * cursor					- [in] cursor index (0 = first, ...)
 * pos						- [in] new position
*/
void cmpack_graph_view_set_cursor_pos(CmpackGraphView *graph_view, 
	CmpackGraphAxis axis, gint cursor, gdouble pos);

/* Get cursor position
 * params:
 * graph_view				- [in] graph view
 * axis						- [in] x / y cursors
 * cursor					- [in] cursor index (0 = first, ...)
*/
gdouble cmpack_graph_view_get_cursor_pos(CmpackGraphView *graph_view, 
	CmpackGraphAxis axis, gint cursor);

/* Set cursor caption
 * params:
 * graph_view				- [in] graph view
 * axis						- [in] x / y cursors
 * cursor					- [in] cursor index (0 = first, ...)
 * caption					- [in] new caption
*/
void cmpack_graph_view_set_cursor_caption(CmpackGraphView *graph_view, 
	CmpackGraphAxis axis, gint cursor, const gchar *caption);

G_END_DECLS

#endif
