diff options
Diffstat (limited to 'deps/uber-graph/uber-line-graph.c')
-rw-r--r-- | deps/uber-graph/uber-line-graph.c | 1028 |
1 files changed, 1028 insertions, 0 deletions
diff --git a/deps/uber-graph/uber-line-graph.c b/deps/uber-graph/uber-line-graph.c new file mode 100644 index 00000000..776f5363 --- /dev/null +++ b/deps/uber-graph/uber-line-graph.c @@ -0,0 +1,1028 @@ +/* uber-line-graph.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-line-graph.h" +#include "uber-range.h" +#include "uber-scale.h" +#include "g-ring.h" + +#define RECT_BOTTOM(r) ((r).y + (r).height) +#define RECT_RIGHT(r) ((r).x + (r).width) +#define SCALE_FACTOR (0.2) + +/** + * SECTION:uber-line-graph.h + * @title: UberLineGraph + * @short_description: + * + * Section overview. + */ + + +typedef struct +{ + GRing *raw_data; + GdkRGBA color; + gdouble width; + gdouble *dashes; + gint num_dashes; + gdouble dash_offset; + UberLabel *label; + guint label_id; +} LineInfo; + +struct _UberLineGraphPrivate +{ + GArray *lines; + cairo_antialias_t antialias; + guint stride; + gboolean autoscale; + UberRange range; + UberScale scale; + gpointer scale_data; + GDestroyNotify scale_notify; + UberLineGraphFunc func; + gpointer func_data; + GDestroyNotify func_notify; +}; + +G_DEFINE_TYPE_WITH_PRIVATE(UberLineGraph, uber_line_graph, UBER_TYPE_GRAPH) + + +enum +{ + PROP_0, + PROP_AUTOSCALE, + PROP_RANGE, +}; + +/** + * uber_line_graph_init_ring: + * @ring: A #GRing. + * + * Initialize the #GRing to default values (UBER_LINE_GRAPH_NO_VALUE). + * + * Returns: None. + * Side effects: None. + */ +static inline void +uber_line_graph_init_ring (GRing *ring) /* IN */ +{ + gdouble val = UBER_LINE_GRAPH_NO_VALUE; + guint i; + + g_return_if_fail(ring != NULL); + + for (i = 0; i < ring->len; i++) { + g_ring_append_val(ring, val); + } +} + +/** + * uber_line_graph_new: + * + * Creates a new instance of #UberLineGraph. + * + * Returns: the newly created instance of #UberLineGraph. + * Side effects: None. + */ +GtkWidget* +uber_line_graph_new (void) +{ + UberLineGraph *graph; + + graph = g_object_new(UBER_TYPE_LINE_GRAPH, NULL); + return GTK_WIDGET(graph); +} + +/** + * uber_line_graph_color: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_color_changed (UberLabel *label, /* IN */ + GdkRGBA *color, /* IN */ + UberLineGraph *graph) /* IN */ +{ + UberLineGraphPrivate *priv; + LineInfo *info; + guint i; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(color != NULL); + + priv = graph->priv; + for (i = 0; i < priv->lines->len; i++) { + info = &g_array_index(priv->lines, LineInfo, i); + if (info->label == label) { + info->color = *color; + } + } + uber_graph_redraw(UBER_GRAPH(graph)); +} + +void +uber_line_graph_bind_label (UberLineGraph *graph, /* IN */ + guint line, /* IN */ + UberLabel *label) /* IN */ +{ + UberLineGraphPrivate *priv; + LineInfo *info; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(UBER_IS_LABEL(label)); + g_return_if_fail(line > 0); + g_return_if_fail(line <= graph->priv->lines->len); + + priv = graph->priv; + info = &g_array_index(priv->lines, LineInfo, line - 1); + if (info->label_id) { + g_signal_handler_disconnect(info->label, info->label_id); + } + info->label = label; + info->label_id = g_signal_connect(label, + "color-changed", + G_CALLBACK(uber_line_graph_color_changed), + graph); +} + +/** + * uber_line_graph_set_autoscale: + * @graph: A #UberLineGraph. + * @autoscale: Should we autoscale. + * + * Sets if we should autoscale the range of the graph when a new input + * value is outside the visible range. + * + * Returns: None. + * Side effects: None. + */ +void +uber_line_graph_set_autoscale (UberLineGraph *graph, /* IN */ + gboolean autoscale) /* IN */ +{ + UberLineGraphPrivate *priv; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + + priv = graph->priv; + priv->autoscale = autoscale; +} + +/** + * uber_line_graph_get_autoscale: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +gboolean +uber_line_graph_get_autoscale (UberLineGraph *graph) /* IN */ +{ + g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), FALSE); + return graph->priv->autoscale; +} + +/** + * uber_line_graph_add_line: + * @graph: A #UberLineGraph. + * @color: A #GdkRGBA for the line or %NULL. + * + * Adds a new line to the graph. If color is %NULL, the next value + * in the default color list will be used. + * + * See uber_line_graph_remove_line(). + * + * Returns: The line identifier. + * Side effects: None. + */ +gint +uber_line_graph_add_line (UberLineGraph *graph, /* IN */ + const GdkRGBA *color, /* IN */ + UberLabel *label) /* IN */ +{ + UberLineGraphPrivate *priv; + LineInfo info = { 0 }; + + g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), 0); + + priv = graph->priv; + info.width = 1.0; + /* + * Retrieve the lines color. + */ + if (color) { + info.color = *color; + } else { + gdk_rgba_parse(&info.color, "#729fcf"); + } + /* + * Allocate buffers for data points. + */ + info.raw_data = g_ring_sized_new(sizeof(gdouble), priv->stride, NULL); + uber_line_graph_init_ring(info.raw_data); + /* + * Store the newly crated line. + */ + g_array_append_val(priv->lines, info); + /* + * Mark the graph for full redraw. + */ + uber_graph_redraw(UBER_GRAPH(graph)); + /* + * Attach label. + */ + if (label) { + uber_line_graph_bind_label(graph, priv->lines->len, label); + uber_graph_add_label(UBER_GRAPH(graph), label); + uber_label_set_color(label, &info.color); + } + /* + * Line indexes start from 1. + */ + return priv->lines->len; +} + +/** + * uber_line_graph_set_antialias: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +void +uber_line_graph_set_antialias (UberLineGraph *graph, /* IN */ + cairo_antialias_t antialias) /* IN */ +{ + UberLineGraphPrivate *priv; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + + priv = graph->priv; + priv->antialias = antialias; + uber_graph_redraw(UBER_GRAPH(graph)); +} + +/** + * uber_line_graph_get_antialias: + * @graph: A #UberLineGraph. + * + * Retrieves the antialias mode for the graph. + * + * Returns: A cairo_antialias_t. + * Side effects: None. + */ +cairo_antialias_t +uber_line_graph_get_antialias (UberLineGraph *graph) /* IN */ +{ + g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), 0); + + return graph->priv->antialias; +} + +/** + * uber_line_graph_get_next_data: + * @graph: A #UberGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static gboolean +uber_line_graph_get_next_data (UberGraph *graph) /* IN */ +{ + UberLineGraphPrivate *priv; + gboolean scale_changed = FALSE; + gboolean ret = FALSE; + LineInfo *line; + gdouble val; + guint i; + + g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), FALSE); + + priv = UBER_LINE_GRAPH(graph)->priv; + /* + * Retrieve the next data point. + */ + if (priv->func) { + for (i = 0; i < priv->lines->len; i++) { + line = &g_array_index(priv->lines, LineInfo, i); + val = priv->func(UBER_LINE_GRAPH(graph), i + 1, priv->func_data); + g_ring_append_val(line->raw_data, val); + if (priv->autoscale) { + if (val < priv->range.begin) { + priv->range.begin = val - (val * SCALE_FACTOR); + priv->range.range = priv->range.end - priv->range.begin; + scale_changed = TRUE; + } else if (val > priv->range.end) { + priv->range.end = val + (val * SCALE_FACTOR); + priv->range.range = priv->range.end - priv->range.begin; + scale_changed = TRUE; + } + } + } + } + if (scale_changed) { + uber_graph_scale_changed(graph); + } + return ret; +} + +/** + * uber_line_graph_set_data_func: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +void +uber_line_graph_set_data_func (UberLineGraph *graph, /* IN */ + UberLineGraphFunc func, /* IN */ + gpointer user_data, /* IN */ + GDestroyNotify notify) /* IN */ +{ + UberLineGraphPrivate *priv; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + + priv = graph->priv; + /* + * Free existing data func if neccessary. + */ + if (priv->func_notify) { + priv->func_notify(priv->func_data); + } + /* + * Store data func. + */ + priv->func = func; + priv->func_data = user_data; + priv->func_notify = notify; +} + +/** + * uber_line_graph_stylize_line: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_stylize_line (UberLineGraph *graph, /* IN */ + LineInfo *info, /* IN */ + cairo_t *cr) /* IN */ +{ + UberLineGraphPrivate *priv; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(info != NULL); + + priv = graph->priv; + if (info->dashes) { + cairo_set_dash(cr, info->dashes, info->num_dashes, info->dash_offset); + } else { + cairo_set_dash(cr, NULL, 0, 0); + } + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width(cr, info->width); + cairo_set_antialias(cr, priv->antialias); + cairo_set_source_rgba(cr, + info->color.red, + info->color.green, + info->color.blue, + info->color.alpha); +} + +/** + * uber_line_graph_render: + * @graph: A #UberGraph. + * @cr: A #cairo_t context. + * @area: Full area to render contents within. + * @line: The line to render. + * + * Render a particular line to the graph. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_render_line (UberLineGraph *graph, /* IN */ + cairo_t *cr, /* IN */ + GdkRectangle *area, /* IN */ + LineInfo *line, /* IN */ + guint epoch, /* IN */ + gfloat each) /* IN */ +{ + UberLineGraphPrivate *priv; + UberRange pixel_range; + GdkRectangle vis; + guint x; + guint last_x; + gdouble y; + gdouble last_y; + gdouble val; + guint i; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + + priv = graph->priv; + uber_graph_get_content_area(UBER_GRAPH(graph), &vis); + pixel_range.begin = area->y + 1; + pixel_range.end = area->y + area->height; + pixel_range.range = pixel_range.end - pixel_range.begin; + /* + * Prepare cairo settings. + */ + uber_line_graph_stylize_line(graph, line, cr); + /* + * Force a new path. + */ + cairo_new_path(cr); + /* + * Draw the line contents as bezier curves. + */ + for (i = 0; i < line->raw_data->len; i++) { + /* + * Retrieve data point. + */ + val = g_ring_get_index(line->raw_data, gdouble, (int)i); + /* + * Once we get to UBER_LINE_GRAPH_NO_VALUE, we must be at the end of the data + * sequence. This may not always be true in the future. + */ + if (val == UBER_LINE_GRAPH_NO_VALUE) { + break; + } + /* + * Translate value to coordinate system. + */ + if (!priv->scale(&priv->range, &pixel_range, &val, priv->scale_data)) { + break; + } + /* + * Calculate X/Y coordinate. + */ + y = (gint)(RECT_BOTTOM(*area) - val) - .5; + x = epoch - (each * i); + if (i == 0) { + /* + * Just move to the right position on first entry. + */ + cairo_move_to(cr, x, y); + goto next; + } else { + /* + * Draw curve to data point using the last X/Y positions as + * control points. + */ + cairo_curve_to(cr, + last_x - (each / 2.), + last_y, + last_x - (each / 2.), + y, x, y); + } + next: + last_y = y; + last_x = x; + } + /* + * Stroke the line content. + */ + cairo_stroke(cr); +} + +/** + * uber_line_graph_render: + * @graph: A #UberGraph. + * + * Render the entire contents of the graph. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_render (UberGraph *graph, /* IN */ + cairo_t *cr, /* IN */ + GdkRectangle *rect, /* IN */ + guint epoch, /* IN */ + gfloat each) /* IN */ +{ + UberLineGraphPrivate *priv; + LineInfo *line; + guint i; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + + priv = UBER_LINE_GRAPH(graph)->priv; + /* + * Render each line to the graph. + */ + for (i = 0; i < priv->lines->len; i++) { + line = &g_array_index(priv->lines, LineInfo, i); + uber_line_graph_render_line(UBER_LINE_GRAPH(graph), cr, rect, + line, epoch, each); + } +} + +/** + * uber_line_graph_render_fast: + * @graph: A #UberGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_render_fast (UberGraph *graph, /* IN */ + cairo_t *cr, /* IN */ + GdkRectangle *rect, /* IN */ + guint epoch, /* IN */ + gfloat each) /* IN */ +{ + UberLineGraphPrivate *priv; + UberRange pixel_range; + LineInfo *line; + gdouble last_y; + gdouble y; + guint i; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(cr != NULL); + g_return_if_fail(rect != NULL); + + priv = UBER_LINE_GRAPH(graph)->priv; + pixel_range.begin = rect->y + 1; + pixel_range.end = rect->y + rect->height; + pixel_range.range = pixel_range.end - pixel_range.begin; + /* + * Render most recent data point for each line. + */ + for (i = 0; i < priv->lines->len; i++) { + line = &g_array_index(priv->lines, LineInfo, i); + uber_line_graph_stylize_line(UBER_LINE_GRAPH(graph), line, cr); + /* + * Calculate positions. + */ + y = g_ring_get_index(line->raw_data, gdouble, 0); + last_y = g_ring_get_index(line->raw_data, gdouble, 1); + /* + * Don't try to draw before we have real values. + */ + if ((isnan(y) || isinf(y)) || (isnan(last_y) || isinf(last_y))) { + continue; + } + /* + * Translate to coordinate scale. + */ + if (!priv->scale(&priv->range, &pixel_range, &y, priv->scale_data) || + !priv->scale(&priv->range, &pixel_range, &last_y, priv->scale_data)) { + continue; + } + /* + * Translate position from bottom right corner. + */ + y = (gint)(RECT_BOTTOM(*rect) - y) - .5; + last_y = (gint)(RECT_BOTTOM(*rect) - last_y) - .5; + /* + * Convert relative position to fixed from bottom pixel. + */ + cairo_new_path(cr); + cairo_move_to(cr, epoch, y); + cairo_curve_to(cr, + epoch - (each / 2.), + y, + epoch - (each / 2.), + last_y, + epoch - each, + last_y); + cairo_stroke(cr); + } +} + +/** + * uber_line_graph_set_stride: + * @graph: A #UberGraph. + * @stride: The number of data points within the graph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_set_stride (UberGraph *graph, /* IN */ + guint stride) /* IN */ +{ + UberLineGraphPrivate *priv; + LineInfo *line; + guint i; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + + priv = UBER_LINE_GRAPH(graph)->priv; + priv->stride = stride; + /* + * TODO: Support changing stride after lines have been added. + */ + if (priv->lines->len) { + for (i = 0; i < priv->lines->len; i++) { + line = &g_array_index(priv->lines, LineInfo, i); + g_ring_unref(line->raw_data); + line->raw_data = g_ring_sized_new(sizeof(gdouble), + priv->stride, NULL); + uber_line_graph_init_ring(line->raw_data); + } + return; + } +} + +/** + * uber_line_graph_get_range: + * @graph: (in): A #UberLineGraph. + * + * XXX + * + * Returns: An #UberRange which should not be modified or freed. + * Side effects: None. + */ +const UberRange* +uber_line_graph_get_range (UberLineGraph *graph) /* IN */ +{ + g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), NULL); + return &graph->priv->range; +} + +/** + * uber_line_graph_set_range: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +void +uber_line_graph_set_range (UberLineGraph *graph, /* IN */ + const UberRange *range) /* IN */ +{ + UberLineGraphPrivate *priv; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(range != NULL); + + priv = graph->priv; + priv->range = *range; +} + +/** + * uber_line_graph_get_yrange: + * @graph: A #UberGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_get_yrange (UberGraph *graph, /* IN */ + UberRange *range) /* OUT */ +{ + UberLineGraphPrivate *priv; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(range != NULL); + + priv = UBER_LINE_GRAPH(graph)->priv; + *range = priv->range; +} + +/** + * uber_line_graph_set_line_dash: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +void +uber_line_graph_set_line_dash (UberLineGraph *graph, /* IN */ + guint line, /* IN */ + const gdouble *dashes, /* IN */ + gint num_dashes, /* IN */ + gdouble offset) /* IN */ +{ + UberLineGraphPrivate *priv; + LineInfo *info; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(dashes != NULL); + g_return_if_fail(num_dashes > 0); + g_return_if_fail(line > 0); + g_return_if_fail(line <= graph->priv->lines->len); + + priv = graph->priv; + info = &g_array_index(priv->lines, LineInfo, line - 1); + if (info->dashes) { + g_free(info->dashes); + info->dashes = NULL; + info->num_dashes = 0; + info->dash_offset = 0; + } + if (dashes) { + info->dashes = g_new0(gdouble, num_dashes); + memcpy(info->dashes, dashes, sizeof(gdouble) * num_dashes); + info->num_dashes = num_dashes; + info->dash_offset = offset; + } +} + +/** + * uber_line_graph_set_line_width: + * @graph: A #UberLineGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +void +uber_line_graph_set_line_width (UberLineGraph *graph, /* IN */ + gint line, /* IN */ + gdouble width) /* IN */ +{ + LineInfo *info; + + g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); + g_return_if_fail(line > 0); + g_return_if_fail(line <= (int)graph->priv->lines->len); + + info = &g_array_index(graph->priv->lines, LineInfo, line - 1); + info->width = width; + uber_graph_redraw(UBER_GRAPH(graph)); +} + +/** + * uber_line_graph_downscale: + * @graph: A #UberGraph. + * + * XXX + * + * Returns: None. + * Side effects: None. + */ +static gboolean +uber_line_graph_downscale (UberGraph *graph) /* IN */ +{ + UberLineGraphPrivate *priv; + gboolean ret = FALSE; + gdouble val = 0; + gdouble cur; + LineInfo *line; + guint i; + guint j; + + g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), FALSE); + + priv = UBER_LINE_GRAPH(graph)->priv; + /* + * If we are set to autoscale, ignore request. + */ + if (!priv->autoscale) { + return FALSE; + } + /* + * Determine the largest value available. + */ + for (i = 0; i < priv->lines->len; i++) { + line = &g_array_index(priv->lines, LineInfo, i); + for (j = 0; j < line->raw_data->len; j++) { + cur = g_ring_get_index(line->raw_data, gdouble, (int)j); + val = (cur > val) ? cur : val; + } + } + /* + * Downscale if we can. + */ + if (val != priv->range.begin) { + if ((val * (1. + SCALE_FACTOR)) < priv->range.end) { + priv->range.end = val * (1. + SCALE_FACTOR); + priv->range.range = priv->range.end - priv->range.begin; + ret = TRUE; + } + } + return ret; +} + +/** + * uber_line_graph_finalize: + * @object: A #UberLineGraph. + * + * Finalizer for a #UberLineGraph instance. Frees any resources held by + * the instance. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_finalize (GObject *object) /* IN */ +{ + UberLineGraphPrivate *priv; + LineInfo *line; + guint i; + + priv = UBER_LINE_GRAPH(object)->priv; + /* + * Clean up after cached values. + */ + for (i = 0; i < priv->lines->len; i++) { + line = &g_array_index(priv->lines, LineInfo, i); + g_ring_unref(line->raw_data); + g_free(line->dashes); + } + G_OBJECT_CLASS(uber_line_graph_parent_class)->finalize(object); +} + +/** + * uber_line_graph_set_property: + * @object: (in): A #GObject. + * @prop_id: (in): The property identifier. + * @value: (out): The given property. + * @pspec: (in): A #ParamSpec. + * + * Get a given #GObject property. + */ +static void +uber_line_graph_get_property (GObject *object, /* IN */ + guint prop_id, /* IN */ + GValue *value, /* OUT */ + GParamSpec *pspec) /* IN */ +{ + UberLineGraph *graph = UBER_LINE_GRAPH(object); + + switch (prop_id) { + case PROP_AUTOSCALE: + g_value_set_boolean(value, uber_line_graph_get_autoscale(graph)); + break; + case PROP_RANGE: + g_value_set_boxed(value, uber_line_graph_get_range(graph)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +/** + * uber_line_graph_set_property: + * @object: (in): A #GObject. + * @prop_id: (in): The property identifier. + * @value: (in): The given property. + * @pspec: (in): A #ParamSpec. + * + * Set a given #GObject property. + */ +static void +uber_line_graph_set_property (GObject *object, /* IN */ + guint prop_id, /* IN */ + const GValue *value, /* IN */ + GParamSpec *pspec) /* IN */ +{ + UberLineGraph *graph = UBER_LINE_GRAPH(object); + + switch (prop_id) { + case PROP_AUTOSCALE: + uber_line_graph_set_autoscale(graph, g_value_get_boolean(value)); + break; + case PROP_RANGE: + uber_line_graph_set_range(graph, g_value_get_boxed(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +/** + * uber_line_graph_class_init: + * @klass: A #UberLineGraphClass. + * + * Initializes the #UberLineGraphClass and prepares the vtable. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_class_init (UberLineGraphClass *klass) /* IN */ +{ + GObjectClass *object_class; + UberGraphClass *graph_class; + + object_class = G_OBJECT_CLASS(klass); + object_class->finalize = uber_line_graph_finalize; + object_class->get_property = uber_line_graph_get_property; + object_class->set_property = uber_line_graph_set_property; + + graph_class = UBER_GRAPH_CLASS(klass); + graph_class->downscale = uber_line_graph_downscale; + graph_class->get_next_data = uber_line_graph_get_next_data; + graph_class->get_yrange = uber_line_graph_get_yrange; + graph_class->render = uber_line_graph_render; + graph_class->render_fast = uber_line_graph_render_fast; + graph_class->set_stride = uber_line_graph_set_stride; + + g_object_class_install_property(object_class, + PROP_AUTOSCALE, + g_param_spec_boolean("autoscale", + "autoscale", + "autoscale", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property(object_class, + PROP_RANGE, + g_param_spec_boxed("range", + "range", + "range", + UBER_TYPE_RANGE, + G_PARAM_READWRITE)); +} + +/** + * uber_line_graph_init: + * @graph: A #UberLineGraph. + * + * Initializes the newly created #UberLineGraph instance. + * + * Returns: None. + * Side effects: None. + */ +static void +uber_line_graph_init (UberLineGraph *graph) /* IN */ +{ + UberLineGraphPrivate *priv; + + /* + * Keep pointer to private data. + */ + graph->priv = uber_line_graph_get_instance_private(graph); + + priv = graph->priv; + /* + * Initialize defaults. + */ + priv->stride = 60; + priv->antialias = CAIRO_ANTIALIAS_DEFAULT; + priv->lines = g_array_sized_new(FALSE, FALSE, sizeof(LineInfo), 2); + priv->scale = uber_scale_linear; + priv->autoscale = TRUE; +} + +void +uber_line_graph_clear (UberLineGraph *graph) /* IN */ +{ + UberLineGraphPrivate *priv = graph->priv; + LineInfo *line; + guint i; + + for (i = 0; i < priv->lines->len; i++) { + line = &g_array_index(priv->lines, LineInfo, i); + uber_line_graph_init_ring(line->raw_data); + } +} |