[goffice] Implement color map change in color and contour plots
- From: Jean BrÃfort <jbrefort src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Implement color map change in color and contour plots
- Date: Thu, 1 Nov 2012 14:04:20 +0000 (UTC)
commit 2e10be931a84474e98cb1421fcc2ae0d5acc6554
Author: Jean Brefort <jean brefort normalesup org>
Date: Thu Nov 1 15:03:05 2012 +0100
Implement color map change in color and contour plots
ChangeLog | 22 ++
docs/reference/goffice-0.10-sections.txt | 9 +
docs/reference/goffice-docs.xml | 1 +
goffice/Makefile.am | 1 +
goffice/app/go-doc.c | 43 +++
goffice/app/go-doc.h | 5 +
goffice/app/goffice-app.h | 5 +
goffice/goffice.h | 8 -
goffice/graph/goffice-graph.h | 2 +
goffice/graph/gog-axis-color-map-prefs.ui | 248 ++++++++++++++++++
goffice/graph/gog-axis-color-map.c | 403 ++++++++++++++++++++++++++++-
goffice/graph/gog-axis-color-map.h | 12 +
goffice/graph/gog-axis-prefs.ui | 182 ++++++++------
goffice/graph/gog-axis.c | 135 ++++++++++-
goffice/graph/gog-color-scale.c | 12 +-
goffice/graph/gog-graph.c | 18 +-
goffice/graph/gog-graph.h | 1 +
goffice/graph/gog-object-xml.c | 11 +-
goffice/graph/gog-object.c | 4 +-
goffice/graph/gog-theme.c | 25 ++-
goffice/gtk/go-locale-sel.c | 2 +-
goffice/utils/go-path.c | 2 +-
plugins/plot_surface/gog-contour.c | 16 +-
po/POTFILES.in | 2 +
24 files changed, 1050 insertions(+), 119 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 811b28b..f990b48 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2012-11-01 Jean Brefort <jean brefort normalesup org>
+
+ * goffice/Makefile.am: add new ui file.
+ * file goffice/app/go-doc.c: add support for color maps.
+ * file goffice/app/go-doc.h: ditto.
+ * file goffice/app/goffice-app.h: ditto.
+ * file goffice/goffice.h: ditto.
+ * file goffice/graph/goffice-graph.h: ditto.
+ * goffice/graph/gog-axis-color-map-prefs.ui: new ui file.
+ * goffice/graph/gog-axis-color-map.c: new functions.
+ * goffice/graph/gog-axis-color-map.h: ditto.
+ * goffice/graph/gog-axis-prefs.ui: allow for color map changes.
+ * goffice/graph/gog-axis.c: ditto.
+ * goffice/graph/gog-color-scale.c: minor update.
+ * goffice/graph/gog-graph.c: make sure we can access the GODoc when loading.
+ * goffice/graph/gog-graph.h: ditto.
+ * goffice/graph/gog-object-xml.c: ditto.
+ * goffice/graph/gog-object.c: ditto.
+ * goffice/graph/gog-theme.c: minor update.
+ * plugins/plot_surface/gog-contour.c: interpolate colors when using a color
+ map with less colors than there are levels.
+
2012-10-28 Morten Welinder <terra gnome org>
* goffice/math/go-regression.c (go_regression_stat_destroy): Plug
diff --git a/docs/reference/goffice-0.10-sections.txt b/docs/reference/goffice-0.10-sections.txt
index 02af549..8f53a72 100644
--- a/docs/reference/goffice-0.10-sections.txt
+++ b/docs/reference/goffice-0.10-sections.txt
@@ -843,6 +843,8 @@ go_distribution_get_type
GODoc
go_doc_add_image
go_doc_end_read
+go_doc_foreach_color_map
+go_doc_get_color_map
go_doc_get_dirty_time
go_doc_get_image
go_doc_get_images
@@ -2741,9 +2743,15 @@ gog_axis_base_view_get_type
<FILE>gog-axis-color-map</FILE>
<TITLE>GogAxisColorMap</TITLE>
GogAxisColorMap
+gog_axis_color_map_edit
+GogAxisColorMapHandler
+gog_axis_color_map_foreach
gog_axis_color_map_from_colors
gog_axis_color_map_get_color
+gog_axis_color_map_get_from_name
gog_axis_color_map_get_max
+gog_axis_color_map_get_name
+gog_axis_color_map_get_snapshot
<SUBSECTION Standard>
GOG_AXIS_COLOR_MAP
GOG_IS_AXIS_COLOR_MAP
@@ -2939,6 +2947,7 @@ gog_graph_dup
gog_graph_export_image
gog_graph_force_update
gog_graph_get_data
+gog_graph_get_document
gog_graph_get_size
gog_graph_get_supported_image_formats
gog_graph_get_theme
diff --git a/docs/reference/goffice-docs.xml b/docs/reference/goffice-docs.xml
index 8567871..5d6185b 100644
--- a/docs/reference/goffice-docs.xml
+++ b/docs/reference/goffice-docs.xml
@@ -51,6 +51,7 @@
<xi:include href="xml/gog-theme.xml"/>
<xi:include href="xml/gog-chart-map.xml"/>
<xi:include href="xml/gog-axis-map.xml"/>
+ <xi:include href="xml/gog-axis-color-map.xml"/>
<xi:include href="xml/gog-3d-box.xml"/>
</chapter>
</part>
diff --git a/goffice/Makefile.am b/goffice/Makefile.am
index 6878d91..9c8d744 100644
--- a/goffice/Makefile.am
+++ b/goffice/Makefile.am
@@ -554,6 +554,7 @@ endif
embedded_stuff_compress = \
graph/gog-3d-box-prefs.ui \
graph/gog-axis-prefs.ui \
+ graph/gog-axis-color-map-prefs.ui \
graph/gog-equation-prefs.ui \
graph/gog-error-bar-prefs.ui \
graph/gog-graph-prefs.ui \
diff --git a/goffice/app/go-doc.c b/goffice/app/go-doc.c
index 49040ec..25997fd 100644
--- a/goffice/app/go-doc.c
+++ b/goffice/app/go-doc.c
@@ -33,6 +33,10 @@
struct _GODocPrivate {
GHashTable *imagebuf; /* used when loading/saving images */
+
+ /* color maps */
+ GSList *colormaps; /* document graph axis color maps */
+ GSList *colormapsbuf; /* used when loading/saving color maps */
};
/**
@@ -132,6 +136,7 @@ go_doc_finalize (GObject *obj)
if (doc->images)
g_hash_table_destroy (doc->images);
doc->images = NULL;
+ g_slist_free_full (doc->priv->colormaps, g_object_unref);
g_free (doc->priv);
doc->priv = NULL;
@@ -627,3 +632,41 @@ go_doc_image_fetch (GODoc *doc, char const *id, GType type)
}
return image;
}
+
+/**
+ * go_doc_get_color_map:
+ * @doc: a #GODoc
+ * @name: the color map name to search for
+ *
+ * Retrieves the color map whose name is @name. The difference with
+ * gog_axis_color_map_get_from_name() is that color maps specific to the
+ * document are searched first if any.
+ * Returns: (transfer none): the found color map or %NULL.
+ **/
+GogAxisColorMap const *
+go_doc_get_color_map (GODoc *doc, char const *name)
+{
+ g_return_val_if_fail (GO_IS_DOC (doc) && name && *name, NULL);
+#if 0
+ if (doc->priv->colormaps == NULL)
+ return NULL;
+ return g_hash_table_lookup (doc->priv->colormaps, name);
+#endif
+ return gog_axis_color_map_get_from_name (name);
+}
+
+/**
+ * go_doc_foreach_color_map:
+ * @doc: a #GODoc
+ * @handler: (scope call): a #GogAxisColorMapHandler
+ * @user_data: data to pass to @handler
+ *
+ * Executes @handler to each color map installed on the system or specific to
+ * @doc. This function calls gog_axis_color_map_foreach() but don't execute the
+ * handler if a color map with the same name exists in the document.
+ **/
+void
+go_doc_foreach_color_map (GODoc *doc, GogAxisColorMapHandler handler, gpointer user_data)
+{
+ gog_axis_color_map_foreach (handler, user_data);
+}
diff --git a/goffice/app/go-doc.h b/goffice/app/go-doc.h
index d866fdf..1c1a14b 100644
--- a/goffice/app/go-doc.h
+++ b/goffice/app/go-doc.h
@@ -62,6 +62,11 @@ void go_doc_read (GODoc *doc, GsfXMLIn *xin, xmlChar const **attrs);
void go_doc_end_read (GODoc *doc);
GOImage *go_doc_image_fetch (GODoc *doc, char const *id, GType type);
+GogAxisColorMap const *go_doc_get_color_map (GODoc *doc, char const *name);
+void go_doc_foreach_color_map (GODoc *doc,
+ GogAxisColorMapHandler handler,
+ gpointer user_data);
+
G_END_DECLS
#endif /* GO_DOC_H */
diff --git a/goffice/app/goffice-app.h b/goffice/app/goffice-app.h
index 1ce7b03..5edf2d8 100644
--- a/goffice/app/goffice-app.h
+++ b/goffice/app/goffice-app.h
@@ -61,6 +61,11 @@ G_END_DECLS
#include <goffice/goffice.h>
#include <goffice/utils/goffice-utils.h>
+#include <goffice/graph/goffice-graph.h>
+#include <goffice/canvas/goffice-canvas.h>
+#ifdef GOFFICE_WITH_GTK
+#include <goffice/gtk/goffice-gtk.h>
+#endif
#include <goffice/app/error-info.h>
#include <goffice/app/file.h>
diff --git a/goffice/goffice.h b/goffice/goffice.h
index 6dbfa8b..bf15e1a 100644
--- a/goffice/goffice.h
+++ b/goffice/goffice.h
@@ -56,14 +56,6 @@
#endif
#include <goffice/app/goffice-app.h>
-#include <goffice/utils/goffice-utils.h>
-#include <goffice/data/goffice-data.h>
-#include <goffice/math/goffice-math.h>
-#include <goffice/graph/goffice-graph.h>
-#include <goffice/canvas/goffice-canvas.h>
-#ifdef GOFFICE_WITH_GTK
-#include <goffice/gtk/goffice-gtk.h>
-#endif
G_BEGIN_DECLS
diff --git a/goffice/graph/goffice-graph.h b/goffice/graph/goffice-graph.h
index b550056..ff50a8b 100644
--- a/goffice/graph/goffice-graph.h
+++ b/goffice/graph/goffice-graph.h
@@ -236,6 +236,8 @@ extern int goffice_graph_debug_level;
G_END_DECLS
#include <goffice/goffice.h>
+#include <goffice/data/goffice-data.h>
+#include <goffice/math/goffice-math.h>
#include <goffice/graph/gog-object.h>
#include <goffice/graph/gog-styled-object.h>
diff --git a/goffice/graph/gog-axis-color-map-prefs.ui b/goffice/graph/gog-axis-color-map-prefs.ui
new file mode 100644
index 0000000..fb33bae
--- /dev/null
+++ b/goffice/graph/gog-axis-color-map-prefs.ui
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkAdjustment" id="stop-adj">
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkDialog" id="gog-axis-color-map-prefs">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-close</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label">gtk-save</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><b>Current color stop</b></property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">4</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Value</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Color</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">6</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label" translatable="yes"><b>Snapshots</b></property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="vexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Discrete</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="vexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Gradient</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="stop-btn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ <property name="adjustment">stop-adj</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Name</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">3</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">button2</action-widget>
+ <action-widget response="1">button1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/goffice/graph/gog-axis-color-map.c b/goffice/graph/gog-axis-color-map.c
index 8c2508a..9bf7a86 100644
--- a/goffice/graph/gog-axis-color-map.c
+++ b/goffice/graph/gog-axis-color-map.c
@@ -21,16 +21,32 @@
#include <goffice/goffice-config.h>
#include <goffice/goffice.h>
+#include <goffice/goffice-priv.h>
#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
#ifdef GOFFICE_WITH_GTK
#include <gtk/gtk.h>
#endif
+/**
+ * SECTION: gog-axis-color-map
+ * @short_description: map values to colors.
+ *
+ * Used to map color and pseudo-3d axes values to the actual color. The first
+ * color maps 0 and the last a positive integer returned by
+ * gog_axis_color_map_get_max(). For color axes, these integer values must
+ * themselves be mapped to the minimum and maximum of the axis (unless the
+ * axis is inverted). For pseudo-3d axes, successive colors are obtained for
+ * integer values, cycling to the first color when the colors number is not
+ * large enough.
+ **/
struct _GogAxisColorMap {
GObject base;
- char *name;
+ char *name, *local_name;
+ GHashTable *names;
unsigned size; /* colors number */
unsigned *limits;
GOColor *colors;
@@ -45,10 +61,15 @@ gog_axis_color_map_finalize (GObject *obj)
GogAxisColorMap *map = GOG_AXIS_COLOR_MAP (obj);
g_free (map->name);
map->name = NULL;
+ g_free (map->local_name);
+ map->local_name = NULL;
g_free (map->limits);
map->limits = NULL;
g_free (map->colors);
map->colors = NULL;
+ if (map->names)
+ g_hash_table_destroy (map->names);
+ map->names = NULL;
parent_klass->finalize (obj);
}
@@ -69,6 +90,14 @@ GSF_CLASS (GogAxisColorMap, gog_axis_color_map,
gog_axis_color_map_class_init, gog_axis_color_map_init,
G_TYPE_OBJECT)
+/**
+ * gog_axis_color_map_get_color:
+ * @map: a #GogAxisMap
+ * @x: the value to map
+ *
+ * Maps @x to a color.
+ * Returns: the found color.
+ **/
GOColor
gog_axis_color_map_get_color (GogAxisColorMap const *map, double x)
{
@@ -80,13 +109,21 @@ gog_axis_color_map_get_color (GogAxisColorMap const *map, double x)
if (map->size == 1)
return map->colors[0];
if (x > map->limits[map->size-1])
- x -= floor (x / map->limits[map->size-1]) * map->limits[map->size-1];
- while (n < map->size && x > map->limits[n])
+ x -= floor (x / (map->limits[map->size-1] + 1)) * (map->limits[map->size-1] + 1);
+ while (n < map->size && x > map->limits[n] + 1e-10)
n++;
t = (x - map->limits[n-1]) / (map->limits[n] - map->limits[n-1]);
return GO_COLOR_INTERPOLATE (map->colors[n-1], map->colors[n], t);
}
+/**
+ * gog_axis_color_map_get_max:
+ * @map: a #GogAxisMap
+ *
+ * Retrieves the value corresponding to the last color in the map. The first
+ * always corresponds to 0.
+ * Returns: the maximum value.
+ **/
unsigned
gog_axis_color_map_get_max (GogAxisColorMap const *map)
{
@@ -95,6 +132,125 @@ gog_axis_color_map_get_max (GogAxisColorMap const *map)
}
/**
+ * gog_axis_color_map_get_snapshot:
+ * @map: a #GogAxisMap
+ *
+ * Retrieves the color map name.
+ * Returns: (transfer none): the map name.
+ **/
+char const *
+gog_axis_color_map_get_name (GogAxisColorMap const *map)
+{
+ g_return_val_if_fail (GOG_IS_AXIS_COLOR_MAP (map), NULL);
+ return map->name;
+}
+
+/**
+ * gog_axis_color_map_get_snapshot:
+ * @map: a #GogAxisMap
+ * @discrete: whether to use constant colors between each stop or a gradient.
+ * @horizontal: whether to get an horizontal or a vertical snapshot.
+ * @width: the pixbuf width.
+ * @height: the pixbuf height.
+ *
+ * Builds a snapshot of the color map.
+ * Returns: (transfer full): the new #GdkPixbuf.
+ **/
+GdkPixbuf *
+gog_axis_color_map_get_snapshot (GogAxisColorMap const *map,
+ gboolean discrete, gboolean horizontal,
+ unsigned width, unsigned height)
+{
+ cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+ cairo_t *cr = cairo_create (surface);
+ unsigned i, max = gog_axis_color_map_get_max (map);
+
+ g_return_val_if_fail (GOG_IS_AXIS_COLOR_MAP (map), NULL);
+ if (discrete) {
+ GOColor color;
+ unsigned t0 = 0, t1, maxt = horizontal? width: height;
+ max++;
+ for (i = 0; i < max; i++) {
+ t1 = (i + 1) * maxt / max;
+ color = gog_axis_color_map_get_color (map, i);
+ if (horizontal)
+ cairo_rectangle (cr, t0, 0., t1, height);
+ else
+ cairo_rectangle (cr, 0., t0, width, t1);
+ cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (color));
+ cairo_fill (cr);
+ t0 = t1;
+ }
+ } else {
+ double x1, y1;
+ cairo_pattern_t *pattern;
+ if (horizontal) {
+ x1 = width;
+ y1 = 0.;
+ } else {
+ x1 = 0.;
+ y1 = height;
+ }
+ pattern = cairo_pattern_create_linear (0., 0., x1, y1);
+ for (i = 0; i < map->size; i++) {
+ cairo_pattern_add_color_stop_rgba (pattern,
+ (double) map->limits[i] / (double) max,
+ GO_COLOR_TO_CAIRO (map->colors[i]));
+ }
+ cairo_rectangle (cr, 0., 0., width, height);
+ cairo_set_source (cr, pattern);
+ cairo_fill (cr);
+ cairo_pattern_destroy (pattern);
+ }
+
+ go_cairo_convert_data_to_pixbuf (gdk_pixbuf_get_pixels (pixbuf),
+ cairo_image_surface_get_data (surface),
+ width, height, width * 4);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ return pixbuf;
+}
+
+#ifdef GOFFICE_WITH_GTK
+/**
+ * gog_axis_color_map_edit:
+ * @map: a #GogAxisColorMap or %NULL
+ * @cc: a #GOCmdContext
+ *
+ * Opens a dialog to edit the color map. If @map is %NULL, creates a new one
+ * unless the user cancels the edition.
+ * Returns: (transfer none): the edited color map.
+ **/
+GogAxisColorMap *
+gog_axis_color_map_edit (GogAxisColorMap *map, GOCmdContext *cc)
+{
+ GtkBuilder *gui = go_gtk_builder_load_internal ("res:go:graph/gog-axis-color-map-prefs.ui", GETTEXT_PACKAGE, cc);
+ GtkWidget *top_level = go_gtk_builder_get_widget (gui, "gog-axis-color-map-prefs");
+ unsigned response;
+ gboolean created = FALSE;
+
+ if (map == NULL) {
+ GOColor color = GO_COLOR_BLUE;
+ map = gog_axis_color_map_from_colors ("New map", 1, &color);
+ created = TRUE;
+ } else {
+ }
+
+ response = gtk_dialog_run (GTK_DIALOG (top_level));
+ if (response == 1) {
+ } else {
+ if (created)
+ g_object_unref (map);
+ map = NULL;
+ }
+ gtk_widget_destroy (top_level);
+ g_object_unref (gui);
+ return map;
+}
+#endif
+
+/**
* gog_axis_color_map_from_colors:
* @name: color map name
* @nb: colors number
@@ -127,12 +283,241 @@ _gog_axis_color_map_get_default ()
return color_map;
}
+static GSList *color_maps;
+
+/**
+ * gog_axis_color_map_registry_add:
+ * @map: a #GogAxisColorMap
+ *
+ * Keep a pointer to @map in graph color maps registry.
+ * This function does not add a reference to @map.
+ **/
+static void
+gog_axis_color_map_registry_add (GogAxisColorMap *map)
+{
+ g_return_if_fail (GOG_IS_AXIS_COLOR_MAP (map));
+
+ /* TODO: Check for duplicated names and for already
+ * registered map */
+
+ color_maps = g_slist_append (color_maps, map);
+}
+
+struct _color_stop {
+ unsigned bin;
+ GOColor color;
+};
+
+struct color_map_load_state {
+ GogAxisColorMap *map;
+ char *lang, *local_name;
+ unsigned name_lang_score;
+ char const * const *langs;
+ GSList *color_stops;
+};
+
+static void
+color_stop_start (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ struct color_map_load_state *state = (struct color_map_load_state *) xin->user_state;
+ GOColor color;
+ unsigned bin = 0;
+ char *end;
+ gboolean color_found = FALSE;
+ gboolean bin_found = FALSE;
+
+ for (; attrs != NULL && *attrs ; attrs += 2)
+ if (0 == strcmp (*attrs, "bin")) {
+ bin = strtoul (attrs[1], &end, 10);
+ if (*end == 0)
+ bin_found = TRUE;
+ } else if (0 == strcmp (*attrs, "color"))
+ color_found = go_color_from_str (attrs[1], &color);
+ if (color_found && bin_found) {
+ struct _color_stop* stop = g_new (struct _color_stop, 1);
+ stop->bin = bin;
+ stop->color = color;
+ state->color_stops = g_slist_append (state->color_stops, stop);
+ } else
+ g_warning ("[GogAxisColorMap]: Invalid color stop");
+
+}
+
+static void
+name_start (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ struct color_map_load_state *state = (struct color_map_load_state *) xin->user_state;
+ unsigned i;
+ for (i = 0; attrs != NULL && attrs[i] && attrs[i+1] ; i += 2)
+ if (0 == strcmp (attrs[i], "xml:lang"))
+ state->lang = g_strdup (attrs[i+1]);
+}
+
+static void
+name_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ struct color_map_load_state *state = (struct color_map_load_state *) xin->user_state;
+ char *name = NULL;
+ if (xin->content->str == NULL)
+ return;
+ name = g_strdup (xin->content->str);
+ if (state->map == NULL) {
+ state->map = g_object_new (GOG_TYPE_AXIS_COLOR_MAP, NULL);
+ state->map->names = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+ }
+ if (state->lang == NULL) {
+ state->map->name = name;
+ } else {
+ if (state->name_lang_score > 0 && state->langs[0] != NULL) {
+ unsigned i;
+ for (i = 0; i < state->name_lang_score && state->langs[i] != NULL; i++) {
+ if (strcmp (state->langs[i], state->lang) == 0) {
+ g_free (state->local_name);
+ state->local_name = g_strdup (name);
+ state->name_lang_score = i;
+ }
+ }
+ }
+ g_hash_table_replace (state->map->names, state->lang, name);
+ state->lang = NULL;
+ }
+}
+
+static int
+color_stops_cmp (struct _color_stop *first, struct _color_stop *second)
+{
+ return (first->bin < second->bin)? -1: (int) (first->bin - second->bin);
+}
+
+static void
+color_map_load_from_uri (char const *uri)
+{
+ static GsfXMLInNode const color_map_dtd[] = {
+ GSF_XML_IN_NODE (THEME, THEME, -1, "GogAxisColorMap", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (THEME, NAME, -1, "name", GSF_XML_CONTENT, name_start, name_end),
+ GSF_XML_IN_NODE (THEME, UNAME, -1, "_name", GSF_XML_CONTENT, name_start, name_end),
+ GSF_XML_IN_NODE (THEME, STOP, -1, "color-stop", GSF_XML_CONTENT, color_stop_start, NULL),
+ GSF_XML_IN_NODE_END
+ };
+ struct color_map_load_state state;
+ GsfXMLInDoc *xml;
+ GsfInput *input = go_file_open (uri, NULL);
+
+ if (input == NULL) {
+ g_warning ("[GogAxisColorMap]: Could not open %s", uri);
+ return;
+ }
+ state.map = NULL;
+ state.lang = state.local_name = NULL;
+ state.langs = g_get_language_names ();
+ state.name_lang_score = G_MAXINT;
+ state.color_stops = NULL;
+ xml = gsf_xml_in_doc_new (color_map_dtd, NULL);
+ if (!gsf_xml_in_doc_parse (xml, input, &state))
+ g_warning ("[GogAxisColorMap]: Could not parse %s", uri);
+ if (state.map != NULL) {
+ GSList *ptr;
+ state.map->local_name = state.local_name;
+ /* populates the colors */
+ /* first sort the color list according to bins */
+ ptr = state.color_stops = g_slist_sort (state.color_stops, (GCompareFunc) color_stops_cmp);
+ if (((struct _color_stop *) ptr->data)->bin != 0) {
+ g_warning ("[GogAxisColorMap]: Invalid color map in %s", uri);
+ g_object_unref (state.map);
+ } else {
+ unsigned cur_bin, n = 0;
+ state.map->size = g_slist_length (state.color_stops);
+ state.map->limits = g_new (unsigned, state.map->size);
+ state.map->colors = g_new (GOColor, state.map->size);
+ while (ptr) {
+ cur_bin = state.map->limits[n] = ((struct _color_stop *) ptr->data)->bin;
+ state.map->colors[n++] = ((struct _color_stop *) ptr->data)->color;
+ do (ptr = ptr->next);
+ while (ptr && ((struct _color_stop *) ptr->data)->bin == cur_bin);
+ }
+ state.map->size = n; /* we drop duplicate bins */
+ gog_axis_color_map_registry_add (state.map);
+ }
+ } else
+ g_free (state.local_name);
+ g_slist_free_full (state.color_stops, g_free);
+ g_free (state.lang);
+ gsf_xml_in_doc_free (xml);
+ g_object_unref (input);
+}
+
+static void
+color_maps_load_from_dir (char const *path)
+{
+ GDir *dir = g_dir_open (path, 0, NULL);
+ char const *d_name;
+
+ if (dir == NULL)
+ return;
+ while ((d_name = g_dir_read_name (dir)) != NULL) {
+ char *fullname = g_build_filename (path, d_name, NULL);
+ char *uri = go_filename_to_uri (fullname);
+ char *mime_type = go_get_mime_type (uri);
+ if (!strcmp (mime_type, "application/xml")) /* we don't have a better one */
+ color_map_load_from_uri (uri);
+ g_free (mime_type);
+ g_free (uri);
+ g_free (fullname);
+ }
+ g_dir_close (dir);
+}
+
+/**
+ * GogAxisColorMapHandler:
+ * @map: a #GogAxisColorMap
+ * @user_data: user data
+ *
+ * Type of the callback to pass to gog_axis_color_map_foreach() and
+ * go_doc_foreach_color_map() to iterate through color maps.
+ **/
+
+/**
+ * gog_axis_color_map_foreach:
+ * @handler: (scope call): a #GogAxisColorMapHandler
+ * @user_data: data to pass to @handler
+ *
+ * Executes @handler to each color map installed on the system. This function
+ * should not be called directly, call go_doc_foreach_color_map() instead.
+ **/
+void
+gog_axis_color_map_foreach (GogAxisColorMapHandler handler, gpointer user_data)
+{
+ GSList *ptr;
+ for (ptr = color_maps; ptr; ptr = ptr->next)
+ handler ((GogAxisColorMap *) (ptr->data), user_data);
+}
+
+/**
+ * gog_axis_color_map_get_from_name:
+ * @name: the color map name to search for
+ *
+ * Retrieves the color map whose name is @name.
+ * Returns: (transfer none): the found color map or %NULL.
+ **/
+GogAxisColorMap const *
+gog_axis_color_map_get_from_name (char const *name)
+{
+ GSList *ptr;
+ for (ptr = color_maps; ptr; ptr = ptr->next)
+ if (!strcmp (((GogAxisColorMap *) (ptr->data))->name, name))
+ return (GogAxisColorMap *) ptr->data;
+ return NULL;
+}
+
void
_gog_axis_color_maps_init (void)
{
+ char *path;
+
/* Default color map */
color_map = g_object_new (GOG_TYPE_AXIS_COLOR_MAP, NULL);
- color_map->name = g_strdup ("Default");
+ color_map->name = g_strdup (N_("Default"));
color_map->size = 5;
color_map->limits = g_new (unsigned, 5);
color_map->colors = g_new (GOColor, 5);
@@ -146,10 +531,20 @@ _gog_axis_color_maps_init (void)
color_map->colors[3] = GO_COLOR_YELLOW;
color_map->limits[4] = 6;
color_map->colors[4] = GO_COLOR_RED;
+
+ /* Now load registered color maps */
+ path = g_build_filename (go_sys_data_dir (), "colormaps", NULL);
+ color_maps_load_from_dir (path);
+ g_free (path);
+
+ path = g_build_filename (g_get_home_dir (), ".goffice", "colormaps", NULL);
+ color_maps_load_from_dir (path);
+ g_free (path);
}
void
_gog_axis_color_maps_shutdown (void)
{
g_object_unref (color_map);
+ g_slist_free_full (color_maps, g_object_unref);
}
diff --git a/goffice/graph/gog-axis-color-map.h b/goffice/graph/gog-axis-color-map.h
index 8607367..093f4eb 100644
--- a/goffice/graph/gog-axis-color-map.h
+++ b/goffice/graph/gog-axis-color-map.h
@@ -35,6 +35,18 @@ GType gog_axis_color_map_get_type (void);
GOColor gog_axis_color_map_get_color (GogAxisColorMap const *map, double x);
unsigned gog_axis_color_map_get_max (GogAxisColorMap const *map);
GogAxisColorMap *gog_axis_color_map_from_colors (char const *name, unsigned nb, GOColor const *colors);
+GdkPixbuf *gog_axis_color_map_get_snapshot (GogAxisColorMap const *map,
+ gboolean discrete,
+ gboolean horizontal,
+ unsigned width,
+ unsigned height);
+char const *gog_axis_color_map_get_name (GogAxisColorMap const *map);
+#ifdef GOFFICE_WITH_GTK
+GogAxisColorMap *gog_axis_color_map_edit (GogAxisColorMap *map, GOCmdContext *cc);
+#endif
+typedef void (*GogAxisColorMapHandler) (GogAxisColorMap const *map, gpointer user_data);
+void gog_axis_color_map_foreach (GogAxisColorMapHandler handler, gpointer user_data);
+GogAxisColorMap const *gog_axis_color_map_get_from_name (char const *name);
/* private */
diff --git a/goffice/graph/gog-axis-prefs.ui b/goffice/graph/gog-axis-prefs.ui
index f0f48e2..95513f0 100644
--- a/goffice/graph/gog-axis-prefs.ui
+++ b/goffice/graph/gog-axis-prefs.ui
@@ -301,24 +301,6 @@
<property name="height">1</property>
</packing>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
<property name="left_attach">0</property>
@@ -377,24 +359,6 @@
<property name="height">1</property>
</packing>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
<property name="left_attach">0</property>
@@ -403,24 +367,6 @@
<property name="height">1</property>
</packing>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
<property name="left_attach">0</property>
@@ -501,12 +447,6 @@
<child>
<placeholder/>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
<object class="GtkGrid" id="axis-pref-grid">
<property name="visible">True</property>
@@ -691,15 +631,6 @@
<child>
<placeholder/>
</child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
<property name="left_attach">0</property>
@@ -732,17 +663,118 @@
<property name="height">1</property>
</packing>
</child>
+ </object>
+ <object class="GtkListStore" id="color-map-list">
+ <columns>
+ <!-- column-name Name -->
+ <column type="gchararray"/>
+ <!-- column-name Snapshot -->
+ <column type="GdkPixbuf"/>
+ <!-- column-name Map -->
+ <column type="GObject"/>
+ </columns>
+ </object>
+ <object class="GtkGrid" id="color-map-grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
<child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
+ <object class="GtkComboBox" id="color-map-combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="model">color-map-list</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ <property name="height">1</property>
+ </packing>
</child>
<child>
- <placeholder/>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
</child>
<child>
- <placeholder/>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="new-btn">
+ <property name="label" translatable="yes">New</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Creates a new color map from scratch</property>
+ <property name="tooltip_text" translatable="yes">Creates a new color map from scratch</property>
+ <property name="use_action_appearance">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="duplicate-btn">
+ <property name="label" translatable="yes">Duplicate</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Creates a new color map based on the currently selected one.</property>
+ <property name="tooltip_text" translatable="yes">Creates a new color map based on the currently selected one.</property>
+ <property name="use_action_appearance">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="edit-btn">
+ <property name="label" translatable="yes">Edit</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Edits the color map.</property>
+ <property name="tooltip_text" translatable="yes">Edits the color map.</property>
+ <property name="use_action_appearance">False</property>
+ <property name="image_position">right</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
</child>
<child>
<placeholder/>
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index f90d928..c488c7e 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -2054,7 +2054,8 @@ enum {
AXIS_PROP_CIRCULAR_ROTATION,
AXIS_PROP_POLAR_UNIT,
AXIS_PROP_SPAN_START,
- AXIS_PROP_SPAN_END
+ AXIS_PROP_SPAN_END,
+ AXIS_PROP_COLOR_MAP
};
/*****************************************************************************/
@@ -2262,6 +2263,24 @@ gog_axis_set_property (GObject *obj, guint param_id,
axis->span_end = new_value;
}
break;
+ case AXIS_PROP_COLOR_MAP: {
+ char const *str = g_value_get_string (value);
+ GogAxisColorMap const *map = NULL;
+ if (strcmp (str, "default")) {
+ map = go_doc_get_color_map (gog_graph_get_document (gog_object_get_graph (GOG_OBJECT (axis))), str);
+ if (!map) {
+ /* might be the continuous theme color map */
+ map = gog_theme_get_color_map (gog_graph_get_theme (gog_object_get_graph (GOG_OBJECT (axis))), FALSE);
+ if (strcmp (gog_axis_color_map_get_name (map), str))
+ map = NULL;
+ }
+ }
+ if (map) {
+ axis->color_map = map;
+ axis->auto_color_map = FALSE;
+ }
+ break;
+ }
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
return; /* NOTE : RETURN */
@@ -2311,6 +2330,9 @@ gog_axis_get_property (GObject *obj, guint param_id,
case AXIS_PROP_SPAN_END:
g_value_set_double (value, axis->span_end);
break;
+ case AXIS_PROP_COLOR_MAP:
+ g_value_set_string (value, (axis->auto_color_map)? "default": gog_axis_color_map_get_name (axis->color_map));
+ break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
break;
@@ -2470,6 +2492,8 @@ gog_axis_update (GogObject *obj)
typedef struct {
GogAxis *axis;
GtkWidget *format_selector;
+ GtkComboBox *color_map_combo;
+ GOCmdContext *cc;
} GogAxisPrefState;
static void
@@ -2667,6 +2691,48 @@ cb_end_changed (GtkSpinButton *spin, GogAxis *axis)
}
static void
+color_map_new_cb (GogAxisPrefState *state)
+{
+ GogAxisColorMap *map = gog_axis_color_map_edit (NULL, state->cc);
+ if (map) {
+ }
+}
+
+static void
+color_map_changed_cb (GtkComboBox *combo, GogAxis *axis)
+{
+ GtkTreeModel *model = gtk_combo_box_get_model (combo);
+ GtkTreeIter iter;
+ GogAxisColorMap *map;
+ GogTheme *theme = gog_graph_get_theme (gog_object_get_graph (GOG_OBJECT (axis)));
+ gtk_combo_box_get_active_iter (combo, &iter);
+ gtk_tree_model_get (model, &iter, 2, &map, -1);
+ axis->color_map = map;
+ axis->auto_color_map = map == gog_theme_get_color_map (theme, axis->type == GOG_AXIS_PSEUDO_3D);
+ gog_object_emit_changed (GOG_OBJECT (axis), FALSE);
+}
+
+struct ColorMapState {
+ GtkComboBox *combo;
+ GtkListStore *model;
+ GogAxisColorMap const *target;
+ gboolean discrete;
+};
+
+static void
+add_color_map_cb (GogAxisColorMap const *map, struct ColorMapState *state)
+{
+ GtkTreeIter iter;
+ GdkPixbuf *pixbuf = gog_axis_color_map_get_snapshot (map, state->discrete,
+ TRUE, 200, 16);
+ gtk_list_store_append (state->model, &iter);
+ gtk_list_store_set (state->model, &iter, 0, gog_axis_color_map_get_name (map),
+ 1, pixbuf, 2, map, -1);
+ if (map == state->target)
+ gtk_combo_box_set_active_iter (state->combo, &iter);
+}
+
+static void
gog_axis_populate_editor (GogObject *gobj,
GOEditor *editor,
GogDataAllocator *dalloc,
@@ -2683,13 +2749,13 @@ gog_axis_populate_editor (GogObject *gobj,
GogAxisPrefState *state;
GogDataset *set = GOG_DATASET (gobj);
GtkBuilder *gui;
-
gui = go_gtk_builder_load_internal ("res:go:graph/gog-axis-prefs.ui", GETTEXT_PACKAGE, cc);
if (gui == NULL)
return;
state = g_new0 (GogAxisPrefState, 1);
state->axis = axis;
+ state->cc = cc;
g_object_ref (G_OBJECT (axis));
/* Bounds Page */
@@ -2790,6 +2856,65 @@ gog_axis_populate_editor (GogObject *gobj,
_("Span"));
}
+ /* color map */
+ if (axis->type == GOG_AXIS_COLOR || axis->type == GOG_AXIS_PSEUDO_3D) {
+ GtkListStore *model = GTK_LIST_STORE (gtk_builder_get_object (gui, "color-map-list"));
+ GtkTreeIter iter;
+ GdkPixbuf *pixbuf;
+ GogAxisColorMap const *map;
+ GogTheme *theme = gog_graph_get_theme (gog_object_get_graph (GOG_OBJECT (axis)));
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+ GtkWidget *combo = go_gtk_builder_get_widget (gui, "color-map-combo");
+ struct ColorMapState color_state;
+ state->color_map_combo = GTK_COMBO_BOX (combo);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
+ "text", 0, NULL);
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
+ "pixbuf", 1, NULL);
+
+ if (axis->type == GOG_AXIS_PSEUDO_3D) {
+ gtk_list_store_append (model, &iter);
+ map = gog_theme_get_color_map (theme, TRUE);
+ pixbuf = gog_axis_color_map_get_snapshot (map, TRUE,
+ TRUE, 200, 16);
+ gtk_list_store_set (model, &iter, 0, gog_axis_color_map_get_name (map),
+ 1, pixbuf, 2, map, -1);
+ g_object_unref (pixbuf);
+ if (map == axis->color_map)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+ }
+ gtk_list_store_append (model, &iter);
+ map = gog_theme_get_color_map (theme, FALSE);
+ pixbuf = gog_axis_color_map_get_snapshot (map, FALSE,
+ TRUE, 200, 16);
+ gtk_list_store_set (model, &iter, 0, gog_axis_color_map_get_name (map),
+ 1, pixbuf, 2, map, -1);
+ g_object_unref (pixbuf);
+ if (map == axis->color_map)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+ /* add all locally defined maps */
+ color_state.combo = GTK_COMBO_BOX (combo);
+ color_state.model = model;
+ color_state.target = axis->color_map;
+ color_state.discrete = axis->type == GOG_AXIS_PSEUDO_3D;
+ gog_axis_color_map_foreach ((GogAxisColorMapHandler) add_color_map_cb, &color_state);
+ /* add document maps if any */
+ /* TODO */
+ g_signal_connect (combo, "changed", G_CALLBACK (color_map_changed_cb), axis);
+ w = go_gtk_builder_get_widget (gui, "new-btn");
+ g_signal_connect_swapped (w, "clicked", G_CALLBACK (color_map_new_cb), combo);
+ gtk_widget_hide (w);
+ w = go_gtk_builder_get_widget (gui, "duplicate-btn");
+ gtk_widget_hide (w);
+ w = go_gtk_builder_get_widget (gui, "edit-btn");
+ gtk_widget_hide (w);
+ go_editor_add_page (editor,
+ go_gtk_builder_get_widget (gui, "color-map-grid"),
+ _("Colors"));
+ }
if (gog_object_is_visible (axis) && gog_axis_get_atype (axis) < GOG_AXIS_VIRTUAL) {
/* Style page */
@@ -2912,6 +3037,11 @@ gog_axis_class_init (GObjectClass *gobject_klass)
_("Position of the plot area at which the axis effective area ends, expressed as a percentage of the available position. Defaults to 1.0"),
0., 1., 1.,
GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+ g_object_class_install_property (gobject_klass, AXIS_PROP_COLOR_MAP,
+ g_param_spec_string ("color-map-name", _("ColorMapName"),
+ _("The name of the color map"),
+ "default",
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
gog_object_register_roles (gog_klass, roles, G_N_ELEMENTS (roles));
@@ -3349,7 +3479,6 @@ gog_axis_get_color_map (GogAxis *axis)
g_return_val_if_fail (GOG_IS_AXIS (axis), NULL);
return axis->color_map;
-
}
/****************************************************************************/
diff --git a/goffice/graph/gog-color-scale.c b/goffice/graph/gog-color-scale.c
index a4dfd03..b1f24ed 100644
--- a/goffice/graph/gog-color-scale.c
+++ b/goffice/graph/gog-color-scale.c
@@ -29,12 +29,22 @@
#include <gtk/gtk.h>
#endif
+/**
+ * SECTION: gog-color-scale
+ * @short_description: Displays the color scale used by an axis.
+ *
+ * A color scale has two parts: an axis, and a rectangle filled by the colors
+ * corresponding to the axis scale. It can be displayed horizontally or
+ * vertically.
+ **/
struct _GogColorScale {
GogStyledObject base;
GogAxis *color_axis; /* the color or pseudo-3d axis */
GogAxis *axis; /* the axis used to display the scale */
gboolean horizontal;
- double width; /* will actually be height if horizontal */
+ gboolean axis_at_low; /* axis position on low coordinates side */
+ double width; /* will actually be height of the colored rectangle if
+ * horizontal */
};
typedef GogStyledObjectClass GogColorScaleClass;
diff --git a/goffice/graph/gog-graph.c b/goffice/graph/gog-graph.c
index 4f21ac9..c723e67 100644
--- a/goffice/graph/gog-graph.c
+++ b/goffice/graph/gog-graph.c
@@ -630,9 +630,7 @@ gog_graph_num_rows (GogGraph const *graph)
GogGraph *
gog_graph_dup (GogGraph const *graph)
{
- GogObject *res = gog_object_dup (GOG_OBJECT (graph), NULL, NULL);
- GOG_GRAPH (res)->doc = graph->doc;
- return GOG_GRAPH (res);
+ return GOG_GRAPH (gog_object_dup (GOG_OBJECT (graph), NULL, NULL));
}
/**
@@ -1289,3 +1287,17 @@ void gog_graph_render_to_cairo (GogGraph *graph, cairo_t *cairo, double w, doubl
gog_renderer_render_to_cairo (renderer, cairo, w, h);
g_object_unref (renderer);
}
+
+/**
+ * gog_graph_get_document:
+ * @graph: a #GogGraph
+ *
+ * Retrieves the #GODoc for @graph.
+ * Returns: (transfer none): the document.
+ **/
+GODoc *
+gog_graph_get_document (GogGraph *graph)
+{
+ g_return_val_if_fail (GOG_IS_GRAPH (graph), NULL);
+ return graph->doc;
+}
diff --git a/goffice/graph/gog-graph.h b/goffice/graph/gog-graph.h
index 7714f0e..a4ba6c2 100644
--- a/goffice/graph/gog-graph.h
+++ b/goffice/graph/gog-graph.h
@@ -73,6 +73,7 @@ void gog_graph_view_handle_event (GogGraphView *gview, GdkEvent *event, doub
#endif
void gog_graph_render_to_cairo (GogGraph *graph, cairo_t *cairo, double w, double h);
+GODoc *gog_graph_get_document (GogGraph *graph);
G_END_DECLS
diff --git a/goffice/graph/gog-object-xml.c b/goffice/graph/gog-object-xml.c
index 9a7edbd..78665b2 100644
--- a/goffice/graph/gog-object-xml.c
+++ b/goffice/graph/gog-object-xml.c
@@ -20,14 +20,7 @@
*/
#include <goffice/goffice-config.h>
-#include <goffice/graph/gog-object-xml.h>
-#include <goffice/graph/gog-object.h>
-#include <goffice/graph/gog-plot.h>
-#include <goffice/graph/gog-trend-line.h>
-#include <goffice/graph/gog-data-set.h>
-#include <goffice/data/go-data.h>
-#include <goffice/utils/go-color.h>
-#include <goffice/utils/go-persist.h>
+#include <goffice/goffice.h>
#include <string.h>
#include <stdlib.h>
@@ -449,6 +442,8 @@ gogo_start (GsfXMLIn *xin, xmlChar const **attrs)
if (res == NULL) {
g_warning ("unknown type '%s'", type);
}
+ if (GOG_IS_GRAPH (res))
+ ((GogGraph *) res)->doc = (GODoc *) g_object_get_data (G_OBJECT (gsf_xml_in_get_input (xin)), "document");
} else
res = NULL;
diff --git a/goffice/graph/gog-object.c b/goffice/graph/gog-object.c
index f80d53b..df7dd31 100644
--- a/goffice/graph/gog-object.c
+++ b/goffice/graph/gog-object.c
@@ -1090,7 +1090,9 @@ gog_object_dup (GogObject const *src, GogObject *new_parent, GogDataDuplicator d
else
dataset_dup (GOG_DATASET (src), GOG_DATASET (dst));
}
- if (GOG_IS_CHART (src))
+ if (GOG_IS_GRAPH (src))
+ GOG_GRAPH (dst)->doc = GOG_GRAPH (src)->doc;
+ else if (GOG_IS_CHART (src))
GOG_CHART (dst)->axis_set = GOG_CHART (src)->axis_set;
for (ptr = src->children; ptr != NULL ; ptr = ptr->next)
diff --git a/goffice/graph/gog-theme.c b/goffice/graph/gog-theme.c
index 7f64ebb..e5996c8 100644
--- a/goffice/graph/gog-theme.c
+++ b/goffice/graph/gog-theme.c
@@ -241,6 +241,8 @@ gog_theme_finalize (GObject *obj)
g_object_unref (g_ptr_array_index (theme->palette, i));
g_ptr_array_free (theme->palette, TRUE);
}
+ if (theme->cm)
+ g_object_unref (theme->cm);
if (theme->dcm)
g_object_unref (theme->dcm);
@@ -846,7 +848,7 @@ build_predefined_themes (void)
NULL, "GogEquation", NULL);
#endif
/* builds the default discrete color map */
- theme->dcm = gog_axis_color_map_from_colors ("Default discrete",
+ theme->dcm = gog_axis_color_map_from_colors (N_("Theme"),
G_N_ELEMENTS (default_palette),
default_palette);
@@ -995,7 +997,7 @@ build_predefined_themes (void)
NULL, "GogEquation", NULL);
#endif
- theme->dcm = gog_axis_color_map_from_colors ("Default discrete",
+ theme->dcm = gog_axis_color_map_from_colors (N_("Theme"),
G_N_ELEMENTS (guppi_palette),
guppi_palette);
}
@@ -1029,6 +1031,7 @@ name_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
if (state->lang == NULL) {
GOStyle *style;
state->theme = gog_theme_new (name);
+ name = NULL;
state->theme->palette = g_ptr_array_new ();
/* initialize a dummy GogSeries style */
style = go_style_new ();
@@ -1043,11 +1046,13 @@ name_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
for (i = 0; i < state->name_lang_score && state->langs[i] != NULL; i++) {
if (strcmp (state->langs[i], state->lang) == 0) {
g_free (state->local_name);
- state->local_name = g_strdup (name);
+ state->local_name = name;
+ name = NULL;
state->name_lang_score = i;
}
}
}
+ g_free (name);
g_free (state->lang);
state->lang = NULL;
}
@@ -1069,8 +1074,8 @@ desc_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
}
}
}
- g_free (state->lang);
- state->lang = NULL;
+ g_free (state->desc);
+ state->desc = NULL;
}
static void
@@ -1113,8 +1118,10 @@ theme_load_from_uri (char const *uri)
GsfXMLInDoc *xml;
GsfInput *input = go_file_open (uri, NULL);
- if (input == NULL)
+ if (input == NULL) {
g_warning ("[GogTheme]: Could not open %s", uri);
+ return;
+ }
state.theme = NULL;
state.desc = state.lang = state.local_name = NULL;
state.langs = g_get_language_names ();
@@ -1128,7 +1135,7 @@ theme_load_from_uri (char const *uri)
unsigned i;
for (i = 0; i < state.theme->palette->len; i++)
colors[i] = GO_STYLE (g_ptr_array_index (state.theme->palette, i))->fill.pattern.back;
- state.theme->dcm = gog_axis_color_map_from_colors ("Default discrete", state.theme->palette->len, colors);
+ state.theme->dcm = gog_axis_color_map_from_colors ("Default", state.theme->palette->len, colors);
g_free (colors);
}
state.theme->local_name = state.local_name;
@@ -1199,8 +1206,10 @@ _gog_themes_shutdown (void)
/**
* gog_theme_get_color_map:
* @theme: #GogTheme
- * @discrete:
+ * @discrete: whether the map is for a discrete axis.
*
+ * Retrieves the themed color map. Each theme has a discrete color map and a
+ * continuous one.
* Returns: (transfer none): the requested color map.
**/
GogAxisColorMap const *
diff --git a/goffice/gtk/go-locale-sel.c b/goffice/gtk/go-locale-sel.c
index f8ea999..7b53223 100644
--- a/goffice/gtk/go-locale-sel.c
+++ b/goffice/gtk/go-locale-sel.c
@@ -158,7 +158,7 @@ static LocaleInfo locale_trans_array[] = {
{N_("Luxembourg/German (de_LU)"), "de_LU", LG_WESTERN_EUROPE },
{N_("Maldives (dv_MV)"), "dv_MV", LG_ASIA },
{N_("Bhutan (dz_BT)"), "dz_BT", LG_ASIA },
- {N_("Cyprus/Greek (el_CY)"), "el_CY", LG_WESTERN_EUROPE },
+ {N_("Cyprus/Greek (el_CY)"), "el_CY", LG_WESTERN_EUROPE },
{N_("Greece (el_GR)"), "el_GR", LG_WESTERN_EUROPE },
{N_("Antigua and Barbuda/English (en_AG)"), "en_AG", LG_CARIBBEAN },
{N_("Australia (en_AU)"), "en_AU", LG_AUSTRALIA },
diff --git a/goffice/utils/go-path.c b/goffice/utils/go-path.c
index cdc3b6b..0057735 100644
--- a/goffice/utils/go-path.c
+++ b/goffice/utils/go-path.c
@@ -896,7 +896,7 @@ go_path_to_svg (GOPath *path)
(GOPathLineToFunc) go_path_svg_line_to,
(GOPathCurveToFunc) go_path_svg_curve_to,
(GOPathClosePathFunc) go_path_svg_close, &closure);
-
+
return g_string_free (closure.str, FALSE);
}
diff --git a/plugins/plot_surface/gog-contour.c b/plugins/plot_surface/gog-contour.c
index c42c514..a406c12 100644
--- a/plugins/plot_surface/gog-contour.c
+++ b/plugins/plot_surface/gog-contour.c
@@ -142,7 +142,7 @@ gog_contour_plot_foreach_elem (GogPlot *plot, gboolean only_visible,
GogAxisColorMap const *map = gog_axis_get_color_map (axis);
GogAxisTick *zticks;
double *limits;
- double minimum, maximum, epsilon;
+ double minimum, maximum, epsilon, scale;
char const *separator = go_locale_get_decimal ()->str;
/* First get the series name and style */
@@ -170,6 +170,7 @@ gog_contour_plot_foreach_elem (GogPlot *plot, gboolean only_visible,
limits[j] = maximum;
else
j--;
+ scale = (j > gog_axis_color_map_get_max (map) && j > 1)? (double) gog_axis_color_map_get_max (map) / (j - 1): 1.;
style->interesting_fields = GO_STYLE_FILL | GO_STYLE_OUTLINE;
style->fill.type = GO_STYLE_FILL_PATTERN;
@@ -177,14 +178,14 @@ gog_contour_plot_foreach_elem (GogPlot *plot, gboolean only_visible,
if (gog_axis_is_inverted (axis)) {
for (i = 0; i < j; i++) {
- style->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: gog_axis_color_map_get_color (map, i);
+ style->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: gog_axis_color_map_get_color (map, i * scale);
label = g_strdup_printf ("[%g%s %g%c", limits[j - i - 1], separator,
limits[j - i], (limits[i - j] - minimum > epsilon)? '[':']');
(func) (i, style, label, NULL, data);
g_free (label);
}
if (limits[i - j] - minimum > epsilon) {
- style->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: gog_axis_color_map_get_color (map, i);
+ style->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: gog_axis_color_map_get_color (map, i * scale);
label = g_strdup_printf ("[%g%s %g]", minimum, separator,
limits[i - j]);
(func) (i + 1, style, label, NULL, data);
@@ -202,7 +203,7 @@ gog_contour_plot_foreach_elem (GogPlot *plot, gboolean only_visible,
} else
i = 0;
for (; i < j; i++) {
- style->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: gog_axis_color_map_get_color (map, i);
+ style->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: gog_axis_color_map_get_color (map, i * scale);
label = g_strdup_printf ("[%g%s %g%c", limits[i], separator,
limits[i + 1], (i == j - 1)? ']':'[');
(func) (i + 1, style, label, NULL, data);
@@ -337,8 +338,11 @@ gog_contour_view_render (GogView *view, GogViewAllocation const *bbox)
color = g_new0 (GOColor, max);
if (max < 2)
color[0] = GO_COLOR_WHITE;
- else for (i = 0; i < (unsigned) max; i++)
- color[i] = gog_axis_color_map_get_color (color_map, i);
+ else {
+ double scale = ((unsigned) max > gog_axis_color_map_get_max (color_map))? (double) gog_axis_color_map_get_max (color_map) / (max - 1): 1.;
+ for (i = 0; i < (unsigned) max; i++)
+ color[i] = gog_axis_color_map_get_color (color_map, i * scale);
+ }
/* clip to avoid problems with logarithmic axes */
gog_renderer_push_clip_rectangle (rend, view->residual.x, view->residual.y,
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bfdcdeb..b153977 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -71,6 +71,8 @@ goffice/graph/gog-axis-line.c
[type: gettext/glade]goffice/graph/gog-axis-prefs.ui
goffice/graph/gog-axis.c
goffice/graph/gog-axis.h
+goffice/graph/gog-axis-color-map.c
+[type: gettext/glade]goffice/graph/gog-axis-color-map-prefs.ui
goffice/graph/gog-chart-impl.h
goffice/graph/gog-chart.c
goffice/graph/gog-chart.h
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]