[goffice] Implement color scales. [#695829]



commit 13ab147836137fe3876e2bb8af4bf297faf52b51
Author: Jean Brefort <jean brefort normalesup org>
Date:   Fri May 3 16:30:35 2013 +0200

    Implement color scales. [#695829]

 ChangeLog                                |   26 ++
 NEWS                                     |    3 +
 docs/reference/goffice-0.10-sections.txt |    9 +
 goffice/Makefile.am                      |    1 +
 goffice/goffice.c                        |    1 +
 goffice/graph/goffice-graph.h            |    2 +-
 goffice/graph/gog-axis-color-map.c       |   77 +++--
 goffice/graph/gog-axis-color-map.h       |    3 +
 goffice/graph/gog-axis.c                 |   18 +
 goffice/graph/gog-axis.h                 |    4 +
 goffice/graph/gog-chart.c                |   64 ++++-
 goffice/graph/gog-color-scale-prefs.ui   |  115 +++++++
 goffice/graph/gog-color-scale.c          |  545 ++++++++++++++++++++++++++++--
 goffice/graph/gog-color-scale.h          |    2 +
 goffice/graph/gog-object.c               |  157 ++++++----
 goffice/graph/gog-renderer.c             |   12 +
 goffice/graph/gog-renderer.h             |    4 +
 goffice/graph/gog-theme.c                |   19 +-
 goffice/graph/gog-view.c                 |   15 +-
 plugins/plot_surface/gog-contour.c       |    2 +-
 plugins/plot_surface/gog-xyz-prefs.c     |   15 +
 plugins/plot_surface/gog-xyz-prefs.ui    |   25 ++-
 22 files changed, 999 insertions(+), 120 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index c7077fe..5b534f9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2013-05-03  Jean Brefort  <jean brefort normalesup org>
+
+       * goffice/Makefile.am: add new UI file.
+       * goffice/goffice.c (libgoffice_init): implement color scales.
+       * goffice/graph/goffice-graph.h: ditto.
+       * goffice/graph/gog-axis-color-map.c: ditto.
+       * goffice/graph/gog-axis-color-map.h: ditto.
+       * goffice/graph/gog-axis.c: ditto.
+       * goffice/graph/gog-axis.h: ditto.
+       * goffice/graph/gog-chart.c: ditto.
+       * goffice/graph/gog-color-scale-prefs.ui: new UI file.
+       * goffice/graph/gog-color-scale.c: implement color scales.
+       * goffice/graph/gog-color-scale.h: ditto.
+       * goffice/graph/gog-object.c: fix manual size issues.
+       * goffice/graph/gog-renderer.c (gog_renderer_draw_color_map): new function.
+       * goffice/graph/gog-renderer.h: ditto.
+       * goffice/graph/gog-theme.c (build_predefined_themes): add color scale.
+       * goffice/graph/gog-view.c (gog_view_size_allocate_real): fix manual size
+       issues.
+       * plugins/plot_surface/gog-contour.c
+       (gog_contour_plot_foreach_elem): don't crash when inverting the pseudo-3d
+       axis.
+       * plugins/plot_surface/gog-xyz-prefs.c: add an option to not show the colors
+       in the legend.
+       * plugins/plot_surface/gog-xyz-prefs.ui: ditto.
+
 2013-04-30  Morten Welinder  <terra gnome org>
 
        * goffice/math/go-regression.c (go_matrix_pseudo_inverse): New
diff --git a/NEWS b/NEWS
index c8ac26f..08d97bb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 goffice 0.10.3:
 
+Jean:
+       * Implement color scales. [#695829]
+
 --------------------------------------------------------------------------
 goffice 0.10.2:
 
diff --git a/docs/reference/goffice-0.10-sections.txt b/docs/reference/goffice-0.10-sections.txt
index 056958e..1bbbcb5 100644
--- a/docs/reference/goffice-0.10-sections.txt
+++ b/docs/reference/goffice-0.10-sections.txt
@@ -586,6 +586,7 @@ GO_COMPONENT
 GO_IS_COMPONENT
 GO_TYPE_COMPONENT
 go_component_get_type
+GOComponentPrivate
 </SECTION>
 
 <SECTION>
@@ -1981,6 +1982,8 @@ go_matrix_determinant
 go_matrix_determinantl
 go_matrix_invert
 go_matrix_invertl
+go_matrix_pseudo_inverse
+go_matrix_pseudo_inversel
 go_non_linear_regression
 go_non_linear_regressionl
 go_power_regression
@@ -2258,6 +2261,7 @@ goc_canvas_get_grabbed_item
 goc_canvas_get_height
 goc_canvas_get_item_at
 goc_canvas_get_pixels_per_unit
+goc_canvas_get_realized
 goc_canvas_get_root
 goc_canvas_get_scroll_position
 goc_canvas_get_width
@@ -2368,6 +2372,7 @@ goc_item_draw_region
 goc_item_get_bounds
 goc_item_get_operator
 goc_item_get_parent
+goc_item_get_style_context
 goc_item_get_window
 goc_item_grab
 goc_item_hide
@@ -2794,6 +2799,7 @@ gog_axis_color_map_get_id
 gog_axis_color_map_get_name
 gog_axis_color_map_get_resource_type
 gog_axis_color_map_get_snapshot
+gog_axis_color_map_to_cairo
 <SUBSECTION Standard>
 GOG_AXIS_COLOR_MAP
 GOG_IS_AXIS_COLOR_MAP
@@ -2889,6 +2895,8 @@ gog_child_button_get_type
 <FILE>gog-color-scale</FILE>
 <TITLE>GogColorScale</TITLE>
 GogColorScale
+gog_color_scale_get_axis
+gog_color_scale_set_axis
 <SUBSECTION Standard>
 GOG_COLOR_SCALE
 GOG_IS_COLOR_SCALE
@@ -3269,6 +3277,7 @@ gog_reg_curve_get_type
 GOG_RENDERER_GRIP_SIZE
 GOG_RENDERER_HAIRLINE_WIDTH_PTS
 gog_renderer_draw_circle
+gog_renderer_draw_color_map
 gog_renderer_draw_data_label
 gog_renderer_draw_gostring
 gog_renderer_draw_grip
diff --git a/goffice/Makefile.am b/goffice/Makefile.am
index 110c918..98bc860 100644
--- a/goffice/Makefile.am
+++ b/goffice/Makefile.am
@@ -561,6 +561,7 @@ embedded_stuff_compress = \
        graph/gog-3d-box-prefs.ui               \
        graph/gog-axis-prefs.ui                 \
        graph/gog-axis-color-map-prefs.ui       \
+       graph/gog-color-scale-prefs.ui  \
        graph/gog-equation-prefs.ui             \
        graph/gog-error-bar-prefs.ui            \
        graph/gog-graph-prefs.ui                \
diff --git a/goffice/goffice.c b/goffice/goffice.c
index 9cad131..26e7064 100644
--- a/goffice/goffice.c
+++ b/goffice/goffice.c
@@ -208,6 +208,7 @@ libgoffice_init (void)
        (void) GOG_TYPE_LEGEND;
        (void) GOG_TYPE_AXIS;
        (void) GOG_TYPE_AXIS_LINE;
+       (void) GOG_TYPE_COLOR_SCALE;
        (void) GOG_TYPE_LABEL;
        (void) GOG_TYPE_GRID;
        (void) GOG_TYPE_GRID_LINE;
diff --git a/goffice/graph/goffice-graph.h b/goffice/graph/goffice-graph.h
index 2b1fe2f..28cf54a 100644
--- a/goffice/graph/goffice-graph.h
+++ b/goffice/graph/goffice-graph.h
@@ -201,7 +201,7 @@ typedef enum {
        GOG_POSITION_MANUAL_W_ABS    = 1 << 22, /* absolute width */
        GOG_POSITION_MANUAL_H        = 1 << 23, /* relative height */
        GOG_POSITION_MANUAL_H_ABS    = 1 << 24, /* absolute height */
-       GOG_POSITION_ANY_MANUAL_SIZE = 0xf00000
+       GOG_POSITION_ANY_MANUAL_SIZE = 0x1e00000
 } GogObjectPosition;
 
 typedef enum {
diff --git a/goffice/graph/gog-axis-color-map.c b/goffice/graph/gog-axis-color-map.c
index 11d7bb7..075b55b 100644
--- a/goffice/graph/gog-axis-color-map.c
+++ b/goffice/graph/gog-axis-color-map.c
@@ -496,7 +496,6 @@ gog_axis_color_map_get_snapshot (GogAxisColorMap const *map,
        cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 16, 16);
        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);
        cairo_pattern_t *pattern;
 
        g_return_val_if_fail (GOG_IS_AXIS_COLOR_MAP (map), NULL);
@@ -519,31 +518,70 @@ gog_axis_color_map_get_snapshot (GogAxisColorMap const *map,
        cairo_set_source (cr, pattern);
        cairo_fill (cr);
        cairo_pattern_destroy (pattern);
+       gog_axis_color_map_to_cairo (map, cr, discrete, horizontal, width, height);
+
+       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;
+}
+
+
+/**
+ * gog_axis_color_map_to_cairo:
+ * @map: a #GogAxisMap
+ * @cr: a cairo context.
+ * @discrete: whether to use constant colors between each stop or a gradient.
+ * @horizontal: whether to get an horizontal or a vertical snapshot.
+ * @width: the rectangle width.
+ * @height: the rectangle height.
+ *
+ * When @discrete is larger than 1, it will be interpreted as the number of 
+ * major ticks used. The number of colors will then be @discrete − 1.
+ * Draws a snapshot of the color map inside the rectangle.
+ **/
+void
+gog_axis_color_map_to_cairo (GogAxisColorMap const *map, cairo_t *cr,
+                             unsigned discrete, gboolean horizontal,
+                             double width, double height)
+{
+       unsigned i, max = gog_axis_color_map_get_max (map);
        if (discrete) {
                GOColor color;
-               unsigned t0 = 0, t1, maxt = horizontal? width: height;
+               double t0, maxt, step, start, scale = 1;
+               if (discrete > 1) {
+                       if (discrete > max + 1) { /* we need to have at least two colors */
+                               scale = (double) gog_axis_color_map_get_max (map) / (discrete - 2);
+                               max = discrete - 2;
+                       }
+               }
                max++;
+               if (horizontal) {
+                       maxt = width;
+                       step = maxt / max;
+                       start = 0;
+               } else {
+                       maxt = height;
+                       step = -maxt / max;
+                       start = height;
+               }
                for (i = 0; i < max; i++) {
-                       t1 = (i + 1) * maxt / max;
-                       color = gog_axis_color_map_get_color (map, i);
+                       t0 = start + i * step;
+                       color = gog_axis_color_map_get_color (map, i * scale);
                        if (horizontal)
-                               cairo_rectangle (cr, t0, 0., t1, height);
+                               cairo_rectangle (cr, t0, 0., step, height);
                        else
-                               cairo_rectangle (cr, 0., t0, width, t1);
+                               cairo_rectangle (cr, 0., t0, width, step);
                        cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (color));
                        cairo_fill (cr);
-                       t0 = t1;
                }
        } else {
-               double x1, y1;
-               if (horizontal) {
-                       x1 = width;
-                       y1 = 0.;
-               } else {
-                       x1 = 0.;
-                       y1 = height;
-               }
-               pattern = cairo_pattern_create_linear (0., 0., x1, y1);
+               cairo_pattern_t *pattern;
+               pattern = (horizontal)?
+                                       cairo_pattern_create_linear (0., 0., width, 0.):
+                                       cairo_pattern_create_linear (0., height, 0., 0.);
                for (i = 0; i < map->size; i++) {
                        cairo_pattern_add_color_stop_rgba (pattern,
                                                           (double) map->limits[i] / (double) max,
@@ -554,13 +592,6 @@ gog_axis_color_map_get_snapshot (GogAxisColorMap const *map,
                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;
 }
 
 static void
diff --git a/goffice/graph/gog-axis-color-map.h b/goffice/graph/gog-axis-color-map.h
index 7161db0..9d7d296 100644
--- a/goffice/graph/gog-axis-color-map.h
+++ b/goffice/graph/gog-axis-color-map.h
@@ -44,6 +44,9 @@ GdkPixbuf *gog_axis_color_map_get_snapshot (GogAxisColorMap const *map,
                                             gboolean horizontal,
                                             unsigned width,
                                             unsigned height);
+void gog_axis_color_map_to_cairo (GogAxisColorMap const *map, cairo_t *cr,
+                                  unsigned discrete, gboolean horizontal,
+                                  double width, double height);
 char const *gog_axis_color_map_get_id (GogAxisColorMap const *map);
 char const *gog_axis_color_map_get_name (GogAxisColorMap const *map);
 GoResourceType gog_axis_color_map_get_resource_type (GogAxisColorMap const *map);
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index 81ee9ac..0a357e1 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -125,6 +125,7 @@ struct _GogAxis {
        double span_start, span_end;    /* percent of used area */
        GogAxisColorMap const *color_map;               /* color map for color and pseudo-3d axis */
        gboolean auto_color_map;
+       GogColorScale *color_scale;
 };
 
 /*****************************************************************************/
@@ -3554,6 +3555,23 @@ gog_axis_get_color_map (GogAxis *axis)
        return axis->color_map;
 }
 
+GogColorScale *
+_gog_axis_get_color_scale (GogAxis *axis)
+{
+       g_return_val_if_fail (GOG_IS_AXIS (axis), NULL);
+
+       return axis->color_scale;
+}
+
+void
+_gog_axis_set_color_scale (GogAxis *axis, GogColorScale *scale)
+{
+       g_return_if_fail (GOG_IS_AXIS (axis) &&
+                         (axis->type == GOG_AXIS_COLOR || axis->type == GOG_AXIS_PSEUDO_3D) &&
+                         (axis->color_scale == NULL || scale == NULL));
+       axis->color_scale = scale;
+}
+
 /****************************************************************************/
 
 typedef GogAxisBaseView                GogAxisView;
diff --git a/goffice/graph/gog-axis.h b/goffice/graph/gog-axis.h
index 4aaa99a..e582d86 100644
--- a/goffice/graph/gog-axis.h
+++ b/goffice/graph/gog-axis.h
@@ -111,6 +111,10 @@ double                     gog_axis_get_polar_perimeter    (GogAxis *axis);
 double                         gog_axis_get_circular_rotation  (GogAxis *axis);
 GogAxisColorMap const *gog_axis_get_color_map  (GogAxis *axis);
 
+/* private */
+GogColorScale *_gog_axis_get_color_scale (GogAxis *axis);
+void _gog_axis_set_color_scale (GogAxis *axis, GogColorScale *scale);
+
 G_END_DECLS
 
 #endif /* GOG_AXIS_H */
diff --git a/goffice/graph/gog-chart.c b/goffice/graph/gog-chart.c
index 57c6dec..ae9e000 100644
--- a/goffice/graph/gog-chart.c
+++ b/goffice/graph/gog-chart.c
@@ -554,13 +554,67 @@ axis_post_add (GogObject *axis, GogAxisType t)
 }
 
 static void
-axis_pre_remove (GogObject *parent, GogObject *axis)
+axis_pre_remove (GogObject *parent, GogObject *child)
 {
        GogChart *chart = GOG_CHART (parent);
+       GogAxis *axis = GOG_AXIS (child);
+       GogColorScale *scale = _gog_axis_get_color_scale (axis);
+       if (scale)
+               gog_color_scale_set_axis (scale, NULL);
        gog_axis_clear_contributors (GOG_AXIS (axis));
        chart->axes = g_slist_remove (chart->axes, axis);
 }
 
+/*  Color scale related code */
+static gboolean
+color_scale_can_add (GogObject const *parent)
+{
+       /* TRUE if there are more color or pseudo-3d axes than there are color scales */
+       GogChart *chart = GOG_CHART (parent);
+       GSList *ptr;
+       GogAxis *axis;
+       GogAxisType type;
+
+       if ((chart->axis_set & ((1 << GOG_AXIS_COLOR) | (1 << GOG_AXIS_PSEUDO_3D ))) == 0)
+               return FALSE;
+       for (ptr = chart->axes; ptr && ptr->data; ptr = ptr->next) {
+               axis = GOG_AXIS (ptr->data);
+               type = gog_axis_get_atype (axis);
+               if ((type == GOG_AXIS_COLOR || type == GOG_AXIS_PSEUDO_3D)
+                   && _gog_axis_get_color_scale (axis) == NULL)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static void
+color_scale_post_add (GogObject *parent, GogObject *child)
+{
+       /* Link the color scale to an axis without a preexisting color scale */
+       GogChart *chart = GOG_CHART (parent);
+       GSList *ptr;
+       GogAxis *axis;
+       GogAxisType type;
+
+       for (ptr = chart->axes; ptr && ptr->data; ptr = ptr->next) {
+               axis = GOG_AXIS (ptr->data);
+               type = gog_axis_get_atype (axis);
+               if ((type == GOG_AXIS_COLOR || type == GOG_AXIS_PSEUDO_3D)
+                   && _gog_axis_get_color_scale (axis) == NULL) {
+                               gog_color_scale_set_axis (GOG_COLOR_SCALE (child), axis);
+                               break;
+                       }
+       }
+}
+
+static void
+color_scale_pre_remove (GogObject *parent, GogObject *scale)
+{
+       /* Unlink the color scale */
+       gog_color_scale_set_axis (GOG_COLOR_SCALE (scale), NULL);
+}
+
+
 static gboolean x_axis_can_add (GogObject const *parent) { return axis_can_add (parent, GOG_AXIS_X); }
 static void x_axis_post_add    (GogObject *parent, GogObject *child)  { axis_post_add   (child, GOG_AXIS_X); 
}
 static gboolean y_axis_can_add (GogObject const *parent) { return axis_can_add (parent, GOG_AXIS_Y); }
@@ -650,7 +704,13 @@ static GogObjectRole const roles[] = {
 #endif
        { N_("3D-Box"), "Gog3DBox",     1,
          GOG_POSITION_SPECIAL, GOG_POSITION_SPECIAL, GOG_OBJECT_NAME_BY_ROLE,
-         role_3d_box_can_add, role_3d_box_can_remove, NULL, NULL, NULL, NULL, { -1 } }
+         role_3d_box_can_add, role_3d_box_can_remove, NULL, NULL, NULL, NULL, { -1 } },
+       { N_("Color-Scale"), "GogColorScale", 7,
+         GOG_POSITION_COMPASS|GOG_POSITION_ANY_MANUAL|GOG_POSITION_ANY_MANUAL_SIZE,
+         GOG_POSITION_E|GOG_POSITION_ALIGN_CENTER,
+         GOG_OBJECT_NAME_BY_ROLE,
+         color_scale_can_add, NULL, NULL,
+         color_scale_post_add, color_scale_pre_remove, NULL, { -1 } }
 };
 
 static GogManualSizeMode
diff --git a/goffice/graph/gog-color-scale-prefs.ui b/goffice/graph/gog-color-scale-prefs.ui
new file mode 100644
index 0000000..2d9fa8a
--- /dev/null
+++ b/goffice/graph/gog-color-scale-prefs.ui
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkGrid" id="color-scale-prefs">
+    <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>
+      <object class="GtkLabel" id="pos-lbl">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Ticks position:</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>
+      <object class="GtkLabel" id="direct-lbl">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Direction:</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="GtkComboBoxText" id="direction-btn">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="entry_text_column">0</property>
+        <property name="id_column">1</property>
+        <items>
+          <item translatable="yes">Horizontal</item>
+          <item translatable="yes">Vertical</item>
+        </items>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">0</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkComboBoxText" id="position-btn">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="entry_text_column">0</property>
+        <property name="id_column">1</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">1</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <object class="GtkLabel" id="width-lbl">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Width:</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="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="top_attach">2</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkAdjustment" id="width-adj">
+    <property name="lower">1</property>
+    <property name="upper">255</property>
+    <property name="value">10</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+</interface>
diff --git a/goffice/graph/gog-color-scale.c b/goffice/graph/gog-color-scale.c
index c62ba1a..33e2ee6 100644
--- a/goffice/graph/gog-color-scale.c
+++ b/goffice/graph/gog-color-scale.c
@@ -40,11 +40,11 @@
 struct _GogColorScale {
        GogStyledObject base;
        GogAxis *color_axis; /* the color or pseudo-3d axis */
-       GogAxis *axis; /* the axis used to display the scale */
        gboolean horizontal;
        gboolean axis_at_low;   /* axis position on low coordinates side */
        double width; /* will actually be height of the colored rectangle if
                                   * horizontal */
+       int tick_size;
 };
 typedef GogStyledObjectClass GogColorScaleClass;
 
@@ -54,16 +54,157 @@ static GType gog_color_scale_view_get_type (void);
 static void
 gog_color_scale_init_style (GogStyledObject *gso, GOStyle *style)
 {
-       style->interesting_fields = GO_STYLE_LINE | GO_STYLE_FONT | GO_STYLE_TEXT_LAYOUT;
+       style->interesting_fields = GO_STYLE_LINE | GO_STYLE_FILL |
+                               GO_STYLE_FONT | GO_STYLE_TEXT_LAYOUT;
        gog_theme_fillin_style (gog_object_get_theme (GOG_OBJECT (gso)),
-                               style, GOG_OBJECT (gso), 0, GO_STYLE_LINE |
+                               style, GOG_OBJECT (gso), 0,
+                               GO_STYLE_LINE | GO_STYLE_FILL |
                                GO_STYLE_FONT | GO_STYLE_TEXT_LAYOUT);
 }
 
+#ifdef GOFFICE_WITH_GTK
+
+static void
+position_fill_cb (GtkComboBoxText *box, GogColorScale *scale)
+{
+       if (scale->horizontal) {
+               gtk_combo_box_text_append_text (box, _("Top"));
+               gtk_combo_box_text_append_text (box, _("Bottom"));
+       } else {
+               gtk_combo_box_text_append_text (box, _("Left"));
+               gtk_combo_box_text_append_text (box, _("Right"));
+       }
+       gtk_combo_box_set_active (GTK_COMBO_BOX (box), (scale->axis_at_low)? 0: 1);
+}
+
+static void
+position_changed_cb (GtkComboBox *box, GogColorScale *scale)
+{
+       scale->axis_at_low = gtk_combo_box_get_active (box) == 0;
+       gog_object_emit_changed (GOG_OBJECT (scale), FALSE);
+}
+
+static void
+direction_changed_cb (GtkComboBox *box, GogColorScale *scale)
+{
+       GogObjectPosition pos;
+       GogObject *gobj = GOG_OBJECT (scale);
+       GtkComboBoxText *text;
+       scale->horizontal = gtk_combo_box_get_active (box) == 0;
+       /* if the position is automatic, try to adjust accordingly */
+       pos = gog_object_get_position_flags (gobj, GOG_POSITION_MANUAL);
+       if (!pos) {
+               gboolean changed = TRUE;
+               pos = gog_object_get_position_flags (gobj, GOG_POSITION_COMPASS);
+               switch (pos) {
+               case GOG_POSITION_N:
+                       pos = GOG_POSITION_W;
+                       break;
+               case GOG_POSITION_S:
+                       pos = GOG_POSITION_E;
+                       break;
+               case GOG_POSITION_E:
+                       pos = GOG_POSITION_S;
+                       break;
+               case GOG_POSITION_W:
+                       pos = GOG_POSITION_N;
+                       break;
+               default:
+                       changed = FALSE;
+               }
+               if (changed)
+                       gog_object_set_position_flags (gobj, pos, GOG_POSITION_COMPASS);
+       }
+       pos = gog_object_get_position_flags (gobj, GOG_POSITION_ANY_MANUAL_SIZE);
+       if (pos) {
+               GogViewAllocation alloc;
+               double buf;
+               switch (pos) {
+               case GOG_POSITION_MANUAL_W:
+                       gog_object_set_position_flags (gobj, GOG_POSITION_MANUAL_H,
+                                                          GOG_POSITION_ANY_MANUAL_SIZE);
+                       break;
+               case GOG_POSITION_MANUAL_W_ABS:
+                       gog_object_set_position_flags (gobj, GOG_POSITION_MANUAL_H_ABS,
+                                                          GOG_POSITION_ANY_MANUAL_SIZE);
+                       break;
+               case GOG_POSITION_MANUAL_H:
+                       gog_object_set_position_flags (gobj, GOG_POSITION_MANUAL_W,
+                                                          GOG_POSITION_ANY_MANUAL_SIZE);
+                       break;
+               case GOG_POSITION_MANUAL_H_ABS:
+                       gog_object_set_position_flags (gobj, GOG_POSITION_MANUAL_W_ABS,
+                                                          GOG_POSITION_ANY_MANUAL_SIZE);
+                       break;
+               default:
+                       break;
+               }
+               gog_object_get_manual_position (gobj, &alloc);
+               buf = alloc.w;
+               alloc.w = alloc.h;
+               alloc.h = buf;
+               gog_object_set_manual_position (gobj, &alloc);
+       }
+       g_signal_emit_by_name (gobj, "update-editor");
+       text = GTK_COMBO_BOX_TEXT (g_object_get_data (G_OBJECT (box), "position"));
+       g_signal_handlers_block_by_func (text, position_changed_cb, scale);
+       gtk_list_store_clear (GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (text))));
+       position_fill_cb (text, scale);
+       g_signal_handlers_unblock_by_func (text, position_changed_cb, scale);
+}
+
+static void
+width_changed_cb (GtkSpinButton *btn, GogColorScale *scale)
+{
+       scale->width = gtk_spin_button_get_value_as_int (btn);
+       gog_object_emit_changed (GOG_OBJECT (scale), TRUE);
+}
+
+static void
+gog_color_scale_populate_editor (GogObject *gobj,
+                          GOEditor *editor,
+                          G_GNUC_UNUSED GogDataAllocator *dalloc,
+                          GOCmdContext *cc)
+{
+       GogColorScale *scale = GOG_COLOR_SCALE (gobj);
+       GtkBuilder *gui;
+       GtkWidget *w, *w_;
+
+       gui = go_gtk_builder_load_internal ("res:go:graph/gog-color-scale-prefs.ui", GETTEXT_PACKAGE, cc);
+       if (gui == NULL)
+               return;
+
+       w = go_gtk_builder_get_widget (gui, "direction-btn");
+       gtk_combo_box_set_active (GTK_COMBO_BOX (w), (scale->horizontal)? 0: 1);
+       g_signal_connect (w, "changed", G_CALLBACK (direction_changed_cb), scale);
+
+       w_ = go_gtk_builder_get_widget (gui, "position-btn");
+       g_object_set_data (G_OBJECT (w), "position", w_);
+       position_fill_cb (GTK_COMBO_BOX_TEXT (w_), scale);
+       g_signal_connect (w_, "changed", G_CALLBACK (position_changed_cb), scale);
+
+       w = go_gtk_builder_get_widget (gui, "width-btn");
+       gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), scale->width);
+       g_signal_connect (w, "changed", G_CALLBACK (width_changed_cb), scale);
+
+       go_editor_add_page (editor, go_gtk_builder_get_widget (gui, "color-scale-prefs"), _("Details"));
+       g_object_unref (gui);
+       ((GogObjectClass *) parent_klass)->populate_editor (gobj, editor, dalloc, cc);
+}
+#endif
+
+static GogManualSizeMode
+gog_color_scale_get_manual_size_mode (GogObject *obj)
+{
+       return GOG_COLOR_SCALE (obj)->horizontal? GOG_MANUAL_SIZE_WIDTH: GOG_MANUAL_SIZE_HEIGHT;
+}
+
 enum {
        COLOR_SCALE_PROP_0,
        COLOR_SCALE_PROP_HORIZONTAL,
-       COLOR_SCALE_PROP_WIDTH
+       COLOR_SCALE_PROP_WIDTH,
+       COLOR_SCALE_PROP_AXIS,
+       COLOR_SCALE_PROP_TICK_SIZE_PTS
 };
 
 static void
@@ -75,17 +216,40 @@ gog_color_scale_set_property (GObject *obj, guint param_id,
        switch (param_id) {
        case COLOR_SCALE_PROP_HORIZONTAL:
                scale->horizontal = g_value_get_boolean (value);
-               g_object_set (G_OBJECT (scale->axis), "type",
-                             scale->horizontal? GOG_AXIS_X: GOG_AXIS_Y, NULL);
                break;
        case COLOR_SCALE_PROP_WIDTH:
                scale->width = g_value_get_double (value);
                break;
+       case COLOR_SCALE_PROP_AXIS: {
+               GogChart *chart = GOG_CHART (gog_object_get_parent (GOG_OBJECT (obj)));
+               GSList *ptr;
+               char const *buf = g_value_get_string (value);
+               GogAxis *axis = NULL;
+               for (ptr = gog_chart_get_axes (chart, GOG_AXIS_COLOR); ptr && ptr->data; ptr = ptr->next) {
+                       if (!strcmp (buf, gog_object_get_name (GOG_OBJECT (ptr->data)))) {
+                           axis = GOG_AXIS (ptr->data);
+                               break;
+                       }
+               }
+               if (axis == NULL) /* try with the pseudo-3d axes */
+                       for (ptr = gog_chart_get_axes (chart, GOG_AXIS_PSEUDO_3D); ptr && ptr->data; ptr = 
ptr->next) {
+                               if (!strcmp (buf, gog_object_get_name (GOG_OBJECT (ptr->data)))) {
+                                       axis = GOG_AXIS (ptr->data);
+                                       break;
+                               }
+                       }
+               gog_color_scale_set_axis (scale, axis);
+               break;
+       }
+       case COLOR_SCALE_PROP_TICK_SIZE_PTS:
+               scale->tick_size = g_value_get_int (value);
+               break;
 
        default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
                 return; /* NOTE : RETURN */
        }
-               gog_object_emit_changed (GOG_OBJECT (obj), TRUE);
+
+       gog_object_emit_changed (GOG_OBJECT (obj), TRUE);
 }
 
 static void
@@ -101,6 +265,12 @@ gog_color_scale_get_property (GObject *obj, guint param_id,
        case COLOR_SCALE_PROP_WIDTH:
                g_value_set_double (value, scale->width);
                break;
+       case COLOR_SCALE_PROP_AXIS:
+               g_value_set_string (value, gog_object_get_name (GOG_OBJECT (scale->color_axis)));
+               break;
+       case COLOR_SCALE_PROP_TICK_SIZE_PTS:
+               g_value_set_int (value, scale->tick_size);
+               break;
 
        default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
                 return; /* NOTE : RETURN */
@@ -108,16 +278,6 @@ gog_color_scale_get_property (GObject *obj, guint param_id,
 }
 
 static void
-gog_color_scale_finalize (GObject *obj)
-{
-       GogColorScale *scale = GOG_COLOR_SCALE (obj);
-
-       g_object_unref (scale->axis);
-
-       parent_klass->finalize (obj);
-}
-
-static void
 gog_color_scale_class_init (GObjectClass *gobject_klass)
 {
        GogObjectClass *gog_klass = (GogObjectClass *) gobject_klass;
@@ -125,7 +285,6 @@ gog_color_scale_class_init (GObjectClass *gobject_klass)
 
        parent_klass = g_type_class_peek_parent (gobject_klass);
        /* GObjectClass */
-       gobject_klass->finalize = gog_color_scale_finalize;
        gobject_klass->get_property = gog_color_scale_get_property;
        gobject_klass->set_property = gog_color_scale_set_property;
        g_object_class_install_property (gobject_klass, COLOR_SCALE_PROP_HORIZONTAL,
@@ -136,11 +295,26 @@ gog_color_scale_class_init (GObjectClass *gobject_klass)
        g_object_class_install_property (gobject_klass, COLOR_SCALE_PROP_WIDTH,
                g_param_spec_double ("width", _("Width"),
                        _("Color scale thickness."),
-                       0., 255., 10.,
+                       1., 255., 10.,
+                       GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+       g_object_class_install_property (gobject_klass, COLOR_SCALE_PROP_AXIS,
+               g_param_spec_string ("axis",
+                       _("Axis"),
+                       _("Reference to the color or pseudo-3d axis"),
+                       NULL,
+                       GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+       g_object_class_install_property (gobject_klass, COLOR_SCALE_PROP_TICK_SIZE_PTS,
+               g_param_spec_int ("tick-size-pts",
+                       _("Tick size"),
+                       _("Size of the tick marks, in points"),
+                       0, 20, 4,
                        GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 
+       gog_klass->get_manual_size_mode = gog_color_scale_get_manual_size_mode;
        gog_klass->view_type    = gog_color_scale_view_get_type ();
-
+#ifdef GOFFICE_WITH_GTK
+       gog_klass->populate_editor = gog_color_scale_populate_editor;
+#endif
        style_klass->init_style = gog_color_scale_init_style;
 }
 
@@ -148,18 +322,53 @@ static void
 gog_color_scale_init (GogColorScale *scale)
 {
        scale->width = 10;
-       scale->axis = (GogAxis *) g_object_new (GOG_TYPE_AXIS,
-                                               "type", GOG_AXIS_Y,
-                                               NULL);
+       scale->tick_size = 4;
 }
 
 GSF_CLASS (GogColorScale, gog_color_scale,
           gog_color_scale_class_init, gog_color_scale_init,
           GOG_TYPE_STYLED_OBJECT)
 
+/**
+ * gog_color_scale_get_axis:
+ * @scale: #GogColorScale
+ *
+ * Gets the axis mapping to the colors and associated with @scale
+ * Returns: (transfer none): the associated axis.
+ **/
+GogAxis *
+gog_color_scale_get_axis (GogColorScale *scale)
+{
+       g_return_val_if_fail (GOG_IS_COLOR_SCALE (scale), NULL);
+       return scale->color_axis;
+}
+
+/**
+ * gog_color_scale_set_axis:
+ * @scale: #GogColorScale
+ * @axis: a color or pseudo-3d axis
+ *
+ * Associates the axis with @scale.
+ **/
+void
+gog_color_scale_set_axis (GogColorScale *scale, GogAxis *axis)
+{
+       g_return_if_fail (GOG_IS_COLOR_SCALE (scale));
+       if (scale->color_axis == axis)
+               return;
+       if (scale->color_axis != NULL)
+               _gog_axis_set_color_scale (scale->color_axis, NULL);
+       scale->color_axis = axis;
+       if (axis)
+               _gog_axis_set_color_scale (axis, scale);
+}
+
 /************************************************************************/
 
-typedef GogView                GogColorScaleView;
+typedef struct {
+       GogView base;
+       GogViewAllocation scale_area;
+} GogColorScaleView;
 typedef GogViewClass   GogColorScaleViewClass;
 
 #define GOG_TYPE_COLOR_SCALE_VIEW      (gog_color_scale_view_get_type ())
@@ -171,11 +380,299 @@ gog_color_scale_view_size_request (GogView *v,
                                    GogViewRequisition const *available,
                                    GogViewRequisition *req)
 {
+       GogColorScale *scale = GOG_COLOR_SCALE (v->model);
+       GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (scale));
+       double line_width, tick_size, label_padding, max_width = 0., max_height = 0.;
+       unsigned nb_ticks, i;
+       GogAxisTick *ticks;
+       GOGeometryAABR txt_aabr;
+       GOGeometryOBR txt_obr;
+
+       gog_renderer_push_style (v->renderer, style);
+       gog_renderer_get_text_OBR (v->renderer, "0", TRUE, &txt_obr, -1.);
+       label_padding = txt_obr.h * .15;
+       nb_ticks = gog_axis_get_ticks (scale->color_axis, &ticks);
+       for (i = 0; i < nb_ticks; i++)
+               if (ticks[i].type == GOG_AXIS_TICK_MAJOR) {
+                       gog_renderer_get_gostring_AABR (v->renderer, ticks[i].str, &txt_aabr, 0.);
+                       if (txt_aabr.w > max_width)
+                               max_width = txt_aabr.w;
+                       if (txt_aabr.h > max_height)
+                               max_height = txt_aabr.h;
+               }
+
+       if (go_style_is_line_visible (style)) {
+               line_width = gog_renderer_line_size (v->renderer, style->line.width);
+               tick_size = gog_renderer_pt2r (v->renderer, scale->tick_size);
+       } else
+               line_width = tick_size = 0.;
+       if (scale->horizontal) {
+               req->w = available->w;
+               req->h = gog_renderer_pt2r (v->renderer, scale->width)
+                                + 2 * line_width + tick_size + label_padding + max_height;
+       } else {
+               req->h = available->h;
+               req->w = gog_renderer_pt2r (v->renderer, scale->width)
+                                + 2 * line_width + tick_size + label_padding + max_width;
+       }
+       gog_renderer_pop_style (v->renderer);
 }
 
 static void
 gog_color_scale_view_render (GogView *view, GogViewAllocation const *bbox)
 {
+       GogColorScale *scale = GOG_COLOR_SCALE (view->model);
+       unsigned nb_ticks, nb_maj_ticks = 0, i, j, l;
+       GogAxisTick *ticks;
+       GogViewAllocation scale_area, label_pos;
+       GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (scale));
+       double line_width, tick_size, label_padding, width, pos, start, stop;
+       GOGeometryOBR txt_obr;
+       GOGeometryOBR *obrs = NULL;
+       GogAxisMap *map;
+       GOPath *path;
+       gboolean is_line_visible;
+       double min, max, first, last, hf, hl;
+       GOAnchorType anchor;
+       gboolean discrete = gog_axis_get_atype (scale->color_axis) == GOG_AXIS_PSEUDO_3D;
+       GogAxisColorMap const *cmap = gog_axis_get_color_map (scale->color_axis);
+
+       gog_renderer_push_style (view->renderer, style);
+       nb_ticks = gog_axis_get_ticks (scale->color_axis, &ticks);
+       for (i = 0; i < nb_ticks; i++)
+               if (ticks[i].type == GOG_AXIS_TICK_MAJOR)
+                       nb_maj_ticks++;
+       gog_renderer_get_text_OBR (view->renderer, "0", TRUE, &txt_obr, -1.);
+       label_padding = txt_obr.h * .15;
+       width = gog_renderer_pt2r (view->renderer, scale->width);
+       obrs = g_new0 (GOGeometryOBR, nb_maj_ticks);
+       gog_axis_get_bounds (scale->color_axis, &min, &max);
+       first = min - 1.;
+       /* evaluate labels size, and find first and last label */
+       for (i = 0, j = 0; i < nb_ticks; i++)
+               if (ticks[i].type == GOG_AXIS_TICK_MAJOR) {
+                       gog_renderer_get_gostring_OBR (view->renderer, ticks[i].str, obrs + j, -1.);
+                       if (first < min) {
+                               first = last = ticks[i].position;
+                               hf = hl = scale->horizontal? obrs[j].w: obrs[j].h;
+                       } else if (ticks[i].position > last) {
+                               last = ticks[i].position;
+                               hl = scale->horizontal? obrs[j].w: obrs[j].h;
+                       } else if (ticks[i].position < first) {
+                               first = ticks[i].position;
+                               hf = scale->horizontal? obrs[j].w: obrs[j].h;
+                       }
+                       j++;
+               }
+       hf /= 2.;
+       hl /= 2.;
+
+       /* evaluate color scale area */
+       if ((is_line_visible = go_style_is_line_visible (style))) {
+               line_width = gog_renderer_line_size (view->renderer, style->line.width);
+               tick_size = gog_renderer_pt2r (view->renderer, scale->tick_size);
+       } else
+               line_width = tick_size = 0.;
+       if (scale->horizontal) {
+               scale_area.x = view->allocation.x;
+               /* we make sure that we have enough room to display the last and first labels */
+               pos = (scale_area.w = view->allocation.w) - hf - hl;
+               stop = hl - pos * (max - last) / (max - min);
+               start = hf - pos * (first - min) / (max - min);
+               if (start < 0)
+                       start = 0.;
+               if (stop < 0.)
+                       stop = 0.;
+               /* we might actually remove slightly more than needed */
+               scale_area.w -= start + stop;
+               scale_area.x += gog_axis_is_inverted (scale->color_axis)? stop: start;
+               scale_area.y = (scale->axis_at_low)?
+                       view->allocation.y + view->allocation.h - width - 2 * line_width:
+                       view->allocation.y;
+               scale_area.h = width + 2 * line_width;
+       } else {
+               scale_area.x = (scale->axis_at_low)?
+                       view->allocation.x + view->allocation.w - width - 2 * line_width:
+                       view->allocation.x;
+               scale_area.w = width + 2 * line_width;
+               scale_area.y = view->allocation.y;
+               /* we make sure that we have enough room to display the last and first labels */
+               pos = (scale_area.h = view->allocation.h) - hf -hl;
+               stop = hl - pos * (max - last) / (max - min);
+               start = hf - pos * (first - min) / (max - min);
+               if (start < 0)
+                       start = 0.;
+               if (stop < 0.)
+                       stop = 0.;
+               /* we might actually remove slightly more than needed */
+               scale_area.h -= start + stop;
+               scale_area.y += gog_axis_is_inverted (scale->color_axis)? start: stop;
+       }
+
+       gog_renderer_stroke_rectangle (view->renderer, &scale_area);
+       scale_area.x += line_width / 2.;
+       scale_area.w -= line_width;
+       scale_area.y += line_width / 2.;
+       scale_area.h -= line_width;
+       if (scale->horizontal)
+               map = gog_axis_map_new (scale->color_axis, scale_area.x, scale_area.w);
+       else
+               map = gog_axis_map_new (scale->color_axis, scale_area.y + scale_area.h, -scale_area.h);
+       if (discrete) {
+               GOStyle *dstyle;
+               double *limits, epsilon, sc, *x, *w;
+               /* some of the code was copied from gog-contour.c to be consistent */
+               i = j = 0;
+               epsilon = (max - min) / nb_ticks * 1e-10; /* should avoid rounding errors */
+               while (ticks[i].type != GOG_AXIS_TICK_MAJOR)
+                       i++;
+               if (ticks[i].position - min > epsilon) {
+                       limits = g_new (double, nb_maj_ticks + 2);
+                       limits[j++] = min;
+               } else
+                       limits = g_new (double, nb_maj_ticks + 1);
+               for (; i < nb_ticks; i++)
+                       if (ticks[i].type == GOG_AXIS_TICK_MAJOR)
+                               limits[j++] = ticks[i].position;
+               if (j == 0 || max - limits[j - 1] > epsilon)
+                       limits[j] = max;
+               else
+                       j--;
+               sc = (j > gog_axis_color_map_get_max (cmap) && j > 1)? (double) gog_axis_color_map_get_max 
(cmap) / (j - 1): 1.;
+               dstyle = go_style_dup (style);
+               dstyle->interesting_fields = GO_STYLE_FILL | GO_STYLE_OUTLINE;
+               dstyle->fill.type = GO_STYLE_FILL_PATTERN;
+               dstyle->fill.pattern.pattern = GO_PATTERN_SOLID;
+               gog_renderer_push_style (view->renderer, dstyle);
+               /* using label_pos as drawing rectangle */
+               if (scale->horizontal) {
+                       x = &label_pos.x;
+                       w = &label_pos.w;
+                       label_pos.y = scale_area.y;
+                       label_pos.h = scale_area.h;
+               } else {
+                       x = &label_pos.y;
+                       w = &label_pos.h;
+                       label_pos.x = scale_area.x;
+                       label_pos.w = scale_area.w;
+               }
+               if (gog_axis_is_inverted (scale->color_axis)) {
+                       for (i = 0; i < j; i++) {
+                               dstyle->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: 
gog_axis_color_map_get_color (cmap, i * sc);
+                               *x = gog_axis_map_to_view (map, limits[j - i - 1]);
+                               *w = gog_axis_map_to_view (map, limits[j - i]) - *x;
+                               gog_renderer_fill_rectangle (view->renderer, &label_pos);
+                       }
+                       if (limits[i - j] - min > epsilon) {
+                               dstyle->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: 
gog_axis_color_map_get_color (cmap, i * sc);
+                               *x = gog_axis_map_to_view (map, min);
+                               *w = gog_axis_map_to_view (map, limits[i - j]) - *x;
+                               gog_renderer_fill_rectangle (view->renderer, &label_pos);
+                       }
+               } else {
+                       if (epsilon < limits[0] - min) {
+                               dstyle->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: 
gog_axis_color_map_get_color (cmap, 0);
+                               *x = gog_axis_map_to_view (map, min);
+                               *w = gog_axis_map_to_view (map, limits[0]) - *x;
+                               gog_renderer_fill_rectangle (view->renderer, &label_pos);
+                               i = 1;
+                               j++;
+                       } else
+                               i = 0;
+                       for (; i < j; i++) {
+                               dstyle->fill.pattern.back = (j < 2)? GO_COLOR_WHITE: 
gog_axis_color_map_get_color (cmap, i * sc);
+                               *x = gog_axis_map_to_view (map, limits[i]);
+                               *w = gog_axis_map_to_view (map, limits[i + 1]) - *x;
+                               gog_renderer_fill_rectangle (view->renderer, &label_pos);
+                       }
+               }
+               gog_renderer_pop_style (view->renderer);
+               g_free (limits);
+               g_object_unref (dstyle);
+       } else
+               gog_renderer_draw_color_map (view->renderer, cmap,
+                                            FALSE, scale->horizontal, &scale_area);
+       /* draw ticks */
+       if (scale->horizontal) {
+               if (scale->axis_at_low) {
+                       stop = scale_area.y - line_width;
+                       start = stop - tick_size;
+                       anchor = GO_ANCHOR_SOUTH;
+                       if (discrete)
+                               stop += scale_area.h;
+               } else {
+                       stop = scale_area.y + scale_area.h + line_width;
+                       start = stop + tick_size;
+                       anchor = GO_ANCHOR_NORTH;
+                       if (discrete)
+                               stop -= scale_area.h;
+               }
+               j = l = 0;
+               for (i = 0; i < nb_ticks; i++)
+                       /* Only major ticks are displayed, at least for now */
+                       if (ticks[i].type == GOG_AXIS_TICK_MAJOR) {
+                               pos = gog_axis_map_to_view (map, ticks[i].position);
+                               if (is_line_visible) { 
+                                       path = go_path_new ();
+                                       go_path_move_to (path, pos, start);
+                                       go_path_line_to (path, pos, stop);
+                                       gog_renderer_stroke_shape (view->renderer, path);
+                                       go_path_free (path);
+                               }
+                               label_pos.x = pos;
+                               label_pos.y = start + ((scale->axis_at_low)? -label_padding: label_padding);
+                               obrs[j].x = label_pos.x - obrs[j].w / 2.;
+                               obrs[j].y = pos;
+                               if (j == 0 || !go_geometry_test_OBR_overlap (obrs + j, obrs + l)) {
+                                       gog_renderer_draw_gostring (view->renderer, ticks[i].str,
+                                                                       &label_pos, anchor,
+                                                                           GTK_JUSTIFY_CENTER, -1.);
+                                       l = j;
+                               }
+                               j++;
+                       }
+       } else {
+               if (scale->axis_at_low) {
+                       stop = scale_area.x - line_width;
+                       start = stop - tick_size;
+                       anchor = GO_ANCHOR_EAST;
+                       if (discrete)
+                               stop += scale_area.w;
+               } else {
+                       stop = scale_area.x + scale_area.w + line_width;
+                       start = stop + tick_size;
+                       anchor = GO_ANCHOR_WEST;
+                       if (discrete)
+                               stop -= scale_area.w;
+               }
+               j = l = 0;
+               for (i = 0; i < nb_ticks; i++)
+                       /* Only major ticks are displayed, at least for now */
+                       if (ticks[i].type == GOG_AXIS_TICK_MAJOR) {
+                               pos = gog_axis_map_to_view (map, ticks[i].position);
+                               if (is_line_visible) { 
+                                       path = go_path_new ();
+                                       go_path_move_to (path, start, pos);
+                                       go_path_line_to (path, stop, pos);
+                                       gog_renderer_stroke_shape (view->renderer, path);
+                                       go_path_free (path);
+                               }
+                               label_pos.x = start + ((scale->axis_at_low)? -label_padding: label_padding);
+                               label_pos.y = pos;
+                               obrs[j].x = label_pos.x;
+                               obrs[j].y = pos - obrs[j].h / 2.;
+                               if (j == 0 || !go_geometry_test_OBR_overlap (obrs + j, obrs + l)) {
+                                       gog_renderer_draw_gostring (view->renderer, ticks[i].str,
+                                                                       &label_pos, anchor,
+                                                                           GTK_JUSTIFY_CENTER, -1.);
+                                       l = j;
+                               }
+                               j++;
+                       }
+       }
+       g_free (obrs);
+       gog_axis_map_free (map);
+       gog_renderer_pop_style (view->renderer);
 }
 
 static void
diff --git a/goffice/graph/gog-color-scale.h b/goffice/graph/gog-color-scale.h
index 7076f86..29d20e9 100644
--- a/goffice/graph/gog-color-scale.h
+++ b/goffice/graph/gog-color-scale.h
@@ -31,6 +31,8 @@ G_BEGIN_DECLS
 #define GOG_IS_COLOR_SCALE(o)  (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_TYPE_COLOR_SCALE))
 
 GType gog_color_scale_get_type (void);
+GogAxis *gog_color_scale_get_axis (GogColorScale *scale);
+void gog_color_scale_set_axis (GogColorScale *scale, GogAxis *axis);
 
 G_END_DECLS
 
diff --git a/goffice/graph/gog-object.c b/goffice/graph/gog-object.c
index 5c4594b..be0d188 100644
--- a/goffice/graph/gog-object.c
+++ b/goffice/graph/gog-object.c
@@ -187,6 +187,16 @@ static GogPositionFlagDesc const position_anchor[] = {
        {N_("Bottom right"),    "bottom-right", GOG_POSITION_ANCHOR_SE}
 };
 
+static GogPositionFlagDesc const manual_size[] = {
+       {N_("None"),                    "none",           GOG_POSITION_AUTO},
+       {N_("Width"),                   "width",          GOG_POSITION_MANUAL_W},
+       {N_("Absolute width"),  "abs-width",  GOG_POSITION_MANUAL_W_ABS},
+       {N_("Height"),                  "height",         GOG_POSITION_MANUAL_H},
+       {N_("Absolute height"), "abs-height", GOG_POSITION_MANUAL_H_ABS},
+       {N_("Size"),                    "size",           GOG_POSITION_MANUAL_W | GOG_POSITION_MANUAL_H},
+       {N_("Absolute size"),   "abs-size",       GOG_POSITION_MANUAL_W_ABS | GOG_POSITION_MANUAL_H_ABS}
+};
+
 enum {
        OBJECT_PROP_0,
        OBJECT_PROP_ID,
@@ -196,6 +206,7 @@ enum {
        OBJECT_PROP_POSITION_IS_MANUAL,
        OBJECT_PROP_POSITION_ANCHOR,
        OBJECT_PROP_INVISIBLE,
+       OBJECT_PROP_MANUAL_SIZE_MODE
 };
 
 enum {
@@ -320,6 +331,18 @@ gog_object_set_property (GObject *obj, guint param_id,
        case OBJECT_PROP_INVISIBLE :
                gog_object_set_invisible (gobj, g_value_get_boolean (value));
                break;
+       case OBJECT_PROP_MANUAL_SIZE_MODE:
+               str = g_value_get_string (value);
+               if (str == NULL)
+                       break;
+               for (id = 0; id < G_N_ELEMENTS (manual_size); id++)
+                       if (strcmp (str, manual_size[id].value) == 0)
+                               break;
+               if (id < G_N_ELEMENTS (manual_size))
+                       gog_object_set_position_flags (gobj,
+                                                      manual_size[id].flags,
+                                                      GOG_POSITION_ANY_MANUAL_SIZE);
+               break;
 
        default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
                 return; /* NOTE : RETURN */
@@ -382,6 +405,16 @@ gog_object_get_property (GObject *obj, guint param_id,
        case OBJECT_PROP_INVISIBLE :
                g_value_set_boolean (value, gobj->invisible != 0);
                break;
+       case OBJECT_PROP_MANUAL_SIZE_MODE:
+               flags = gog_object_get_position_flags (GOG_OBJECT (obj), GOG_POSITION_ANY_MANUAL_SIZE);
+               for (i = 0; i < G_N_ELEMENTS (manual_size); i++)
+                       if (manual_size[i].flags == flags) {
+                               g_value_set_string (value, manual_size[i].value);
+                               break;
+                       }
+                       if (i == G_N_ELEMENTS (manual_size))
+                               g_value_set_string (value, "none");
+               break;
 
        default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
                 break;
@@ -396,6 +429,7 @@ typedef struct {
        GogObject       *gobj;
        GtkBuilder      *gui;
        gulong           update_editor_handler;
+       gulong           h_sig, w_sig;
 } ObjectPrefState;
 
 static void
@@ -429,7 +463,7 @@ cb_position_changed (GtkWidget *spin, ObjectPrefState *state)
        GogViewAllocation pos;
        double value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin)) / 100.0;
 
-               gog_object_get_manual_position (state->gobj, &pos);
+    gog_object_get_manual_position (state->gobj, &pos);
        if (spin == state->x_spin)
                pos.x = value;
        else if (spin == state->y_spin)
@@ -492,14 +526,26 @@ cb_anchor_changed (GtkComboBox *combo, ObjectPrefState *state)
 static void
 cb_update_editor (GogObject *gobj, ObjectPrefState *state)
 {
+       GogObjectPosition manual_size = gog_object_get_position_flags (gobj, GOG_POSITION_ANY_MANUAL_SIZE);
+       gboolean visible;
        if (state->x_spin != NULL)
                gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->x_spin), gobj->manual_position.x * 100.0);
        if (state->y_spin != NULL)
                gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->y_spin), gobj->manual_position.y * 100.0);
-       if (state->w_spin != NULL)
+       if (state->w_spin != NULL) {
+               visible = manual_size & GOG_POSITION_MANUAL_W;
                gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->w_spin), gobj->manual_position.w * 100.0);
-       if (state->h_spin != NULL)
+               gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "width_label"), visible);
+               gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "width_spin"), visible);
+               gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "width-pc-lbl"), visible);
+       }
+       if (state->h_spin != NULL) {
+               visible = manual_size & GOG_POSITION_MANUAL_H;
                gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->h_spin), gobj->manual_position.h * 100.0);
+               gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "height_label"), visible);
+               gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "height_spin"), visible);
+               gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "height-pc-lbl"), visible);
+       }
 
        update_select_state (state);
 }
@@ -514,29 +560,32 @@ cb_chart_position_changed (GtkWidget *spin, ObjectPrefState *state)
 static void
 cb_manual_size_changed (GtkComboBox *combo, ObjectPrefState *state)
 {
-       if (gtk_combo_box_get_active (combo) == 1) {
-               if (state->w_spin) {
-                       gtk_widget_show (go_gtk_builder_get_widget (state->gui, "width_label"));
-                       gtk_widget_show (go_gtk_builder_get_widget (state->gui, "width_spin"));
-                       gtk_widget_show (go_gtk_builder_get_widget (state->gui, "width-pc-lbl"));
-               }
-               if (state->h_spin) {
-                       gtk_widget_show (go_gtk_builder_get_widget (state->gui, "height_label"));
-                       gtk_widget_show (go_gtk_builder_get_widget (state->gui, "height_spin"));
-                       gtk_widget_show (go_gtk_builder_get_widget (state->gui, "height-pc-lbl"));
-               }
-       } else {
-               if (state->w_spin) {
-                       gtk_widget_hide (go_gtk_builder_get_widget (state->gui, "width_label"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (state->gui, "width_spin"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (state->gui, "width-pc-lbl"));
-               }
-               if (state->h_spin) {
-                       gtk_widget_hide (go_gtk_builder_get_widget (state->gui, "height_label"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (state->gui, "height_spin"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (state->gui, "height-pc-lbl"));
+       int index = gtk_combo_box_get_active (combo);
+       GogObjectPosition pos = GOG_POSITION_AUTO;
+       gboolean visible;
+       if (index > 0)
+               switch (gog_object_get_manual_size_mode (state->gobj)) {
+               case GOG_MANUAL_SIZE_AUTO:
+                       break;
+               case GOG_MANUAL_SIZE_WIDTH:
+                       pos = GOG_POSITION_MANUAL_W;
+                       break;
+               case GOG_MANUAL_SIZE_HEIGHT:
+                       pos = GOG_POSITION_MANUAL_H;
+                       break;
+               case GOG_MANUAL_SIZE_FULL:
+                       pos = GOG_POSITION_MANUAL_W | GOG_POSITION_MANUAL_H;
+                       break;
                }
-       }
+       gog_object_set_position_flags (state->gobj, pos, GOG_POSITION_ANY_MANUAL_SIZE);
+       visible = pos & GOG_POSITION_MANUAL_W;
+       gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "width_label"), visible);
+       gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "width_spin"), visible);
+       gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "width-pc-lbl"), visible);
+       visible = pos & GOG_POSITION_MANUAL_H;
+       gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "height_label"), visible);
+       gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "height_spin"), visible);
+       gtk_widget_set_visible (go_gtk_builder_get_widget (state->gui, "height-pc-lbl"), visible);
 }
 
 static void
@@ -551,7 +600,6 @@ gog_object_populate_editor (GogObject *gobj,
        GogObjectPosition allowable_positions, flags;
        ObjectPrefState *state;
        unsigned i;
-       GogManualSizeMode size_mode = gog_object_get_manual_size_mode (gobj);
 
        if (gobj->role == NULL)
                return;
@@ -653,7 +701,7 @@ gog_object_populate_editor (GogObject *gobj,
 
        }
 
-       if (size_mode == GOG_MANUAL_SIZE_AUTO)  {
+       if (gog_object_get_manual_size_mode (gobj) == GOG_MANUAL_SIZE_AUTO)  {
                w = go_gtk_builder_get_widget (gui, "manual-sizes");
                gtk_widget_destroy (w);
                w = go_gtk_builder_get_widget (gui, "size-select-box");
@@ -665,38 +713,22 @@ gog_object_populate_editor (GogObject *gobj,
                                          manual_size? 1: 0);
                g_signal_connect (G_OBJECT (w),
                                  "changed", G_CALLBACK (cb_manual_size_changed), state);
-               if (size_mode & GOG_MANUAL_SIZE_WIDTH) {
-                       w = go_gtk_builder_get_widget (gui, "width_label");
-                       gtk_size_group_add_widget (label_size_group, w);
-                       w = go_gtk_builder_get_widget (gui, "width_spin");
-                       gtk_size_group_add_widget (widget_size_group, w);
-                       gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), gobj->manual_position.w * 100.0);
-                       g_signal_connect (G_OBJECT (w), "value-changed",
-                                         G_CALLBACK (cb_size_changed), state);
-                       state->w_spin = w;
-               }
-               if (!manual_size) {
-                       gtk_widget_hide (go_gtk_builder_get_widget (gui, "width_label"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (gui, "width_spin"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (gui, "width-pc-lbl"));
-               }
-
-               if (size_mode & GOG_MANUAL_SIZE_HEIGHT) {
-                       w = go_gtk_builder_get_widget (gui, "height_label");
-                       gtk_size_group_add_widget (label_size_group, w);
-                       w = go_gtk_builder_get_widget (gui, "height_spin");
-                       gtk_size_group_add_widget (widget_size_group, w);
-                       gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), gobj->manual_position.h * 100.0);
-                       g_signal_connect (G_OBJECT (w), "value-changed",
-                                         G_CALLBACK (cb_size_changed), state);
-                       state->h_spin = w;
-               }
-               if (!manual_size) {
-                       gtk_widget_hide (go_gtk_builder_get_widget (gui, "height_label"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (gui, "height_spin"));
-                       gtk_widget_hide (go_gtk_builder_get_widget (gui, "height-pc-lbl"));
-               }
+               w = go_gtk_builder_get_widget (gui, "width_label");
+               gtk_size_group_add_widget (label_size_group, w);
+               w = go_gtk_builder_get_widget (gui, "width_spin");
+               gtk_size_group_add_widget (widget_size_group, w);
+               g_signal_connect (G_OBJECT (w), "value-changed",
+                                 G_CALLBACK (cb_size_changed), state);
+               state->w_spin = w;
 
+               w = go_gtk_builder_get_widget (gui, "height_label");
+               gtk_size_group_add_widget (label_size_group, w);
+               w = go_gtk_builder_get_widget (gui, "height_spin");
+               gtk_size_group_add_widget (widget_size_group, w);
+               g_signal_connect (G_OBJECT (w), "value-changed",
+                                 G_CALLBACK (cb_size_changed), state);
+               state->h_spin = w;
+               cb_update_editor (gobj, state);
        }
 
        if (GOG_IS_CHART (gobj)) {
@@ -822,6 +854,12 @@ gog_object_class_init (GObjectClass *klass)
                        _("Should the object be hidden"),
                        FALSE,
                        GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+       g_object_class_install_property (klass, OBJECT_PROP_MANUAL_SIZE_MODE,
+               g_param_spec_string ("manual-size",
+                       _("Manual size"),
+                       _("Whether the height or width are manually set"),
+                       "none",
+                       GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 
        /**
         * GogObject::child-added:
@@ -1828,7 +1866,8 @@ gog_object_set_position_flags (GogObject *obj, GogObjectPosition flags, GogObjec
                return TRUE;
 
        if ((flags & obj->role->allowable_positions) !=
-           (flags & (GOG_POSITION_COMPASS | GOG_POSITION_ANY_MANUAL))) {
+           (flags & (GOG_POSITION_COMPASS | GOG_POSITION_ANY_MANUAL |
+                     GOG_POSITION_ANY_MANUAL_SIZE))) {
                g_warning ("[GogObject::set_position_flags] Invalid flags (%s)",
                           gog_object_get_name (obj));
                return FALSE;
diff --git a/goffice/graph/gog-renderer.c b/goffice/graph/gog-renderer.c
index 0fa5a68..bd768a0 100644
--- a/goffice/graph/gog-renderer.c
+++ b/goffice/graph/gog-renderer.c
@@ -1254,6 +1254,18 @@ _free_marker_data (GogRenderer *rend)
 }
 
 void
+gog_renderer_draw_color_map (GogRenderer *rend, GogAxisColorMap const *map,
+                             int discrete, gboolean horizontal,
+                             GogViewAllocation const *rect)
+{
+       cairo_save (rend->cairo);
+       cairo_translate (rend->cairo, rect->x, rect->y);
+       gog_axis_color_map_to_cairo (map, rend->cairo, discrete, horizontal,
+                                    rect->w, rect->h);
+       cairo_restore (rend->cairo);
+}
+
+void
 gog_renderer_push_style (GogRenderer *rend, GOStyle const *style)
 {
        g_return_if_fail (GOG_IS_RENDERER (rend));
diff --git a/goffice/graph/gog-renderer.h b/goffice/graph/gog-renderer.h
index 0b68e29..5b53755 100644
--- a/goffice/graph/gog-renderer.h
+++ b/goffice/graph/gog-renderer.h
@@ -106,6 +106,10 @@ void  gog_renderer_get_text_AABR  (GogRenderer *rend, char const *text,
                                   gboolean use_markup, GOGeometryAABR *aabr,
                                    double max_width);
 
+void  gog_renderer_draw_color_map      (GogRenderer *rend, GogAxisColorMap const *map,
+                                        int discrete, gboolean horizontal,
+                                        GogViewAllocation const *rect);
+
 void  gog_renderer_push_style          (GogRenderer *rend, GOStyle const *style);
 void  gog_renderer_pop_style           (GogRenderer *rend);
 
diff --git a/goffice/graph/gog-theme.c b/goffice/graph/gog-theme.c
index 41a44c0..06b009e 100644
--- a/goffice/graph/gog-theme.c
+++ b/goffice/graph/gog-theme.c
@@ -597,7 +597,8 @@ static GogThemeRoles roles[] = {
        {"GogSeriesLine", NULL, N_("Series lines"), GO_STYLE_LINE, SNAPSHOT_SERIESLINES},
        {"GogSeries", NULL, N_("Series"), GO_STYLE_LINE | GO_STYLE_FILL | GO_STYLE_MARKER, SNAPSHOT_SERIES},
        {"GogSeriesLabels", NULL, N_("Series labels"), GO_STYLE_OUTLINE | GO_STYLE_FILL | GO_STYLE_FONT | 
GO_STYLE_TEXT_LAYOUT, SNAPSHOT_SERIESLABELS},
-       {"GogDataLabel", NULL, N_("Data label"), GO_STYLE_OUTLINE | GO_STYLE_FILL | GO_STYLE_FONT | 
GO_STYLE_TEXT_LAYOUT, SNAPSHOT_SERIESLABELS}
+       {"GogDataLabel", NULL, N_("Data label"), GO_STYLE_OUTLINE | GO_STYLE_FILL | GO_STYLE_FONT | 
GO_STYLE_TEXT_LAYOUT, SNAPSHOT_SERIESLABELS},
+       {"GogColorScale", NULL, N_("Color scale"), GO_STYLE_OUTLINE, SNAPSHOT_GRAPH}
 };
 
 static void
@@ -1389,6 +1390,14 @@ build_predefined_themes (void)
        go_style_set_font_desc (style, pango_font_description_from_string ("Sans 6"));
        gog_theme_add_element (theme, style, NULL,  g_strdup ("GogDataLabel"), NULL);
 
+       /* Color scale */
+       style = go_style_new ();
+       go_style_clear_auto (style);
+       style->line.dash_type = GO_LINE_SOLID;
+       style->line.width = 0; /* hairline */
+       style->line.color = GO_COLOR_BLACK;
+       gog_theme_add_element (theme, style, NULL,  g_strdup ("GogColorScale"), NULL);
+
 #ifdef GOFFICE_WITH_LASEM
        /* Equations */
        style = go_style_new ();
@@ -1554,6 +1563,14 @@ build_predefined_themes (void)
        go_style_set_font_desc (style, pango_font_description_from_string ("Sans 6"));
        gog_theme_add_element (theme, style, NULL,  g_strdup ("GogDataLabel"), NULL);
 
+       /* Color scale */
+       style = go_style_new ();
+       go_style_clear_auto (style);
+       style->line.dash_type = GO_LINE_SOLID;
+       style->line.width = 0; /* hairline */
+       style->line.color = GO_COLOR_BLACK;
+       gog_theme_add_element (theme, style, NULL,  g_strdup ("GogColorScale"), NULL);
+
 #ifdef GOFFICE_WITH_LASEM
        /* Equations */
        style = go_style_new ();
diff --git a/goffice/graph/gog-view.c b/goffice/graph/gog-view.c
index e4f8264..a815a4b 100644
--- a/goffice/graph/gog-view.c
+++ b/goffice/graph/gog-view.c
@@ -545,7 +545,7 @@ gog_view_size_allocate_real (GogView *view, GogViewAllocation const *allocation)
        GogView *child;
        GogObjectPosition pos;
        GogViewRequisition req, available;
-       GogViewAllocation tmp, res = *allocation;
+       GogViewAllocation tmp, res = *allocation, align;
        double const pad_h = gog_renderer_pt2r_y (view->renderer, PAD_HACK);
        double const pad_w = gog_renderer_pt2r_x (view->renderer, PAD_HACK);
 
@@ -589,7 +589,8 @@ gog_view_size_allocate_real (GogView *view, GogViewAllocation const *allocation)
                                        req.h = 0;
                                tmp.h  = req.h;
                                vertical = FALSE;
-                       }
+                       }/* else
+                               tmp.h = req.h;*/
 
                                if (pos & GOG_POSITION_E) {
                                        if (req.w > 0) {
@@ -611,8 +612,14 @@ gog_view_size_allocate_real (GogView *view, GogViewAllocation const *allocation)
                                        /* For NE & NW only alignment fill makes sense */
                                        if (pos & (GOG_POSITION_N|GOG_POSITION_S))
                                                pos = GOG_POSITION_ALIGN_FILL;
-                               }
-
+                               }/* else
+                                       tmp.w = req.w;*/
+
+                               /* the following line adjust the manual sizes if needed */
+                               align = gog_object_get_manual_allocation (gog_view_get_model (child),
+                                                                         allocation, &req);
+                               req.h = align.h;
+                               req.w = align.w;
                                pos &= GOG_POSITION_ALIGNMENT;
                                if (GOG_POSITION_ALIGN_FILL != pos) {
                                        if (vertical) {
diff --git a/plugins/plot_surface/gog-contour.c b/plugins/plot_surface/gog-contour.c
index a406c12..5d03cbf 100644
--- a/plugins/plot_surface/gog-contour.c
+++ b/plugins/plot_surface/gog-contour.c
@@ -180,7 +180,7 @@ gog_contour_plot_foreach_elem  (GogPlot *plot, gboolean only_visible,
                for (i = 0; i < j; 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)? '[':']');
+                                               limits[j - i], (limits[j - i] - minimum > epsilon)? '[':']');
                        (func) (i, style, label, NULL, data);
                        g_free (label);
                }
diff --git a/plugins/plot_surface/gog-xyz-prefs.c b/plugins/plot_surface/gog-xyz-prefs.c
index 58532bd..4c5aa8d 100644
--- a/plugins/plot_surface/gog-xyz-prefs.c
+++ b/plugins/plot_surface/gog-xyz-prefs.c
@@ -21,6 +21,7 @@
 
 #include <goffice/goffice-config.h>
 #include "gog-xyz.h"
+#include "gog-contour.h"
 #include <goffice/gtk/goffice-gtk.h>
 #include <goffice/app/go-plugin.h>
 
@@ -34,6 +35,12 @@ cb_transpose (GtkToggleButton *btn, GObject *plot)
        g_object_set (plot, "transposed", gtk_toggle_button_get_active (btn), NULL);
 }
 
+static void
+cb_show_colors (GtkToggleButton *btn, GObject *plot)
+{
+       g_object_set (plot, "vary-style-by-element", gtk_toggle_button_get_active (btn), NULL);
+}
+
 GtkWidget *
 gog_xyz_plot_pref (GogXYZPlot *plot, GOCmdContext *cc)
 {
@@ -50,6 +57,14 @@ gog_xyz_plot_pref (GogXYZPlot *plot, GOCmdContext *cc)
                "toggled",
                G_CALLBACK (cb_transpose), plot);
 
+       w = go_gtk_builder_get_widget (gui, "colors");
+       if (GOG_IS_CONTOUR_PLOT (plot)) {
+               gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), plot->base.vary_style_by_element);
+               g_signal_connect (G_OBJECT (w), "toggled",
+                                 G_CALLBACK (cb_show_colors), plot);
+       } else
+               gtk_widget_hide (w);
+
        w = GTK_WIDGET (g_object_ref (gtk_builder_get_object (gui, "gog-xyz-prefs")));
        g_object_unref (gui);
 
diff --git a/plugins/plot_surface/gog-xyz-prefs.ui b/plugins/plot_surface/gog-xyz-prefs.ui
index d64c73a..9a6a058 100644
--- a/plugins/plot_surface/gog-xyz-prefs.ui
+++ b/plugins/plot_surface/gog-xyz-prefs.ui
@@ -8,7 +8,23 @@
     <property name="row_spacing">6</property>
     <property name="column_spacing">12</property>
     <child>
-      <placeholder/>
+      <object class="GtkCheckButton" id="transpose">
+        <property name="label" translatable="yes">Transpose</property>
+        <property name="use_action_appearance">False</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="use_action_appearance">False</property>
+        <property name="use_underline">True</property>
+        <property name="xalign">0</property>
+        <property name="draw_indicator">True</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>
       <placeholder/>
@@ -32,20 +48,19 @@
       <placeholder/>
     </child>
     <child>
-      <object class="GtkCheckButton" id="transpose">
-        <property name="label" translatable="yes">Transpose</property>
+      <object class="GtkCheckButton" id="colors">
+        <property name="label" translatable="yes">Show colors in legend</property>
         <property name="use_action_appearance">False</property>
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <property name="receives_default">False</property>
         <property name="use_action_appearance">False</property>
-        <property name="use_underline">True</property>
         <property name="xalign">0</property>
         <property name="draw_indicator">True</property>
       </object>
       <packing>
         <property name="left_attach">0</property>
-        <property name="top_attach">0</property>
+        <property name="top_attach">1</property>
         <property name="width">1</property>
         <property name="height">1</property>
       </packing>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]