diff options
author | Maximiliano Curia <maxy@debian.org> | 2012-01-04 00:00:53 +0100 |
---|---|---|
committer | Maximiliano Curia <maxy@debian.org> | 2012-01-04 00:00:53 +0100 |
commit | 825fd5668026f70071c7a5eef277b0bf5c8f02d2 (patch) | |
tree | 4d3a9112d9887ea16ab5dda07a7a791f15d3278f /src/gplot/gplot.c |
Import oregano_0.70.orig.tar.gz
[dgit import orig oregano_0.70.orig.tar.gz]
Diffstat (limited to 'src/gplot/gplot.c')
-rw-r--r-- | src/gplot/gplot.c | 839 |
1 files changed, 839 insertions, 0 deletions
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; +} + + |