diff options
Diffstat (limited to 'deps/uber-graph/uber-scatter.c')
-rw-r--r-- | deps/uber-graph/uber-scatter.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/deps/uber-graph/uber-scatter.c b/deps/uber-graph/uber-scatter.c new file mode 100644 index 00000000..56c7b00d --- /dev/null +++ b/deps/uber-graph/uber-scatter.c @@ -0,0 +1,421 @@ +/* uber-scatter.c + * + * Copyright (C) 2010 Christian Hergert <chris@dronelabs.com> + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <math.h> +#include <string.h> + +#include "uber-scatter.h" +#include "uber-scale.h" +#include "uber-range.h" +#include "g-ring.h" + +#define RADIUS 3 + +/** + * SECTION:uber-scatter.h + * @title: UberScatter + * @short_description: + * + * Section overview. + */ + + +struct _UberScatterPrivate +{ + GRing *raw_data; + UberRange range; + guint stride; + GdkRGBA fg_color; + gboolean fg_color_set; + UberScatterFunc func; + gpointer func_user_data; + GDestroyNotify func_destroy; +}; + +G_DEFINE_TYPE_WITH_PRIVATE(UberScatter, uber_scatter, UBER_TYPE_GRAPH) + +/** + * uber_scatter_new: + * + * Creates a new instance of #UberScatter. + * + * Returns: the newly created instance of #UberScatter. + * Side effects: None. + */ +GtkWidget* +uber_scatter_new (void) +{ + UberScatter *scatter; + + scatter = g_object_new(UBER_TYPE_SCATTER, NULL); + return GTK_WIDGET(scatter); +} + +/** + * uber_scatter_set_data_func: + * @scatter: A #UberScatter. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +void +uber_scatter_set_data_func (UberScatter *scatter, /* IN */ + UberScatterFunc func, /* IN */ + gpointer user_data, /* IN */ + GDestroyNotify destroy) /* IN */ +{ + UberScatterPrivate *priv; + + g_return_if_fail(UBER_IS_SCATTER(scatter)); + g_return_if_fail(func != NULL); + + priv = scatter->priv; + /* + * Cleanup previous data func if necessary. + */ + if (priv->func_destroy) { + priv->func_destroy(priv->func_user_data); + } + priv->func = func; + priv->func_destroy = destroy; + priv->func_user_data = user_data; +} + +/** + * uber_scatter_destroy_array: + * @array: A #GArray. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_scatter_destroy_array (gpointer data) /* IN */ +{ + GArray **ar = data; + + if (ar) { + g_array_unref(*ar); + } +} + +/** + * uber_scatter_set_stride: + * @graph: A #UberGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_scatter_set_stride (UberGraph *graph, /* IN */ + guint stride) /* IN */ +{ + UberScatterPrivate *priv; + + g_return_if_fail(UBER_IS_SCATTER(graph)); + + priv = UBER_SCATTER(graph)->priv; + if (priv->stride == stride) { + return; + } + priv->stride = stride; + if (priv->raw_data) { + g_ring_unref(priv->raw_data); + } + priv->raw_data = g_ring_sized_new(sizeof(GArray*), stride, + uber_scatter_destroy_array); +} + +/** + * uber_scatter_render: + * @graph: A #UberGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_scatter_render (UberGraph *graph, /* IN */ + cairo_t *cr, /* IN */ + GdkRectangle *area, /* IN */ + guint epoch, /* IN */ + gfloat each) /* IN */ +{ + UberScatterPrivate *priv; + UberRange pixel_range; + GtkStyleContext *style; + GdkRGBA color; + GArray *ar; + gdouble x; + gdouble y; + guint i; + guint j; + + g_return_if_fail(UBER_IS_SCATTER(graph)); + + priv = UBER_SCATTER(graph)->priv; + color = priv->fg_color; + if (!priv->fg_color_set) { + style = gtk_widget_get_style_context(GTK_WIDGET(graph)); + gtk_style_context_get_color(style, GTK_STATE_FLAG_SELECTED, &color); + } + /* + * Calculate ranges. + */ + pixel_range.begin = area->y + (RADIUS / 2.); + pixel_range.end = area->y + area->height - RADIUS; + pixel_range.range = pixel_range.end - pixel_range.begin; + /* + * Retrieve the current data set. + */ + for (i = 0; i < priv->raw_data->len; i++) { + if (!(ar = g_ring_get_index(priv->raw_data, GArray*, (int)i))) { + continue; + } + x = epoch - (i * each) - (each / 2.); + for (j = 0; j < ar->len; j++) { + y = g_array_index(ar, gdouble, j); +// g_debug("Raw ==> %f", y); + uber_scale_linear(&priv->range, &pixel_range, &y, NULL); + /* + * Shadow. + */ + cairo_arc(cr, x + .5, y + .5, RADIUS, 0, 2 * M_PI); + cairo_set_source_rgb(cr, .1, .1, .1); + cairo_fill(cr); + /* + * Foreground. + */ + cairo_arc(cr, x, y, RADIUS, 0, 2 * M_PI); + cairo_set_source_rgb(cr, + color.red, + color.green, + color.blue); + cairo_fill(cr); + } + } +} + +/** + * uber_scatter_render_fast: + * @graph: A #UberGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_scatter_render_fast (UberGraph *graph, /* IN */ + cairo_t *cr, /* IN */ + GdkRectangle *area, /* IN */ + guint epoch, /* IN */ + gfloat each) /* IN */ +{ + UberScatterPrivate *priv; + UberRange pixel_range; + GtkStyleContext *style; + GdkRGBA color; + GArray *ar; + gdouble x; + gdouble y; + guint i; + + g_return_if_fail(UBER_IS_SCATTER(graph)); + + priv = UBER_SCATTER(graph)->priv; + color = priv->fg_color; + if (!priv->fg_color_set) { + style = gtk_widget_get_style_context(GTK_WIDGET(graph)); + gtk_style_context_get_color(style, GTK_STATE_FLAG_SELECTED, &color); + } + /* + * Calculate ranges. + */ + pixel_range.begin = area->y + (RADIUS / 2.); + pixel_range.end = area->y + area->height - RADIUS; + pixel_range.range = pixel_range.end - pixel_range.begin; + /* + * Retrieve the current data set. + */ + ar = g_ring_get_index(priv->raw_data, GArray*, 0); + if (!ar) { + return; + } + /* + * Calculate X position (Center of this chunk). + */ + x = epoch - (each / 2.); + /* + * Draw scatter dots. + */ + for (i = 0; i < ar->len; i++) { + /* + * Scale the value to our graph coordinates. + */ + y = g_array_index(ar, gdouble, i); + /* + * XXX: Support multiple scales. + */ + uber_scale_linear(&priv->range, &pixel_range, &y, NULL); + /* + * Shadow. + */ + cairo_arc(cr, x + .5, y + .5, RADIUS, 0, 2 * M_PI); + cairo_set_source_rgb(cr, .1, .1, .1); + cairo_fill(cr); + /* + * Foreground. + */ + cairo_arc(cr, x, y, RADIUS, 0, 2 * M_PI); + cairo_set_source_rgb(cr, + color.red, + color.green, + color.blue); + cairo_fill(cr); + } +} + +/** + * uber_scatter_get_next_data: + * @graph: A #UberGraph. + * + * Retrieve the next data point for the graph. + * + * Returns: None. + * Side effects: None. + */ +static gboolean +uber_scatter_get_next_data (UberGraph *graph) /* IN */ +{ + UberScatterPrivate *priv; + GArray *array = NULL; + + g_return_val_if_fail(UBER_IS_SCATTER(graph), FALSE); + + priv = UBER_SCATTER(graph)->priv; + if (priv->func) { + if (!priv->func(UBER_SCATTER(graph), &array, priv->func_user_data)) { + array = NULL; + } + g_ring_append_val(priv->raw_data, array); + return TRUE; + } + return FALSE; +} + +/** + * uber_scatter_set_fg_color: + * @scatter: A #UberScatter. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +void +uber_scatter_set_fg_color (UberScatter *scatter, /* IN */ + const GdkRGBA *color) /* IN */ +{ + UberScatterPrivate *priv; + + g_return_if_fail(UBER_IS_SCATTER(scatter)); + + priv = scatter->priv; + if (color) { + priv->fg_color = *color; + priv->fg_color_set = TRUE; + } else { + memset(&priv->fg_color, 0, sizeof(priv->fg_color)); + priv->fg_color_set = FALSE; + } +} + +/** + * uber_scatter_finalize: + * @object: A #UberScatter. + * + * Finalizer for a #UberScatter instance. Frees any resources held by + * the instance. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_scatter_finalize (GObject *object) /* IN */ +{ + G_OBJECT_CLASS(uber_scatter_parent_class)->finalize(object); +} + +/** + * uber_scatter_class_init: + * @klass: A #UberScatterClass. + * + * Initializes the #UberScatterClass and prepares the vtable. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_scatter_class_init (UberScatterClass *klass) /* IN */ +{ + GObjectClass *object_class; + UberGraphClass *graph_class; + + object_class = G_OBJECT_CLASS(klass); + object_class->finalize = uber_scatter_finalize; + + graph_class = UBER_GRAPH_CLASS(klass); + graph_class->render = uber_scatter_render; + graph_class->render_fast = uber_scatter_render_fast; + graph_class->set_stride = uber_scatter_set_stride; + graph_class->get_next_data = uber_scatter_get_next_data; +} + +/** + * uber_scatter_init: + * @scatter: A #UberScatter. + * + * Initializes the newly created #UberScatter instance. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_scatter_init (UberScatter *scatter) /* IN */ +{ + UberScatterPrivate *priv; + + scatter->priv = uber_scatter_get_instance_private(scatter); + + priv = scatter->priv; + + priv->range.begin = 0.; + priv->range.end = 15000.; + priv->range.range = priv->range.end - priv->range.begin; +} |