[goffice] Implement dropbar plots with linear or logarithmic index axis. [#646832]
- From: Jean Bréfort <jbrefort src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Implement dropbar plots with linear or logarithmic index axis. [#646832]
- Date: Wed, 6 Apr 2011 13:40:32 +0000 (UTC)
commit ad6273dd9065400f25cc1033bbb41a954200832d
Author: Jean Brefort <jean brefort normalesup org>
Date: Wed Apr 6 15:38:35 2011 +0200
Implement dropbar plots with linear or logarithmic index axis. [#646832]
ChangeLog | 7 +
NEWS | 1 +
goffice/graph/gog-plot-engine.c | 32 +-
pixmaps/Makefile.am | 1 +
plugins/plot_xy/Makefile.am | 7 +-
plugins/plot_xy/gog-xy-dropbar-prefs.ui | 88 +++++
plugins/plot_xy/gog-xy-dropbar.c | 538 +++++++++++++++++++++++++++++++
plugins/plot_xy/gog-xy-dropbar.h | 54 +++
plugins/plot_xy/gog-xy.c | 4 +
plugins/plot_xy/plot-types.xml.in | 19 ++
plugins/plot_xy/plugin.xml.in | 5 +
11 files changed, 740 insertions(+), 16 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 8d685a6..f5c3835 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2011-04-06 Jean Brefort <jean brefort normalesup org>
+
+ * plugins/plot_xy/gog-xy-dropbar-prefs.ui: implement dropbar plots with
+ linear or logarithmic index axis. [#646832]
+ * plugins/plot_xy/gog-xy-dropbar.c: ditto.
+ * plugins/plot_xy/gog-xy-dropbar.h: ditto.
+
2011-04-04 Jean Brefort <jean brefort normalesup org>
* goffice/utils/go-bezier.c (go_bezier_spline_init): fixed closed bezier
diff --git a/NEWS b/NEWS
index b7a07b5..48851c5 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ goffice 0.8.15:
Jean:
* Fixed closed bezier spline evaluation. [#646700]
+ * Implement dropbar plots with linear or logarithmic index axis. [#646832]
Morten:
* Plug leaks.
diff --git a/goffice/graph/gog-plot-engine.c b/goffice/graph/gog-plot-engine.c
index 2a40a1f..4359a40 100644
--- a/goffice/graph/gog-plot-engine.c
+++ b/goffice/graph/gog-plot-engine.c
@@ -153,20 +153,24 @@ cb_pending_plot_types_load (char const *path,
for (ptr = doc->xmlRootNode->xmlChildrenNode; ptr ; ptr = ptr->next)
if (!xmlIsBlankNode (ptr) && ptr->name && !strcmp (ptr->name, "Family")) {
name = xmlGetProp (ptr, "_name");
- image_file = xmlGetProp (ptr, "sample_image_file");
- if (!go_xml_node_get_int (ptr, "priority", &priority))
- priority = 0;
- axis_set_str = xmlGetProp (ptr, "axis_set");
- axis_set = gog_axis_set_from_str (axis_set_str);
- if (axis_set_str != NULL)
- xmlFree (axis_set_str);
- else
- g_warning ("[GogPlotTypeService::plot_types_load] missing axis set type");
- family = gog_plot_family_register (name, image_file, priority, axis_set);
- if (family != NULL)
- service->families = g_slist_prepend (service->families, family);
- if (name != NULL) xmlFree (name);
- if (image_file != NULL) xmlFree (image_file);
+ if (name) {
+ if (NULL == gog_plot_family_by_name (name)) {
+ image_file = xmlGetProp (ptr, "sample_image_file");
+ if (!go_xml_node_get_int (ptr, "priority", &priority))
+ priority = 0;
+ axis_set_str = xmlGetProp (ptr, "axis_set");
+ axis_set = gog_axis_set_from_str (axis_set_str);
+ if (axis_set_str != NULL)
+ xmlFree (axis_set_str);
+ else
+ g_warning ("[GogPlotTypeService::plot_types_load] missing axis set type");
+ family = gog_plot_family_register (name, image_file, priority, axis_set);
+ if (family != NULL)
+ service->families = g_slist_prepend (service->families, family);
+ if (image_file != NULL) xmlFree (image_file);
+ }
+ xmlFree (name);
+ }
}
for (ptr = doc->xmlRootNode->xmlChildrenNode; ptr ; ptr = ptr->next)
diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am
index 821c728..43f87af 100644
--- a/pixmaps/Makefile.am
+++ b/pixmaps/Makefile.am
@@ -38,6 +38,7 @@ dist_icon_DATA = \
chart_boxplot_1_1.png chart_boxplot_1_2.png \
chart_boxplot_2_1.png chart_boxplot_2_2.png \
chart_dropbar_1_1.png chart_dropbar_1_2.png \
+ chart_dropbar_1_3.png chart_dropbar_1_4.png \
chart_minmax_1_1.png chart_minmax_1_2.png \
chart_minmax_2_1.png chart_minmax_2_2.png \
chart_histogram_1_1.png chart_histogram_2_1.png \
diff --git a/plugins/plot_xy/Makefile.am b/plugins/plot_xy/Makefile.am
index 2060745..16d1743 100644
--- a/plugins/plot_xy/Makefile.am
+++ b/plugins/plot_xy/Makefile.am
@@ -8,7 +8,9 @@ xy_la_LIBADD = $(GOFFICE_PLUGIN_LIBADD)
xy_la_SOURCES = \
gog-xy.c \
- gog-xy.h
+ gog-xy.h \
+ gog-xy-dropbar.c \
+ gog-xy-dropbar.h
xml_in_files = plugin.xml.in plot-types.xml.in
xml_DATA = $(xml_in_files:.xml.in=.xml)
@@ -21,7 +23,8 @@ dist_ui_DATA = \
gog-bubble-prefs.ui \
gog-xy-prefs.ui \
gog-xy-color-prefs.ui \
- gog-xy-series-prefs.ui
+ gog-xy-series-prefs.ui \
+ gog-xy-dropbar-prefs.ui
endif
# do not use the intl-tool stuff to merge the text back
diff --git a/plugins/plot_xy/gog-xy-dropbar-prefs.ui b/plugins/plot_xy/gog-xy-dropbar-prefs.ui
new file mode 100644
index 0000000..78f6a56
--- /dev/null
+++ b/plugins/plot_xy/gog-xy-dropbar-prefs.ui
@@ -0,0 +1,88 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkAdjustment" id="width-adj">
+ <property name="value">50</property>
+ <property name="upper">500</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkTable" id="gog-xy-dropbar-prefs">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="horizontal">
+ <property name="label" translatable="yes">_Horizontal</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="width-lbl">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Bar _width:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">width-btn</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="width-btn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="adjustment">width-adj</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="before-grid">
+ <property name="label" translatable="yes">_Display the grids above the plot</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+</interface>
diff --git a/plugins/plot_xy/gog-xy-dropbar.c b/plugins/plot_xy/gog-xy-dropbar.c
new file mode 100644
index 0000000..2e4bb3b
--- /dev/null
+++ b/plugins/plot_xy/gog-xy-dropbar.c
@@ -0,0 +1,538 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-dropbar.c
+ *
+ * Copyright (C) 2005
+ * Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include "gog-xy-dropbar.h"
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+static GogObjectClass *gog_xy_dropbar_parent_klass;
+
+static GType gog_xy_dropbar_view_get_type (void);
+static GType gog_xy_dropbar_series_get_type (void);
+
+enum {
+ XY_DROPBAR_PROP_FILL_0,
+ XY_DROPBAR_PROP_FILL_BEFORE_GRID,
+ XY_DROPBAR_PROP_HORIZONTAL,
+ XY_DROPBAR_PROP_WIDTH
+};
+
+static void
+gog_xy_dropbar_plot_clear_formats (GogXYDropBarPlot *plot)
+{
+ go_format_unref (plot->x.fmt);
+ plot->x.fmt = NULL;
+
+ go_format_unref (plot->y.fmt);
+ plot->y.fmt = NULL;
+}
+
+static void
+gog_xy_dropbar_set_property (GObject *obj, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GogPlot *plot = GOG_PLOT (obj);
+ GogXYDropBarPlot *dropbar = GOG_XY_DROPBAR_PLOT (obj);
+ switch (param_id) {
+ case XY_DROPBAR_PROP_FILL_BEFORE_GRID:
+ plot->rendering_order = (g_value_get_boolean (value))?
+ GOG_PLOT_RENDERING_BEFORE_GRID:
+ GOG_PLOT_RENDERING_LAST;
+ break;
+ case XY_DROPBAR_PROP_HORIZONTAL:
+ dropbar->horizontal = g_value_get_boolean (value);
+ break;
+ case XY_DROPBAR_PROP_WIDTH:
+ dropbar->width = g_value_get_double (value);
+ break;
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ return;
+ }
+ gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
+}
+
+static void
+gog_xy_dropbar_get_property (GObject *obj, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GogPlot *plot = GOG_PLOT (obj);
+ GogXYDropBarPlot *dropbar = GOG_XY_DROPBAR_PLOT (obj);
+
+ switch (param_id) {
+ case XY_DROPBAR_PROP_FILL_BEFORE_GRID:
+ g_value_set_boolean (value, plot->rendering_order == GOG_PLOT_RENDERING_BEFORE_GRID);
+ break;
+ case XY_DROPBAR_PROP_HORIZONTAL:
+ g_value_set_boolean (value, dropbar->horizontal);
+ break;
+ case XY_DROPBAR_PROP_WIDTH:
+ g_value_set_double (value, dropbar->width);
+ break;
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gog_xy_dropbar_finalize (GObject *obj)
+{
+ gog_xy_dropbar_plot_clear_formats (GOG_XY_DROPBAR_PLOT (obj));
+ G_OBJECT_CLASS (gog_xy_dropbar_parent_klass)->finalize (obj);
+}
+
+#ifdef GOFFICE_WITH_GTK
+static void
+display_before_grid_cb (GtkToggleButton *btn, GObject *obj)
+{
+ g_object_set (obj, "before-grid", gtk_toggle_button_get_active (btn), NULL);
+}
+
+static void
+horizontal_cb (GtkToggleButton *btn, GObject *obj)
+{
+ g_object_set (obj, "horizontal", gtk_toggle_button_get_active (btn), NULL);
+}
+
+static void
+value_changed_cb (GtkSpinButton *btn, GObject *obj)
+{
+ g_object_set (obj, "width", gtk_spin_button_get_value (btn), NULL);
+}
+#endif
+
+static void
+gog_xy_dropbar_populate_editor (GogObject *obj,
+ GOEditor *editor,
+ GogDataAllocator *dalloc,
+ GOCmdContext *cc)
+{
+#ifdef GOFFICE_WITH_GTK
+ GtkBuilder *gui;
+ char const *dir;
+ char *path;
+ GogXYDropBarPlot *dropbar = GOG_XY_DROPBAR_PLOT (obj);
+
+ dir = go_plugin_get_dir_name (go_plugins_get_plugin_by_id ("GOffice_plot_xy"));
+ path = g_build_filename (dir, "gog-xy-dropbar-prefs.ui", NULL);
+ gui = go_gtk_builder_new (path, GETTEXT_PACKAGE, cc);
+ g_free (path);
+
+ if (gui != NULL) {
+ GtkWidget *w = go_gtk_builder_get_widget (gui, "before-grid");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
+ (GOG_PLOT (obj))->rendering_order == GOG_PLOT_RENDERING_BEFORE_GRID);
+ g_signal_connect (G_OBJECT (w),
+ "toggled",
+ G_CALLBACK (display_before_grid_cb), obj);
+ w = go_gtk_builder_get_widget (gui, "horizontal");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), dropbar->horizontal);
+ g_signal_connect (G_OBJECT (w),
+ "toggled",
+ G_CALLBACK (horizontal_cb), obj);
+ w = go_gtk_builder_get_widget (gui, "width-btn");
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), dropbar->width);
+ g_signal_connect (G_OBJECT (w),
+ "value_changed",
+ G_CALLBACK (value_changed_cb), obj);
+ w = go_gtk_builder_get_widget (gui, "gog-xy-dropbar-prefs");
+ go_editor_add_page (editor, w, _("Properties"));
+ g_object_unref (gui);
+ }
+
+#endif
+ gog_xy_dropbar_parent_klass->populate_editor (obj, editor, dalloc, cc);
+};
+
+static void
+gog_xy_dropbar_plot_update (GogObject *obj)
+{
+ GogXYDropBarPlot *model = GOG_XY_DROPBAR_PLOT (obj);
+ GogSeries const *series = NULL;
+ double x_min, x_max, y_min, y_max, tmp_min, tmp_max;
+ GSList *ptr;
+ gboolean is_discrete = FALSE;
+ struct axes_data *realx, *realy;
+
+ if (model->horizontal) {
+ realx = &model->y;
+ realy = &model->x;
+ } else {
+ realx = &model->x;
+ realy = &model->y;
+ }
+ x_min = y_min = DBL_MAX;
+ x_max = y_max = -DBL_MAX;
+ gog_xy_dropbar_plot_clear_formats (model);
+ for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) {
+ series = ptr->data;
+ if (!gog_series_is_valid (GOG_SERIES (series)))
+ continue;
+
+ go_data_get_bounds (series->values[1].data, &tmp_min, &tmp_max);
+ if (y_min > tmp_min) y_min = tmp_min;
+ if (y_max < tmp_max) y_max = tmp_max;
+ if (realy->fmt == NULL) {
+ realy->fmt = go_data_preferred_fmt (series->values[1].data);
+ realy->date_conv = go_data_date_conv (series->values[1].data);
+ }
+ go_data_get_bounds (series->values[2].data, &tmp_min, &tmp_max);
+ if (y_min > tmp_min)
+ y_min = tmp_min;
+ if (y_max < tmp_max)
+ y_max = tmp_max;
+
+ if (series->values[0].data != NULL) {
+ go_data_get_bounds (series->values[0].data, &tmp_min, &tmp_max);
+
+ if (!go_finite (tmp_min) || !go_finite (tmp_max) ||
+ tmp_min > tmp_max) {
+ tmp_min = 0;
+ tmp_max = go_data_get_vector_size (series->values[1].data);
+
+ is_discrete = TRUE;
+ } else if (model->x.fmt == NULL) {
+ realx->fmt = go_data_preferred_fmt (series->values[0].data);
+ realy->date_conv = go_data_date_conv (series->values[0].data);
+ }
+ } else {
+ tmp_min = 0;
+ tmp_max = go_data_get_vector_size (series->values[1].data);
+ is_discrete = TRUE;
+ }
+
+ if (x_min > tmp_min)
+ x_min = tmp_min;
+ if (x_max < tmp_max)
+ x_max = tmp_max;
+ }
+ /* make room for bar width, this is approximate since real width is larger */
+ tmp_max = (x_max - x_min) * model->width / 200.;
+ x_min -= tmp_max;
+ x_max += tmp_max;
+ if (realx->minima != x_min || realx->maxima != x_max) {
+ realx->minima = x_min;
+ realx->maxima = x_max;
+ gog_axis_bound_changed (model->base.axis[0], GOG_OBJECT (model));
+ }
+ if (realy->minima != y_min || realy->maxima != y_max) {
+ realy->minima = y_min;
+ realy->maxima = y_max;
+ gog_axis_bound_changed (model->base.axis[1], GOG_OBJECT (model));
+ }
+ gog_object_emit_changed (GOG_OBJECT (obj), FALSE);
+ if (gog_xy_dropbar_parent_klass->update)
+ gog_xy_dropbar_parent_klass->update (obj);
+}
+
+static GOData *
+gog_xy_dropbar_plot_axis_get_bounds (GogPlot *plot, GogAxisType axis,
+ GogPlotBoundInfo *bounds)
+{
+ GogXYDropBarPlot *model = GOG_XY_DROPBAR_PLOT (plot);
+
+ if ((model->horizontal && axis == GOG_AXIS_Y) || (!model->horizontal && axis == GOG_AXIS_X)) {
+ GSList *ptr;
+
+ bounds->val.minima = model->x.minima;
+ bounds->val.maxima = model->x.maxima;
+ bounds->is_discrete = model->x.minima > model->x.maxima ||
+ !go_finite (model->x.minima) ||
+ !go_finite (model->x.maxima);
+ if (bounds->fmt == NULL && model->x.fmt != NULL)
+ bounds->fmt = go_format_ref (model->x.fmt);
+ if (model->x.date_conv)
+ bounds->date_conv = model->x.date_conv;
+
+ for (ptr = plot->series; ptr != NULL ; ptr = ptr->next)
+ if (gog_series_is_valid (GOG_SERIES (ptr->data)))
+ return GOG_SERIES (ptr->data)->values[0].data;
+ return NULL;
+ }
+
+ if ((model->horizontal && axis == GOG_AXIS_X) || (!model->horizontal && axis == GOG_AXIS_Y)) {
+ bounds->val.minima = model->y.minima;
+ bounds->val.maxima = model->y.maxima;
+ if (bounds->fmt == NULL && model->y.fmt != NULL)
+ bounds->fmt = go_format_ref (model->y.fmt);
+ if (model->y.date_conv)
+ bounds->date_conv = model->y.date_conv;
+ }
+ return NULL;
+}
+
+static char const *
+gog_xy_dropbar_plot_type_name (G_GNUC_UNUSED GogObject const *item)
+{
+ /* xgettext : the base for how to name drop bar/col plot objects
+ * eg The 2nd drop bar/col plot in a chart will be called
+ * PlotDropBar2 */
+ return N_("PlotXYDropBar");
+}
+
+static void
+gog_xy_dropbar_plot_class_init (GObjectClass *gobject_klass)
+{
+ GogObjectClass *gog_object_klass = (GogObjectClass *) gobject_klass;
+ GogPlotClass *plot_klass = (GogPlotClass *) gobject_klass;
+ gog_xy_dropbar_parent_klass = g_type_class_peek_parent (gobject_klass);
+
+ gobject_klass->set_property = gog_xy_dropbar_set_property;
+ gobject_klass->get_property = gog_xy_dropbar_get_property;
+ gobject_klass->finalize = gog_xy_dropbar_finalize;
+ g_object_class_install_property (gobject_klass, XY_DROPBAR_PROP_FILL_BEFORE_GRID,
+ g_param_spec_boolean ("before-grid",
+ _("Displayed under the grids"),
+ _("Should the plot be displayed before the grids"),
+ FALSE,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, XY_DROPBAR_PROP_HORIZONTAL,
+ g_param_spec_boolean ("horizontal",
+ _("Horizontal"),
+ _("Whether to use horizontal bars"),
+ FALSE,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, XY_DROPBAR_PROP_WIDTH,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("Bars width as a percetage of the plot width"),
+ 0., 20., 5., /* using arbitrarily 20%. as maximum value */
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+
+ gog_object_klass->type_name = gog_xy_dropbar_plot_type_name;
+ gog_object_klass->update = gog_xy_dropbar_plot_update;
+ gog_object_klass->view_type = gog_xy_dropbar_view_get_type ();
+ gog_object_klass->populate_editor = gog_xy_dropbar_populate_editor;
+
+ {
+ static GogSeriesDimDesc dimensions[] = {
+ { N_("Positions"), GOG_SERIES_SUGGESTED, FALSE,
+ GOG_DIM_INDEX, GOG_MS_DIM_CATEGORIES },
+ { N_("Start"), GOG_SERIES_REQUIRED, FALSE,
+ GOG_DIM_VALUE, GOG_MS_DIM_START },
+ { N_("End"), GOG_SERIES_REQUIRED, FALSE,
+ GOG_DIM_VALUE, GOG_MS_DIM_END },
+ };
+ plot_klass->desc.series.dim = dimensions;
+ plot_klass->desc.series.num_dim = G_N_ELEMENTS (dimensions);
+ plot_klass->desc.series.style_fields = GO_STYLE_LINE | GO_STYLE_FILL;
+ }
+ plot_klass->series_type = gog_xy_dropbar_series_get_type ();
+ plot_klass->axis_set = GOG_AXIS_SET_XY;
+ plot_klass->axis_get_bounds = gog_xy_dropbar_plot_axis_get_bounds;
+}
+
+static void
+gog_xy_dropbar_plot_init (GogXYDropBarPlot *plot)
+{
+ plot->width = 5.;
+}
+
+GSF_DYNAMIC_CLASS (GogXYDropBarPlot, gog_xy_dropbar_plot,
+ gog_xy_dropbar_plot_class_init, gog_xy_dropbar_plot_init,
+ GOG_TYPE_PLOT)
+
+/*****************************************************************************/
+typedef GogPlotView GogXYDropBarView;
+typedef GogPlotViewClass GogXYDropBarViewClass;
+
+/**
+ * FIXME FIXME FIXME Wrong description
+ * barcol_draw_rect :
+ * @rend : #GogRenderer
+ * @flip :
+ * @base : #GogViewAllocation
+ * @rect : #GogViewAllocation
+ *
+ * A utility routine to build a vpath in @rect. @rect is assumed to be in
+ * coordinates relative to @base with 0,0 as the upper left. @flip transposes
+ * @rect and rotates it to put the origin in the bottom left. Play fast and
+ * loose with coordinates to keep widths >= 1. If we allow things to be less
+ * the background bleeds through.
+ **/
+static void
+barcol_draw_rect (GogRenderer *rend, gboolean flip,
+ GogAxisMap *x_map,
+ GogAxisMap *y_map,
+ GogViewAllocation const *rect)
+{
+ GogViewAllocation r;
+ double t;
+
+ if (flip) {
+ r.x = gog_axis_map_to_view (x_map, rect->y);
+ t = gog_axis_map_to_view (x_map, rect->y + rect->h);
+ if (t > r.x)
+ r.w = t - r.x;
+ else {
+ r.w = r.x - t;
+ r.x = t;
+ }
+ r.h = rect->w;
+ r.y = gog_axis_map_to_view (y_map, rect->x) - r.h / 2.;
+ } else {
+ r.w = rect->w;
+ r.x = gog_axis_map_to_view (x_map, rect->x) - r.w / 2.;
+ r.y = gog_axis_map_to_view (y_map, rect->y);
+ t = gog_axis_map_to_view (y_map, rect->y + rect->h);
+ if (t > r.y)
+ r.h = t - r.y;
+ else {
+ r.h = r.y - t;
+ r.y = t;
+ }
+ }
+ if (fabs (r.w) < 1.) {
+ r.w += 1.;
+ r.x -= .5;
+ }
+ if (fabs (r.h) < 1.) {
+ r.h += 1.;
+ r.y -= .5;
+ }
+ gog_renderer_draw_rectangle (rend, &r);
+}
+
+static void
+gog_xy_dropbar_view_render (GogView *view, GogViewAllocation const *bbox)
+{
+ GogXYDropBarPlot const *model = GOG_XY_DROPBAR_PLOT (view->model);
+ GogPlot *plot = GOG_PLOT (model);
+ GogSeries const *series;
+ GogAxisMap *x_map, *y_map, *val_map, *index_map;
+ GogViewAllocation work;
+ double *pos_vals, *start_vals, *end_vals;
+ unsigned i;
+ GSList *ptr;
+ unsigned n, tmp, num_series;
+ GOStyle *neg_style;
+
+ for (num_series = 0, ptr = plot->series ; ptr != NULL ; ptr = ptr->next, num_series++);
+ if (num_series < 1)
+ return;
+
+ x_map = gog_axis_map_new (GOG_PLOT (model)->axis[0],
+ view->allocation.x, view->allocation.w);
+ y_map = gog_axis_map_new (GOG_PLOT (model)->axis[1], view->allocation.y + view->allocation.h,
+ -view->allocation.h);
+
+ if (!(gog_axis_map_is_valid (x_map) &&
+ gog_axis_map_is_valid (y_map))) {
+ gog_axis_map_free (x_map);
+ gog_axis_map_free (y_map);
+ return;
+ }
+
+ work.w = view->allocation.w * model->width / 100.;
+ for (ptr = plot->series ; ptr != NULL ; ptr = ptr->next) {
+ series = ptr->data;
+ if (!gog_series_is_valid (GOG_SERIES (series)))
+ continue;
+ neg_style = go_style_dup ((GOG_STYLED_OBJECT (series))->style);
+ neg_style->line.color ^= 0xffffff00;
+ neg_style->fill.pattern.back ^= 0xffffff00;
+ neg_style->fill.pattern.fore ^= 0xffffff00;
+ pos_vals = go_data_get_values (series->values[0].data);
+ n = go_data_get_vector_size (series->values[1].data);
+ start_vals = go_data_get_values (series->values[1].data);
+ tmp = go_data_get_vector_size (series->values[1].data);
+ if (n > tmp)
+ n = tmp;
+ end_vals = go_data_get_values (series->values[2].data);
+ tmp = go_data_get_vector_size (series->values[2].data);
+ if (n > tmp)
+ n = tmp;
+
+ if (model->horizontal) {
+ index_map = y_map;
+ val_map = x_map;
+ } else {
+ index_map = x_map;
+ val_map = y_map;
+ }
+ for (i = 0; i < n; i++) {
+ work.x = pos_vals[i];
+ work.y = start_vals[i];
+ work.h = end_vals[i] - work.y;
+ if (!gog_axis_map_finite (index_map, work.x) ||
+ !gog_axis_map_finite (val_map, start_vals[i]) ||
+ !gog_axis_map_finite (val_map, end_vals[i]))
+ continue;
+ gog_renderer_push_style (view->renderer, (start_vals[i] <= end_vals[i])?
+ GOG_STYLED_OBJECT (series)->style: neg_style);
+ barcol_draw_rect (view->renderer, model->horizontal, x_map, y_map, &work);
+ gog_renderer_pop_style (view->renderer);
+ }
+ g_object_unref (neg_style);
+ }
+
+ gog_axis_map_free (x_map);
+ gog_axis_map_free (y_map);
+}
+
+static void
+gog_xy_dropbar_view_class_init (GogViewClass *view_klass)
+{
+ view_klass->render = gog_xy_dropbar_view_render;
+ view_klass->clip = TRUE;
+}
+
+GSF_DYNAMIC_CLASS (GogXYDropBarView, gog_xy_dropbar_view,
+ gog_xy_dropbar_view_class_init, NULL,
+ GOG_TYPE_PLOT_VIEW)
+
+
+/*****************************************************************************/
+typedef GogSeries GogXYDropBarSeries;
+typedef GogSeriesClass GogXYDropBarSeriesClass;
+
+static GogObjectClass *series_parent_klass;
+
+static void
+gog_xy_dropbar_series_update (GogObject *obj)
+{
+ const double *x_vals, *y_vals, *z_vals;
+ GogSeries *series = GOG_SERIES (obj);
+ unsigned old_num = series->num_elements;
+
+ series->num_elements = gog_series_get_xyz_data (series,
+ &x_vals, &y_vals, &z_vals);
+ /* queue plot for redraw */
+ gog_object_request_update (GOG_OBJECT (series->plot));
+ if (old_num != series->num_elements)
+ gog_plot_request_cardinality_update (series->plot);
+
+ if (series_parent_klass->update)
+ series_parent_klass->update (obj);
+}
+
+static void
+gog_xy_dropbar_series_class_init (GogObjectClass *gog_klass)
+{
+ series_parent_klass = g_type_class_peek_parent (gog_klass);
+ gog_klass->update = gog_xy_dropbar_series_update;
+}
+
+GSF_DYNAMIC_CLASS (GogXYDropBarSeries, gog_xy_dropbar_series,
+ gog_xy_dropbar_series_class_init, NULL,
+ GOG_TYPE_SERIES)
diff --git a/plugins/plot_xy/gog-xy-dropbar.h b/plugins/plot_xy/gog-xy-dropbar.h
new file mode 100644
index 0000000..07e92d3
--- /dev/null
+++ b/plugins/plot_xy/gog-xy-dropbar.h
@@ -0,0 +1,54 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gog-xy-dropbar.h
+ *
+ * Copyright (C) 2011
+ * Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOG_XY_DROPBAR_H
+#define GOG_XY_DROPBAR_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct {
+ GogPlot base;
+ gboolean horizontal;
+ double width;
+ struct axes_data {
+ double minima, maxima;
+ GOFormat *fmt;
+ GODateConventions const *date_conv;
+ } x, y;
+} GogXYDropBarPlot;
+typedef GogPlotClass GogXYDropBarPlotClass;
+
+#define GOG_TYPE_XY_DROPBAR_PLOT (gog_xy_dropbar_plot_get_type ())
+#define GOG_XY_DROPBAR_PLOT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_TYPE_XY_DROPBAR_PLOT, GogXYDropBarPlot))
+#define GOG_IS_PLOT_XY_DROPBAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_TYPE_XY_DROPBAR_PLOT))
+
+GType gog_xy_dropbar_plot_get_type (void);
+void gog_xy_dropbar_plot_register_type (GTypeModule *module);
+void gog_xy_dropbar_view_register_type (GTypeModule *module);
+void gog_xy_dropbar_series_register_type (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* GOG_XY_DROPBAR_H */
diff --git a/plugins/plot_xy/gog-xy.c b/plugins/plot_xy/gog-xy.c
index fb3c432..14ba28a 100644
--- a/plugins/plot_xy/gog-xy.c
+++ b/plugins/plot_xy/gog-xy.c
@@ -21,6 +21,7 @@
#include <goffice/goffice-config.h>
#include "gog-xy.h"
+#include "gog-xy-dropbar.h"
#include <goffice/graph/gog-view.h>
#include <goffice/graph/gog-renderer.h>
#include <goffice/graph/gog-theme.h>
@@ -2101,6 +2102,9 @@ go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
gog_xy_series_view_register_type (module);
gog_xy_series_register_type (module);
gog_xy_series_element_register_type (module);
+ gog_xy_dropbar_plot_register_type (module);
+ gog_xy_dropbar_view_register_type (module);
+ gog_xy_dropbar_series_register_type (module);
}
G_MODULE_EXPORT void
diff --git a/plugins/plot_xy/plot-types.xml.in b/plugins/plot_xy/plot-types.xml.in
index 25ea7f2..ffa9411 100644
--- a/plugins/plot_xy/plot-types.xml.in
+++ b/plugins/plot_xy/plot-types.xml.in
@@ -3,6 +3,7 @@
<Family _name="XY" sample_image_file="scatter.xpm" axis_set="xy" priority="100"/>
<Family _name="Bubble" sample_image_file="bubble.xpm" axis_set="xy"/>
<Family _name="ColoredXY" sample_image_file="color.xpm" axis_set="xy-color"/>
+ <Family _name="DropBar" sample_image_file="dropbar.xpm" axis_set="xy"/>
<Type _name="XY Points" row="1" col="1"
engine="GogXYPlot" family="XY"
@@ -78,6 +79,24 @@
<property name="default-style-has-lines">FALSE</property>
<property name="guru-hints">backplane</property>
</Type>
+
+ <!-- Drop bars are bars goint from an initial position
+ to a final position; the fill color is inverted when final position is lower
+ than the initial position; they may be used in stock plots. -->
+ <Type _name="Scattered Vertical Drop Bars" row="1" col="3"
+ engine="GogXYDropBarPlot" family="DropBar"
+ _description="Vertical drop bars with continuous X-axis."
+ sample_image_file="chart_dropbar_1_3.png">
+ <property name="horizontal">False</property>
+ <property name="guru-hints">backplane</property>
+ </Type>
+ <Type _name="Scattered Horizontal Drop Bars" row="1" col="4"
+ engine="GogXYDropBarPlot" family="DropBar"
+ _description="Horizontal drop bars with continuous Y-axis."
+ sample_image_file="chart_dropbar_1_4.png">
+ <property name="horizontal">True</property>
+ <property name="guru-hints">backplane</property>
+ </Type>
</Types>
diff --git a/plugins/plot_xy/plugin.xml.in b/plugins/plot_xy/plugin.xml.in
index 70eb444..ab35755 100644
--- a/plugins/plot_xy/plugin.xml.in
+++ b/plugins/plot_xy/plugin.xml.in
@@ -28,5 +28,10 @@
<_description>Stock Scatter plot types</_description>
</information>
</service>
+ <service type="plot_engine" id="GogXYDropBarPlot">
+ <information>
+ <_description>Scattered dropbar plotting engine</_description>
+ </information>
+ </service>
</services>
</plugin>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]