summaryrefslogtreecommitdiff
path: root/src/gplot
diff options
context:
space:
mode:
Diffstat (limited to 'src/gplot')
-rw-r--r--src/gplot/Makefile.am14
-rw-r--r--src/gplot/gplot.c839
-rw-r--r--src/gplot/gplot.h70
-rw-r--r--src/gplot/gplotfunction.c80
-rw-r--r--src/gplot/gplotfunction.h69
-rw-r--r--src/gplot/gplotlines.c294
-rw-r--r--src/gplot/gplotlines.h55
7 files changed, 1421 insertions, 0 deletions
diff --git a/src/gplot/Makefile.am b/src/gplot/Makefile.am
new file mode 100644
index 0000000..85665ee
--- /dev/null
+++ b/src/gplot/Makefile.am
@@ -0,0 +1,14 @@
+oreganodir = $(datadir)/oregano
+INCLUDES = \
+ $(OREGANO_CFLAGS)
+
+noinst_LIBRARIES = libgplot.a
+libgplot_a_SOURCES = \
+ gplot.c \
+ gplotfunction.c \
+ gplotfunction.h \
+ gplot.h \
+ gplotlines.c \
+ gplotlines.h
+
+libgplot_a_LIBADD = libgplot.a
diff --git a/src/gplot/gplot.c b/src/gplot/gplot.c
new file mode 100644
index 0000000..b41408d
--- /dev/null
+++ b/src/gplot/gplot.c
@@ -0,0 +1,839 @@
+/*
+ * gplot.c
+ *
+ * Authors:
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ *
+ * This library 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "gplot.h"
+
+#define BORDER_SIZE 50
+
+static void g_plot_class_init (GPlotClass* class);
+static void g_plot_init (GPlot* plot);
+static gint g_plot_expose (GtkWidget* widget, GdkEventExpose* event);
+static cairo_t* g_plot_create_cairo (GPlot *);
+static gboolean g_plot_motion_cb (GtkWidget *, GdkEventMotion *, GPlot *);
+static gboolean g_plot_button_press_cb (GtkWidget *, GdkEventButton *, GPlot *);
+static gboolean g_plot_button_release_cb (GtkWidget *, GdkEventButton *, GPlot *);
+static void g_plot_update_bbox (GPlot *);
+static void g_plot_finalize (GObject *object);
+static void g_plot_dispose (GObject *object);
+
+static void get_order_of_magnitude (gdouble val, gdouble *man, gdouble *pw);
+
+enum {
+ ACTION_NONE,
+ ACTION_STARTING_PAN,
+ ACTION_PAN,
+ ACTION_STARTING_REGION,
+ ACTION_REGION
+};
+
+static GtkLayoutClass* parent_class = NULL;
+
+struct _GPlotPriv {
+ GList *functions;
+
+ gchar *xlabel;
+ gchar *xlabel_unit;
+ gchar *ylabel;
+ gchar *ylabel_unit;
+
+ gdouble left_border;
+ gdouble right_border;
+ gdouble top_border;
+ gdouble bottom_border;
+
+ guint zoom_mode;
+ guint action;
+ gdouble zoom;
+ gdouble offset_x;
+ gdouble offset_y;
+ gdouble last_x;
+ gdouble last_y;
+
+ /* Window->Viewport * Transformation Matrix */
+ cairo_matrix_t matrix;
+
+ gboolean window_valid;
+ GPlotFunctionBBox window_bbox;
+ GPlotFunctionBBox viewport_bbox;
+
+ GPlotFunctionBBox rubberband;
+};
+
+GType
+g_plot_get_type ()
+{
+ static GType g_plot_type = 0;
+
+ if (!g_plot_type) {
+ static const GTypeInfo g_plot_info = {
+ sizeof (GPlotClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) g_plot_class_init,
+ NULL,
+ NULL,
+ sizeof (GPlot),
+ 0,
+ (GInstanceInitFunc) g_plot_init,
+ NULL
+ };
+ g_plot_type = g_type_register_static (GTK_TYPE_LAYOUT, "GPlot", &g_plot_info, 0);
+ }
+ return g_plot_type;
+}
+
+static void
+g_plot_class_init (GPlotClass* class)
+{
+ GObjectClass* object_class;
+ GtkWidgetClass* widget_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ widget_class = GTK_WIDGET_CLASS (class);
+ parent_class = g_type_class_peek_parent (class);
+
+ widget_class->expose_event = g_plot_expose;
+
+ object_class->dispose = g_plot_dispose;
+ object_class->finalize = g_plot_finalize;
+}
+
+static cairo_t*
+g_plot_create_cairo (GPlot *p)
+{
+ cairo_t *cr;
+
+ cr = gdk_cairo_create (GTK_LAYOUT (p)->bin_window);
+
+ return cr;
+}
+
+static void
+g_plot_finalize (GObject *object)
+{
+ GPlot *p = GPLOT (object);
+
+ if (p->priv->xlabel)
+ g_free (p->priv->xlabel);
+
+ if (p->priv->ylabel)
+ g_free (p->priv->ylabel);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+g_plot_dispose (GObject *object)
+{
+ GList *lst;
+ GPlot *plot;
+
+ plot = GPLOT (object);
+
+ lst = plot->priv->functions;
+ while (lst) {
+ GPlotFunction *f = (GPlotFunction *)lst->data;
+ g_object_unref (G_OBJECT (f));
+ lst = lst->next;
+ }
+ g_list_free (plot->priv->functions);
+ plot->priv->functions = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static int
+get_best_exponent (int div)
+{
+ /* http://en.wikipedia.org/wiki/Micro */
+ switch (div) {
+ case -24:
+ case -21:
+ case -18:
+ case -15:
+ case -12:
+ case -9:
+ case -6:
+ case -3:
+ case 0:
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ case 18:
+ case 21:
+ case 24:
+ return div;
+ }
+ if (div == -1) return -3;
+
+ if ((div - 1) % 3 == 0)
+ return div - 1;
+ return div + 1;
+}
+
+void
+draw_axis (cairo_t *cr, GPlotFunctionBBox *bbox, gdouble min, gdouble max, gboolean vertical, gint *div)
+{
+ gchar *label;
+ cairo_text_extents_t extents;
+ gdouble i, j;
+ gdouble x1, y1, x2, y2, x3, y3;
+ gdouble step = (max - min) / 10.0;
+ gdouble s;
+ gdouble divisor;
+ gdouble man1, pw1, man2, pw2;
+
+ get_order_of_magnitude (min, &man1, &pw1);
+ get_order_of_magnitude (max, &man2, &pw2);
+ (*div) = get_best_exponent ((pw2+pw1) / 2.0 + 0.5);
+ if ((*div) == 0)
+ divisor = 1;
+ else
+ divisor = pow (10, *div);
+
+ if (vertical)
+ s = (bbox->ymax - bbox->ymin) / 10.0;
+ else
+ s = (bbox->xmax - bbox->xmin) / 10.0;
+
+ for (i = (vertical?bbox->ymin:bbox->xmin), j = max; i <= (vertical?bbox->ymax:bbox->xmax) + 0.5; i += s, j -= step) {
+ label = g_strdup_printf ("%.2f", j / divisor);
+ cairo_text_extents (cr, label, &extents);
+
+ if (vertical) {
+ x1 = bbox->xmin - 4;
+ y1 = i;
+ x2 = bbox->xmin + 4;
+ y2 = i;
+ x3 = bbox->xmin - extents.width * 1.5;
+ y3 = i + extents.height / 2.0;
+ } else {
+ x1 = i;
+ y1 = bbox->ymax - 4;
+ x2 = i;
+ y2 = bbox->ymax + 4;
+ x3 = i;
+ y3 = bbox->ymax + extents.height * 1.5;
+ }
+
+ cairo_move_to (cr, x1, y1);
+ cairo_line_to (cr, x2, y2);
+ cairo_move_to (cr, x3, y3);
+ cairo_show_text (cr, label);
+ g_free (label);
+ }
+ cairo_stroke (cr);
+}
+
+static gchar*
+get_unit_text (int div)
+{
+ /* http://en.wikipedia.org/wiki/Micro */
+ switch (div) {
+ case -24: return g_strdup ("y");
+ case -21: return g_strdup ("z");
+ case -18: return g_strdup ("a");
+ case -15: return g_strdup ("f");
+ case -12: return g_strdup ("p");
+ case -9: return g_strdup ("n");
+ case -6: return g_strdup ("\302\265");
+ case -3: return g_strdup ("m");
+ case 0: return g_strdup ("");
+ case 3: return g_strdup ("k");
+ case 6: return g_strdup ("M");
+ case 9: return g_strdup ("G");
+ case 12: return g_strdup ("T");
+ case 15: return g_strdup ("P");
+ case 18: return g_strdup ("E");
+ case 21: return g_strdup ("Z");
+ case 24: return g_strdup ("Y");
+ }
+
+ return g_strdup_printf ("10e%02d", div);
+}
+
+static gint
+g_plot_expose (GtkWidget* widget, GdkEventExpose* event)
+{
+ static double dashes[] = {3, /* ink */
+ 3, /* skip */
+ 3, /* ink */
+ 3 /* skip*/ };
+ static int ndash = sizeof (dashes)/sizeof(dashes[0]);
+ static double offset = -0.2;
+
+ GPlot *plot;
+ GPlotPriv *priv;
+ cairo_t* cr;
+ guint width;
+ guint height;
+ guint graph_width;
+ guint graph_height;
+ GPlotFunction *f;
+ GList *lst;
+ GPlotFunctionBBox bbox;
+ gdouble aX, bX, aY, bY;
+ gint div;
+ int i = 0;
+ cairo_text_extents_t extents;
+
+ plot = GPLOT (widget);
+ priv = plot->priv;
+
+ if (!priv->window_valid) {
+ g_plot_update_bbox (plot);
+ }
+
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+
+ graph_width = width - priv->left_border - priv->right_border;
+ graph_height = height - priv->top_border - priv->bottom_border;
+
+ cr = g_plot_create_cairo (plot);
+
+ /* Set a clip region for the expose event */
+ /* TODO :This is useful if we use gtk_widget_queue_draw_area */
+ cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
+ cairo_clip (cr);
+
+ /* Paint background */
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ /* Plot Border */
+ cairo_save (cr);
+ cairo_set_line_width (cr, 0.5);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ /* TODO : Move this to SizeAllocation functions */
+ priv->viewport_bbox.xmax = widget->allocation.width - priv->right_border;
+ priv->viewport_bbox.xmin = priv->left_border;
+ priv->viewport_bbox.ymax = widget->allocation.height - priv->bottom_border;
+ priv->viewport_bbox.ymin = priv->top_border;
+
+ /* Save real bbox */
+ bbox = priv->window_bbox;
+
+ /* Calculating Window to Viewport matrix */
+ aX = (priv->viewport_bbox.xmax - priv->viewport_bbox.xmin)
+ / (priv->window_bbox.xmax - priv->window_bbox.xmin);
+ bX = -aX * priv->window_bbox.xmin + priv->viewport_bbox.xmin;
+ aY = (priv->viewport_bbox.ymax - priv->viewport_bbox.ymin)
+ / (priv->window_bbox.ymin - priv->window_bbox.ymax);
+ bY = -aY * priv->window_bbox.ymax + priv->viewport_bbox.ymin;
+
+ cairo_matrix_init (&priv->matrix, aX, 0, 0, aY, bX, bY);
+
+ cairo_save (cr);
+ cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
+ cairo_clip (cr);
+
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_matrix (cr, &priv->matrix);
+ lst = plot->priv->functions;
+ while (lst) {
+ f = (GPlotFunction *)lst->data;
+ g_plot_function_draw (f, cr, &priv->window_bbox);
+ lst = lst->next;
+ }
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ cairo_rectangle (cr, priv->left_border, priv->right_border, graph_width, graph_height);
+ cairo_clip (cr);
+ cairo_save (cr);
+ cairo_set_matrix (cr, &priv->matrix);
+ cairo_move_to (cr, priv->window_bbox.xmin, 0.0);
+ cairo_line_to (cr, priv->window_bbox.xmax, 0.0);
+ cairo_restore (cr);
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+ cairo_set_line_width (cr, 2);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ cairo_set_matrix (cr, &priv->matrix);
+ cairo_move_to (cr, 0.0, priv->window_bbox.ymin);
+ cairo_line_to (cr, 0.0, priv->window_bbox.ymax);
+ cairo_restore (cr);
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+ cairo_set_line_width (cr, 2);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ i = 0;
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_line_width (cr, 1);
+
+ draw_axis (cr, &priv->viewport_bbox, priv->window_bbox.ymin, priv->window_bbox.ymax, TRUE, &div);
+ if (priv->ylabel_unit) {
+ g_free (priv->ylabel_unit);
+ priv->ylabel_unit = NULL;
+ }
+ if (div != 1)
+ priv->ylabel_unit = get_unit_text (div);
+ draw_axis (cr, &priv->viewport_bbox, priv->window_bbox.xmax, priv->window_bbox.xmin, FALSE, &div);
+ if (priv->xlabel_unit) {
+ g_free (priv->xlabel_unit);
+ priv->xlabel_unit = NULL;
+ }
+ if (div != 1)
+ priv->xlabel_unit = get_unit_text (div);
+ cairo_restore (cr);
+
+ /* Axis Labels */
+ if (priv->xlabel) {
+ char *txt;
+ if (priv->xlabel_unit == NULL)
+ txt = g_strdup (priv->xlabel);
+ else
+ txt = g_strdup_printf ("%s %s", priv->xlabel_unit, priv->xlabel);
+
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_font_size (cr, 14);
+ cairo_text_extents (cr, txt, &extents);
+ cairo_move_to (cr, width/2.0 - extents.width/2.0, height-extents.height/2.0);
+ cairo_show_text (cr, txt);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ g_free (txt);
+ }
+
+ if (priv->ylabel) {
+ char *txt;
+ if (priv->ylabel_unit == NULL)
+ txt = g_strdup (priv->ylabel);
+ else
+ txt = g_strdup_printf ("%s %s", priv->ylabel_unit, priv->ylabel);
+
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_font_size (cr, 14);
+ cairo_text_extents (cr, txt, &extents);
+ cairo_move_to (cr, extents.height, height/2.0 + extents.width/2.0);
+ cairo_rotate (cr, 4.7124);
+ cairo_show_text (cr, txt);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ if (priv->action == ACTION_REGION) {
+ gdouble x, y, w, h;
+ x = priv->rubberband.xmin;
+ y = priv->rubberband.ymin;
+ w = priv->rubberband.xmax;
+ h = priv->rubberband.ymax;
+ cairo_save (cr);
+ cairo_identity_matrix (cr);
+ cairo_set_dash (cr, dashes, ndash, offset);
+
+ cairo_set_line_width (cr, 2);
+ cairo_set_source_rgb (cr, 0.0, 1.0, 0.0);
+ cairo_rectangle (cr, x, y, w-x, h-y);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+static void
+g_plot_init (GPlot* plot)
+{
+ plot->priv = g_new0 (GPlotPriv, 1);
+
+ plot->priv->zoom_mode = GPLOT_ZOOM_REGION;
+ plot->priv->functions = NULL;
+ plot->priv->action = ACTION_NONE;
+ plot->priv->zoom = 1.0;
+ plot->priv->offset_x = 0.0;
+ plot->priv->offset_y = 0.0;
+ plot->priv->left_border = BORDER_SIZE;
+ plot->priv->right_border = BORDER_SIZE;
+ plot->priv->top_border = BORDER_SIZE;
+ plot->priv->bottom_border = BORDER_SIZE;
+ plot->priv->xlabel = NULL;
+ plot->priv->xlabel_unit = NULL;
+ plot->priv->ylabel = NULL;
+ plot->priv->ylabel_unit = NULL;
+}
+
+GtkWidget*
+g_plot_new ()
+{
+ GPlot *plot;
+
+ plot = GPLOT (g_object_new (TYPE_GPLOT, NULL));
+
+ gtk_widget_add_events (GTK_WIDGET (plot),
+ GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|
+ GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_MOTION_MASK|
+ GDK_BUTTON1_MOTION_MASK|GDK_BUTTON2_MOTION_MASK|
+ GDK_BUTTON3_MOTION_MASK);
+
+ g_signal_connect (G_OBJECT (plot), "motion-notify-event", G_CALLBACK(g_plot_motion_cb), plot);
+ g_signal_connect (G_OBJECT (plot), "button-press-event", G_CALLBACK(g_plot_button_press_cb), plot);
+ g_signal_connect (G_OBJECT (plot), "button-release-event", G_CALLBACK(g_plot_button_release_cb), plot);
+
+ return GTK_WIDGET (plot);
+}
+
+int
+g_plot_add_function (GPlot *plot, GPlotFunction *func)
+{
+ g_return_val_if_fail (IS_GPLOT (plot), -1);
+
+ plot->priv->functions = g_list_append (plot->priv->functions, func);
+ plot->priv->window_valid = FALSE;
+ return 0;
+}
+
+static gboolean
+g_plot_motion_cb (GtkWidget *w, GdkEventMotion *e, GPlot *p)
+{
+ switch (p->priv->zoom_mode) {
+ case GPLOT_ZOOM_INOUT:
+ if ((p->priv->action == ACTION_STARTING_PAN) || (p->priv->action == ACTION_PAN)) {
+ gdouble dx, dy;
+ cairo_matrix_t t = p->priv->matrix;
+ GdkCursor *cursor = gdk_cursor_new (GDK_FLEUR);
+ gdk_window_set_cursor (w->window, cursor);
+ gdk_cursor_destroy (cursor);
+ gdk_flush ();
+
+ dx = p->priv->last_x - e->x;
+ dy = p->priv->last_y - e->y;
+
+ cairo_matrix_invert (&t);
+ cairo_matrix_transform_distance (&t, &dx, &dy);
+
+ p->priv->window_bbox.xmin -= dx;
+ p->priv->window_bbox.xmax -= dx;
+ p->priv->window_bbox.ymin -= dy;
+ p->priv->window_bbox.ymax -= dy;
+
+ p->priv->last_x = e->x;
+ p->priv->last_y = e->y;
+ p->priv->action = ACTION_PAN;
+ gtk_widget_queue_draw (w);
+ }
+ break;
+ case GPLOT_ZOOM_REGION:
+ if ((p->priv->action == ACTION_STARTING_REGION) || (p->priv->action == ACTION_REGION)) {
+ gdouble dx, dy;
+ GdkCursor *cursor = gdk_cursor_new (GDK_CROSS);
+ gdk_window_set_cursor (w->window, cursor);
+ gdk_cursor_destroy (cursor);
+ gdk_flush ();
+
+ /* dx < 0 == moving to the left */
+ dx = e->x - p->priv->last_x;
+ dy = e->y - p->priv->last_y;
+
+ if (dx < 0) {
+ p->priv->rubberband.xmin = e->x;
+ } else {
+ p->priv->rubberband.xmax = e->x;
+ }
+ if (dy < 0) {
+ p->priv->rubberband.ymin = e->y;
+ } else {
+ p->priv->rubberband.ymax = e->y;
+ }
+
+ p->priv->action = ACTION_REGION;
+ gtk_widget_queue_draw (w);
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+g_plot_button_press_cb (GtkWidget *w, GdkEventButton *e, GPlot *p)
+{
+ g_return_val_if_fail (IS_GPLOT (p), TRUE);
+
+ if (e->type == GDK_2BUTTON_PRESS) {
+ /* TODO : Chekck function below cursor and open a property dialog :) */
+ } else {
+ switch (p->priv->zoom_mode) {
+ case GPLOT_ZOOM_INOUT:
+ if (e->button == 1) {
+ p->priv->action = ACTION_STARTING_PAN;
+ p->priv->last_x = e->x;
+ p->priv->last_y = e->y;
+ }
+ break;
+ case GPLOT_ZOOM_REGION:
+ if ((e->button == 1)) {
+ p->priv->action = ACTION_STARTING_REGION;
+ p->priv->rubberband.xmin = e->x;
+ p->priv->rubberband.ymin = e->y;
+ p->priv->rubberband.xmax = e->x;
+ p->priv->rubberband.ymax = e->y;
+ p->priv->last_x = e->x;
+ p->priv->last_y = e->y;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+g_plot_button_release_cb (GtkWidget *w, GdkEventButton *e, GPlot *p)
+{
+ gdouble zoom;
+
+ g_return_val_if_fail (IS_GPLOT (p), TRUE);
+
+ switch (p->priv->zoom_mode) {
+ case GPLOT_ZOOM_INOUT:
+ if (p->priv->action != ACTION_PAN) {
+ switch (e->button) {
+ case 1:
+ p->priv->zoom += 0.1;
+ zoom = 1.1;
+ break;
+ case 3:
+ p->priv->zoom -= 0.1;
+ zoom = 0.9;
+ }
+ p->priv->window_bbox.xmin /= zoom;
+ p->priv->window_bbox.xmax /= zoom;
+ p->priv->window_bbox.ymin /= zoom;
+ p->priv->window_bbox.ymax /= zoom;
+ gtk_widget_queue_draw (w);
+ } else {
+ gdk_window_set_cursor (w->window, NULL);
+ gdk_flush ();
+ }
+ break;
+ case GPLOT_ZOOM_REGION:
+ if ((e->button == 1) && (p->priv->action == ACTION_REGION)) {
+ gdk_window_set_cursor (w->window, NULL);
+ gdk_flush ();
+ {
+ gdouble x1, y1, x2, y2;
+ cairo_matrix_t t = p->priv->matrix;
+ cairo_matrix_invert (&t);
+
+ x1 = p->priv->rubberband.xmin;
+ y1 = p->priv->rubberband.ymin;
+ x2 = p->priv->rubberband.xmax;
+ y2 = p->priv->rubberband.ymax;
+
+ cairo_matrix_transform_point (&t, &x1, &y1);
+ cairo_matrix_transform_point (&t, &x2, &y2);
+
+ p->priv->window_bbox.xmin = x1;
+ p->priv->window_bbox.xmax = x2;
+ p->priv->window_bbox.ymin = y2;
+ p->priv->window_bbox.ymax = y1;
+ }
+ } else if (e->button == 3) {
+ gdk_window_set_cursor (w->window, NULL);
+ gdk_flush ();
+ }
+ gtk_widget_queue_draw (w);
+ }
+
+ p->priv->action = ACTION_NONE;
+ return TRUE;
+}
+
+void
+g_plot_set_zoom_mode (GPlot *p, guint mode)
+{
+ g_return_if_fail (IS_GPLOT (p));
+
+ p->priv->zoom_mode = mode;
+}
+
+guint
+g_plot_get_zoom_mode (GPlot *p)
+{
+ g_return_val_if_fail (IS_GPLOT (p), 0);
+
+ return p->priv->zoom_mode;
+}
+
+static void
+g_plot_update_bbox (GPlot *p)
+{
+ GPlotFunction *f;
+ GPlotFunctionBBox bbox;
+ GPlotPriv *priv;
+ GList *lst;
+
+ priv = p->priv;
+
+ /* Get functions bbox */
+ priv->window_bbox.xmax = -9999999;
+ priv->window_bbox.xmin = 9999999;
+ priv->window_bbox.ymax = -9999999;
+ priv->window_bbox.ymin = 9999999;
+ lst = priv->functions;
+ while (lst) {
+ f = (GPlotFunction *)lst->data;
+ g_plot_function_get_bbox (f, &bbox);
+ priv->window_bbox.xmax = MAX (priv->window_bbox.xmax, bbox.xmax);
+ priv->window_bbox.xmin = MIN (priv->window_bbox.xmin, bbox.xmin);
+ priv->window_bbox.ymax = MAX (priv->window_bbox.ymax, bbox.ymax);
+ priv->window_bbox.ymin = MIN (priv->window_bbox.ymin, bbox.ymin);
+ lst = lst->next;
+ }
+
+ if (priv->window_bbox.xmin == priv->window_bbox.xmax)
+ priv->window_bbox.xmax += 1;
+
+ if (priv->window_bbox.ymin == priv->window_bbox.ymax)
+ priv->window_bbox.ymax += 1;
+
+ priv->window_bbox.ymin *= 1.1;
+ priv->window_bbox.ymax *= 1.1;
+
+ priv->window_valid = TRUE;
+}
+
+void
+g_plot_reset_zoom (GPlot *p)
+{
+ g_return_if_fail (IS_GPLOT (p));
+
+ p->priv->window_valid = FALSE;
+ p->priv->zoom = 1.0;
+ gtk_widget_queue_draw (GTK_WIDGET (p));
+}
+
+void
+g_plot_set_axis_labels (GPlot *p, gchar *x, gchar *y)
+{
+ cairo_text_extents_t extents;
+
+ g_return_if_fail (IS_GPLOT (p));
+
+ if (x) {
+ cairo_t *cr = g_plot_create_cairo (p);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_font_size (cr, 14);
+ cairo_text_extents (cr, x, &extents);
+ cairo_destroy (cr);
+
+ p->priv->xlabel = g_strdup (x);
+ p->priv->bottom_border = BORDER_SIZE + extents.height;
+ } else {
+ p->priv->bottom_border = BORDER_SIZE;
+ if (p->priv->xlabel) {
+ g_free (p->priv->xlabel);
+ p->priv->xlabel = NULL;
+ }
+ }
+
+ if (y) {
+ cairo_t *cr = g_plot_create_cairo (p);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_set_font_size (cr, 14);
+ cairo_text_extents (cr, y, &extents);
+ cairo_destroy (cr);
+
+ p->priv->xlabel = g_strdup (x);
+ p->priv->left_border = BORDER_SIZE + extents.height;
+
+ p->priv->ylabel = g_strdup (y);
+ } else {
+ p->priv->left_border = BORDER_SIZE;
+ if (p->priv->ylabel) {
+ g_free (p->priv->ylabel);
+ p->priv->ylabel = NULL;
+ }
+ }
+}
+
+void
+g_plot_clear (GPlot *plot)
+{
+ GList *lst;
+
+ g_return_if_fail (plot != NULL);
+ g_return_if_fail (IS_GPLOT (plot));
+
+ lst = plot->priv->functions;
+
+ while (lst) {
+ g_object_unref (G_OBJECT (lst->data));
+ lst = lst->next;
+ }
+ g_list_free (plot->priv->functions);
+ plot->priv->functions = NULL;
+ plot->priv->window_valid = FALSE;
+}
+
+void
+g_plot_window_to_device (GPlot *plot, double *x, double *y)
+{
+ cairo_t *cr;
+
+ g_return_if_fail (plot != NULL);
+ g_return_if_fail (IS_GPLOT (plot));
+
+ cr = g_plot_create_cairo (plot);
+ cairo_set_matrix (cr, &plot->priv->matrix);
+ cairo_device_to_user (cr, x, y);
+ cairo_destroy (cr);
+}
+
+static void
+get_order_of_magnitude (gdouble val, gdouble *man, gdouble *pw)
+{
+ gdouble b;
+ gdouble sx;
+
+ b = (val != 0.0 ? log10 (fabs (val)) / 3.0 : 0.0);
+ b = 3.0 * rint (b);
+ sx = (b != 0.0 ? pow (10.0, b) : 1.0);
+ *man = val / sx;
+ *pw = b;
+}
+
+
diff --git a/src/gplot/gplot.h b/src/gplot/gplot.h
new file mode 100644
index 0000000..041a597
--- /dev/null
+++ b/src/gplot/gplot.h
@@ -0,0 +1,70 @@
+/*
+ * gplot.h
+ *
+ * Authors:
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ *
+ * This library 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GPLOT_H_
+#define _GPLOT_H_
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+
+#include "gplotfunction.h"
+
+#define TYPE_GPLOT (g_plot_get_type())
+#define GPLOT(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, TYPE_GPLOT, GPlot)
+#define GPLOT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, TYPE_GPLOT, GPlotClass)
+#define IS_GPLOT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, TYPE_GPLOT)
+
+typedef struct _GPlot GPlot;
+typedef struct _GPlotClass GPlotClass;
+typedef struct _GPlotPriv GPlotPriv;
+
+enum {
+ GPLOT_ZOOM_INOUT,
+ GPLOT_ZOOM_REGION
+};
+
+struct _GPlot {
+ GtkLayout parent;
+
+ GPlotPriv *priv;
+};
+
+struct _GPlotClass {
+ GtkLayoutClass parent_class;
+};
+
+GType g_plot_get_type ();
+GtkWidget* g_plot_new ();
+void g_plot_clear (GPlot *);
+int g_plot_add_function (GPlot *, GPlotFunction *);
+void g_plot_set_zoom_mode (GPlot *, guint);
+guint g_plot_get_zoom_mode (GPlot *);
+void g_plot_reset_zoom (GPlot *);
+void g_plot_set_axis_labels (GPlot *, gchar *, gchar *);
+void g_plot_window_to_device (GPlot *, double *x, double *y);
+
+#endif
+
diff --git a/src/gplot/gplotfunction.c b/src/gplot/gplotfunction.c
new file mode 100644
index 0000000..576aa85
--- /dev/null
+++ b/src/gplot/gplotfunction.c
@@ -0,0 +1,80 @@
+/*
+ * gplotfunction.c
+ *
+ * Authors:
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ *
+ * This library 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gplotfunction.h"
+
+
+static void
+g_plot_function_base_init (gpointer g_class)
+{
+ static gboolean initialized = FALSE;
+ if (!initialized) {
+ /* create interface signals here. */
+ initialized = TRUE;
+
+ g_object_interface_install_property (g_class,
+ g_param_spec_boolean ("visible",
+ "gplot_function_visible",
+ "Get/Set if function is visible",
+ TRUE,
+ G_PARAM_READWRITE));
+ }
+}
+
+GType
+g_plot_function_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof (GPlotFunctionClass),
+ g_plot_function_base_init, /* base_init */
+ NULL, /* base_finalize */
+ NULL, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE, "GPlotFunction", &info, 0);
+ }
+ return type;
+}
+
+void
+g_plot_function_draw (GPlotFunction *self, cairo_t * cr, GPlotFunctionBBox *bbox)
+{
+ if (GPLOT_FUNCTION_GET_CLASS (self)->draw)
+ GPLOT_FUNCTION_GET_CLASS (self)->draw (self, cr, bbox);
+}
+
+void
+g_plot_function_get_bbox (GPlotFunction *self, GPlotFunctionBBox *bbox)
+{
+ if (GPLOT_FUNCTION_GET_CLASS (self)->get_bbox)
+ GPLOT_FUNCTION_GET_CLASS (self)->get_bbox (self, bbox);
+}
+
diff --git a/src/gplot/gplotfunction.h b/src/gplot/gplotfunction.h
new file mode 100644
index 0000000..8cbc523
--- /dev/null
+++ b/src/gplot/gplotfunction.h
@@ -0,0 +1,69 @@
+/*
+ * gplotfunction.h
+ *
+ * Authors:
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ *
+ * This library 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GPLOT_FUNCTION_H_
+#define _GPLOT_FUNCTION_H_
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+
+#define TYPE_GPLOT_FUNCTION (g_plot_function_get_type())
+#define GPLOT_FUNCTION(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, TYPE_GPLOT_FUNCTION, GPlotFunction)
+#define GPLOT_FUNCTION_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, TYPE_GPLOT_FUNCTION, GPlotFunctionClass)
+#define IS_GPLOT_FUNCTION (obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, TYPE_GPLOT_FUNCTION)
+#define GPLOT_FUNCTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TYPE_GPLOT_FUNCTION, GPlotFunctionClass))
+/*
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+*/
+
+typedef struct _GPlotFunctionBBox {
+ gdouble xmin;
+ gdouble ymin;
+ gdouble xmax;
+ gdouble ymax;
+} GPlotFunctionBBox;
+
+typedef struct _GPlotFunction {} GPlotFunction;
+typedef struct _GPlotFunctionClass GPlotFunctionClass;
+
+struct _GPlotFunctionClass {
+ GTypeInterface parent;
+
+ void (*draw)(GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
+ void (*get_bbox)(GPlotFunction *, GPlotFunctionBBox *);
+};
+
+
+GType g_plot_function_get_type ();
+void g_plot_function_draw (GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
+void g_plot_function_get_bbox (GPlotFunction *, GPlotFunctionBBox *);
+void g_plot_function_set_visible (GPlotFunction *, gboolean);
+gboolean g_plot_function_get_visible (GPlotFunction *);
+
+#endif
+
+
diff --git a/src/gplot/gplotlines.c b/src/gplot/gplotlines.c
new file mode 100644
index 0000000..5e9743e
--- /dev/null
+++ b/src/gplot/gplotlines.c
@@ -0,0 +1,294 @@
+/*
+ * gplotlines.c
+ *
+ * Authors:
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ *
+ * This library 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gplotlines.h"
+#include <string.h>
+
+static void g_plot_lines_class_init (GPlotLinesClass* class);
+static void g_plot_lines_init (GPlotLines* plot);
+static void g_plot_lines_draw (GPlotFunction *, cairo_t *, GPlotFunctionBBox *);
+static void g_plot_lines_get_bbox (GPlotFunction *, GPlotFunctionBBox *);
+static void g_plot_lines_function_init (GPlotFunctionClass *iface);
+static void g_plot_lines_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *spec);
+static void g_plot_lines_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *spec);
+
+static GObjectClass* parent_class = NULL;
+
+enum {
+ ARG_0,
+ ARG_WIDTH,
+ ARG_COLOR,
+ ARG_COLOR_GDKCOLOR,
+ ARG_VISIBLE,
+};
+
+struct _GPlotLinesPriv {
+ gboolean bbox_valid;
+ GPlotFunctionBBox bbox;
+ gdouble *x;
+ gdouble *y;
+ gdouble points;
+ gboolean visible;
+
+ /** Line width */
+ gdouble width;
+
+ /** Line Color */
+ gchar *color_string;
+ GdkColor color;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GPlotLines, g_plot_lines, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TYPE_GPLOT_FUNCTION,
+ g_plot_lines_function_init));
+
+static void
+g_plot_lines_function_init (GPlotFunctionClass *iface)
+{
+ iface->draw = g_plot_lines_draw;
+ iface->get_bbox = g_plot_lines_get_bbox;
+}
+
+static void
+g_plot_lines_dispose(GObject *object)
+{
+ G_OBJECT_CLASS(parent_class)->dispose(object);
+}
+
+static void
+g_plot_lines_finalize(GObject *object)
+{
+ GPlotLines *lines;
+
+ lines = GPLOT_LINES (object);
+
+ if (lines->priv) {
+ g_free (lines->priv->x);
+ g_free (lines->priv->y);
+ g_free (lines->priv->color_string);
+ g_free (lines->priv);
+ }
+
+ G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+static void
+g_plot_lines_class_init (GPlotLinesClass* class)
+{
+ GObjectClass* object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class->set_property = g_plot_lines_set_property;
+ object_class->get_property = g_plot_lines_get_property;
+ object_class->dispose = g_plot_lines_dispose;
+ object_class->finalize = g_plot_lines_finalize;
+
+ g_object_class_override_property (object_class, ARG_VISIBLE, "visible");
+
+ g_object_class_install_property(
+ object_class,
+ ARG_WIDTH,
+ g_param_spec_double ("width", "GPlotLines::width",
+ "the line width", 0.1, 5.0, 1.0, G_PARAM_READWRITE));
+
+ g_object_class_install_property(
+ object_class,
+ ARG_COLOR,
+ g_param_spec_string ("color", "GPlotLines::color",
+ "the string color line", "white", G_PARAM_READWRITE));
+
+ g_object_class_install_property(
+ object_class,
+ ARG_COLOR_GDKCOLOR,
+ g_param_spec_pointer ("color-rgb", "GPlotLines::color-rgb",
+ "the GdkColor of the line", G_PARAM_READWRITE));
+}
+
+static void
+g_plot_lines_init (GPlotLines* plot)
+{
+ GPlotLinesPriv* priv = g_new0 (GPlotLinesPriv, 1);
+
+ priv->bbox_valid = FALSE;
+
+ plot->priv = priv;
+
+ priv->width = 1.0;
+ priv->visible = TRUE;
+ priv->color_string = g_strdup ("white");
+ memset (&priv->color, 0xFF, sizeof (GdkColor));
+}
+
+static void
+g_plot_lines_set_property(GObject *object, guint prop_id, const GValue *value,
+ GParamSpec *spec)
+{
+ GPlotLines *plot = GPLOT_LINES (object);
+
+ switch (prop_id) {
+ case ARG_VISIBLE:
+ plot->priv->visible = g_value_get_boolean (value);
+ break;
+ case ARG_WIDTH:
+ plot->priv->width = g_value_get_double (value);
+ break;
+ case ARG_COLOR:
+ g_free (plot->priv->color_string);
+ plot->priv->color_string = g_strdup (g_value_get_string (value));
+ gdk_color_parse (plot->priv->color_string, &plot->priv->color);
+ break;
+ case ARG_COLOR_GDKCOLOR:
+ //s = g_value_get_string (value)
+ //gdk_color_parse (s, &plot->priv->color);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void
+g_plot_lines_get_property(GObject *object, guint prop_id, GValue *value,
+ GParamSpec *spec)
+{
+ GPlotLines *plot = GPLOT_LINES (object);
+
+ switch (prop_id) {
+ case ARG_WIDTH:
+ g_value_set_double (value, plot->priv->width);
+ break;
+ case ARG_VISIBLE:
+ g_value_set_boolean (value, plot->priv->visible);
+ break;
+ case ARG_COLOR:
+ g_value_set_string (value, plot->priv->color_string);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (plot, prop_id, spec);
+ }
+}
+
+GPlotFunction*
+g_plot_lines_new (gdouble *x, gdouble *y, guint points)
+{
+ GPlotLines *plot;
+
+ plot = GPLOT_LINES (g_object_new (TYPE_GPLOT_LINES, NULL));
+ plot->priv->x = x;
+ plot->priv->y = y;
+ plot->priv->points = points;
+
+ return GPLOT_FUNCTION (plot);
+}
+
+static void
+g_plot_lines_get_bbox (GPlotFunction *f, GPlotFunctionBBox *bbox)
+{
+ GPlotLines *plot;
+
+ g_return_if_fail (IS_GPLOT_LINES (f));
+
+ plot = GPLOT_LINES (f);
+ if (!plot->priv->bbox_valid) {
+ /* Update bbox */
+ guint point;
+ gdouble *x;
+ gdouble *y;
+ guint points;
+
+ points = plot->priv->points;
+ x = plot->priv->x;
+ y = plot->priv->y;
+ plot->priv->bbox.xmin = 99999999;
+ plot->priv->bbox.xmax = -99999999;
+ plot->priv->bbox.ymin = 99999999;
+ plot->priv->bbox.ymax = -99999999;
+ for (point = 0; point < points; point++) {
+ plot->priv->bbox.xmin = MIN(plot->priv->bbox.xmin, x[point]);
+ plot->priv->bbox.ymin = MIN(plot->priv->bbox.ymin, y[point]);
+ plot->priv->bbox.xmax = MAX(plot->priv->bbox.xmax, x[point]);
+ plot->priv->bbox.ymax = MAX(plot->priv->bbox.ymax, y[point]);
+ }
+ plot->priv->bbox_valid = TRUE;
+ }
+
+ (*bbox) = plot->priv->bbox;
+}
+
+static void
+g_plot_lines_draw (GPlotFunction *f, cairo_t *cr, GPlotFunctionBBox *bbox)
+{
+ gboolean first_point = TRUE;
+ guint point;
+ gdouble *x;
+ gdouble *y;
+ guint points;
+ GPlotLines *plot;
+
+ g_return_if_fail (IS_GPLOT_LINES (f));
+
+ plot = GPLOT_LINES (f);
+
+ if (!plot->priv->visible) return;
+
+ points = plot->priv->points;
+ x = plot->priv->x;
+ y = plot->priv->y;
+
+ for (point = 1; point < points; point++) {
+ if ((x[point] >= bbox->xmin) && (x[point] <= bbox->xmax) &&
+ (y[point] >= bbox->ymin) && (y[point] <= bbox->ymax)) {
+
+ if (first_point) {
+ cairo_move_to (cr, x[point-1], y[point-1]);
+ first_point = FALSE;
+ }
+
+ cairo_line_to (cr, x[point], y[point]);
+ } else {
+ if (!first_point) {
+ cairo_line_to (cr, x[point], y[point]);
+ first_point = TRUE;
+ }
+ }
+ }
+
+ if (point < points) {
+ cairo_line_to (cr, x[point], y[point]);
+ }
+
+ cairo_save (cr);
+ cairo_set_source_rgb (cr,
+ plot->priv->color.red / 65535.0,
+ plot->priv->color.green / 65535.0,
+ plot->priv->color.blue / 65535.0);
+ cairo_identity_matrix (cr);
+ cairo_set_line_width (cr, plot->priv->width);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+}
+
diff --git a/src/gplot/gplotlines.h b/src/gplot/gplotlines.h
new file mode 100644
index 0000000..c3dafb2
--- /dev/null
+++ b/src/gplot/gplotlines.h
@@ -0,0 +1,55 @@
+/*
+ * gplotlines.h
+ *
+ * Authors:
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2004 Ricardo Markiewicz
+ *
+ * This library 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 library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GPLOT_LINES_H_
+#define _GPLOT_LINES_H_
+
+#include "gplotfunction.h"
+
+#define TYPE_GPLOT_LINES (g_plot_lines_get_type())
+#define GPLOT_LINES(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, TYPE_GPLOT_LINES, GPlotLines)
+#define GPLOT_LINES_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, TYPE_GPLOT_LINES, GPlotLinesClass)
+#define IS_GPLOT_LINES(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, TYPE_GPLOT_LINES)
+
+typedef struct _GPlotLines GPlotLines;
+typedef struct _GPlotLinesPriv GPlotLinesPriv;
+typedef struct _GPlotLinesClass GPlotLinesClass;
+
+struct _GPlotLines {
+ GObject parent;
+
+ GPlotLinesPriv *priv;
+};
+
+struct _GPlotLinesClass {
+ GObjectClass parent;
+};
+
+GType g_plot_lines_get_type ();
+GPlotFunction* g_plot_lines_new (gdouble *x, gdouble *y, guint points);
+
+#endif
+
+