[goffice] Allow custom ticks and grid lines for axis lines. [#600482]



commit a2f9414fc8671726ee2762fa4a6dadba9a1e8c12
Author: Jean Brefort <jean brefort normalesup org>
Date:   Thu Jan 8 15:34:59 2015 +0100

    Allow custom ticks and grid lines for axis lines. [#600482]

 ChangeLog                                |   10 +
 NEWS                                     |    2 +-
 docs/reference/goffice-0.10-sections.txt |    3 +
 goffice/canvas/goc-widget.c              |    2 +-
 goffice/graph/gog-axis-line.c            |  374 +++++++++++++++++-
 goffice/graph/gog-axis-line.h            |    8 +
 goffice/graph/gog-axis-prefs.ui          |  625 ++++++++++++++----------------
 goffice/graph/gog-axis.h                 |    6 -
 goffice/graph/gog-chart.c                |   16 +
 goffice/graph/gog-grid-line.c            |   17 +-
 10 files changed, 708 insertions(+), 355 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index e322c42..9ccab4c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2015-01-08  Jean Brefort  <jean brefort normalesup org>
+
+       * goffice/graph/gog-axis-line.c: allow custom ticks and grid lines for axis
+       lines. [#600482]
+       * goffice/graph/gog-axis-line.h: ditto.
+       * goffice/graph/gog-axis-prefs.ui: ditto.
+       * goffice/graph/gog-axis.h: ditto.
+       * goffice/graph/gog-chart.c: ditto.
+       * goffice/graph/gog-grid-line.c: ditto.
+
 2015-01-07  Jean Brefort  <jean brefort normalesup org>
 
        * goffice/graph/gog-axis.c: fix axis title position when at high coordinate.
diff --git a/NEWS b/NEWS
index 377f092..012786c 100644
--- a/NEWS
+++ b/NEWS
@@ -5,7 +5,7 @@ Jean:
        * Move the title with its axis parent. [#684777]
        * Implement canvas native scrolling. [#741394]
        * Don't use a data vector with no valid value. [#741910]
-
+       * Allow custom ticks and grid lines for axis lines. [#600482]
 Morten:
        * Dead kitten salvage.
        * Fix canvas issues when removing items.
diff --git a/docs/reference/goffice-0.10-sections.txt b/docs/reference/goffice-0.10-sections.txt
index e4853ee..94546e6 100644
--- a/docs/reference/goffice-0.10-sections.txt
+++ b/docs/reference/goffice-0.10-sections.txt
@@ -708,6 +708,7 @@ go_data_get_vector_markup
 go_data_get_vector_size
 go_data_get_vector_string
 go_data_get_vector_value
+go_data_has_value
 go_data_is_decreasing
 go_data_is_increasing
 go_data_is_valid
@@ -2774,6 +2775,7 @@ go_gtk_select_image_with_extra_widget
 go_gtk_url_is_writeable
 go_gtk_url_show
 go_gtk_widget_disable_focus
+go_gtk_widget_render_icon_pixbuf
 go_gtk_widget_replace
 go_gtk_window_set_transient
 go_gui_get_image_save_info
@@ -2900,6 +2902,7 @@ GogAxisPosition
 GogAxisTickTypes
 gog_axis_base_get_cross_location
 gog_axis_base_get_crossed_axis
+gog_axis_line_get_ticks
 <SUBSECTION Standard>
 GOG_AXIS_BASE
 GOG_AXIS_LINE
diff --git a/goffice/canvas/goc-widget.c b/goffice/canvas/goc-widget.c
index 835c1a5..23de5df 100644
--- a/goffice/canvas/goc-widget.c
+++ b/goffice/canvas/goc-widget.c
@@ -217,7 +217,7 @@ goc_offscreen_box_realize (GtkWidget *widget)
        window = gdk_window_new (gtk_widget_get_parent_window (widget),
                                 &attributes, attributes_mask);
        gtk_widget_set_window (widget, window);
-       if (gdk_screen_is_composited (gdk_window_get_screen (window))) 
+       if (gdk_screen_is_composited (gdk_window_get_screen (window)))
                gdk_window_set_composited (window, TRUE);
        gdk_window_set_user_data (window, widget);
 
diff --git a/goffice/graph/gog-axis-line.c b/goffice/graph/gog-axis-line.c
index 6c6b63b..f7e3be5 100644
--- a/goffice/graph/gog-axis-line.c
+++ b/goffice/graph/gog-axis-line.c
@@ -50,6 +50,8 @@
  * @GOG_AXIS_TICK_MINOR: minor tick.
  **/
 
+static unsigned gog_axis_base_get_ticks (GogAxisBase *axis_base, GogAxisTick **ticks);
+
 static GogViewClass *gab_view_parent_klass;
 static GObjectClass *gab_parent_klass;
 
@@ -1010,6 +1012,7 @@ axis_line_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
        double minor_tick_len, major_tick_len, tick_len;
        double padding = gog_axis_base_get_padding (axis_base);
        double label_size_max = 0;
+       double min, max;
        unsigned i, tick_nbr;
        gboolean is_line_visible;
 
@@ -1059,15 +1062,18 @@ axis_line_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
                go_geometry_AABR_add (&total_bbox, &bbox);
        }
 
-       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
 
        if (!draw_labels || tick_nbr < 1)
                return total_bbox;
 
        map = gog_axis_map_new (axis_base->axis, 0., axis_length);
+       gog_axis_map_get_real_bounds (map, &min, &max);
 
        obrs = g_new0 (GOGeometryOBR, tick_nbr);
        for (i = 0; i < tick_nbr; i++) {
+               if (ticks[i].position < min || ticks[i].position > max)
+                       continue;
                if (ticks[i].str != NULL) {
                        GOGeometryOBR *obr = obrs + i;
                        gog_renderer_get_gostring_OBR (renderer, ticks[i].str, obr, -1.);
@@ -1080,6 +1086,8 @@ axis_line_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
        }
 
        for (i = 0; i < tick_nbr; i++) {
+               if (ticks[i].position < min || ticks[i].position > max)
+                       continue;
                if (ticks[i].str != NULL) {
                        GOGeometryOBR *obr = obrs + i;
                        pos = gog_axis_map_to_view (map, ticks[i].position);
@@ -1126,6 +1134,7 @@ axis_line_render (GogAxisBase *axis_base,
        double padding = gog_axis_base_get_padding (axis_base);
        double label_size_max = 0;
        double s, e;
+       double min, max;
        unsigned i, tick_nbr, nobr = 0, *indexmap = NULL;
        gboolean draw_major, draw_minor;
        gboolean is_line_visible;
@@ -1155,6 +1164,7 @@ axis_line_render (GogAxisBase *axis_base,
        }
 
        map = gog_axis_map_new (axis_base->axis, 0., axis_length);
+       gog_axis_map_get_real_bounds (map, &min, &max);
 
        draw_major = axis_base->major.tick_in || axis_base->major.tick_out;
        draw_minor = axis_base->minor.tick_in || axis_base->minor.tick_out;
@@ -1176,11 +1186,13 @@ axis_line_render (GogAxisBase *axis_base,
        gog_renderer_get_text_OBR (renderer, "0", TRUE, &zero_obr, -1.);
        label_padding = zero_obr.h * .15;
 
-       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
        if (draw_labels) {
                obrs = g_new0 (GOGeometryOBR, tick_nbr);
                indexmap = g_new0 (unsigned int, tick_nbr);
                for (i = 0; i < tick_nbr; i++) {
+                       if (ticks[i].position < min || ticks[i].position > max)
+                               continue;
                        if (ticks[i].str != NULL) {
                                GOGeometryOBR *obr = obrs + i;
                                gog_renderer_get_gostring_OBR (renderer, ticks[i].str, obr, -1.);
@@ -1194,7 +1206,8 @@ axis_line_render (GogAxisBase *axis_base,
        }
 
        for (i = 0; i < tick_nbr; i++) {
-               if (gog_axis_map (map, ticks[i].position) < start_at)
+               if (gog_axis_map (map, ticks[i].position) < start_at ||
+                   ticks[i].position < min || ticks[i].position > max)
                        continue;
 
                if (ticks_pos) {
@@ -1347,7 +1360,7 @@ axis_circle_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
        map = gog_chart_map_get_axis_map (c_map, 1);
        gog_axis_map_get_extents (map, &offset , &position);
        map = gog_chart_map_get_axis_map (c_map, 0);
-       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
        for (i = 0; i < tick_nbr; i++) {
                angle = gog_axis_map_to_view (map, ticks[i].position);
                gog_chart_map_2D_to_view (c_map, ticks[i].position, position, &x, &y);
@@ -1423,7 +1436,7 @@ axis_circle_render (GogAxisBase *axis_base, GogRenderer *renderer,
        gog_renderer_get_text_OBR (renderer, "0", TRUE, &txt_obr, -1.);
        label_padding = txt_obr.h * .15;
 
-       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
        for (i = 0; i < tick_nbr; i++) {
                angle = gog_axis_map_to_view (map, ticks[i].position);
                if (is_line_visible) {
@@ -1942,7 +1955,7 @@ xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
                gog_chart_map_3d_to_view (c_map, xposition, yposition, stop,
                                          &bx, &by, NULL);
                if (action == GOG_AXIS_BASE_RENDER) {
-                       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+                       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
                        ticks_pos = g_new (double, 2 * tick_nbr);
                        for (i = 0; i < tick_nbr; i++)
                                gog_chart_map_3d_to_view (c_map, xposition,
@@ -1963,7 +1976,7 @@ xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
                gog_chart_map_3d_to_view (c_map, stop, yposition, zposition,
                                          &bx, &by, NULL);
                if (action == GOG_AXIS_BASE_RENDER) {
-                       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+                       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
                        ticks_pos = g_new (double, 2 * tick_nbr);
                        for (i = 0; i < tick_nbr; i++) {
                                gog_chart_map_3d_to_view (c_map,
@@ -1985,7 +1998,7 @@ xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
                gog_chart_map_3d_to_view (c_map, xposition, stop, zposition,
                                          &bx, &by, NULL);
                if (action == GOG_AXIS_BASE_RENDER) {
-                       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+                       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
                        ticks_pos = g_new (double, 2 * tick_nbr);
                        for (i = 0; i < tick_nbr; i++)
                                gog_chart_map_3d_to_view (c_map, xposition,
@@ -2067,7 +2080,7 @@ xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
                        tick_len = axis_base->major.tick_out ? major_tick_len :
                                (axis_base->minor.tick_out ? minor_tick_len : 0.);
 
-                       tick_nbr = gog_axis_get_ticks (axis_base->axis, &ticks);
+                       tick_nbr = gog_axis_base_get_ticks (axis_base, &ticks);
 
                        gog_renderer_get_text_OBR (view->renderer,
                                "0", TRUE, &obr, -1.);
@@ -2297,44 +2310,370 @@ GSF_CLASS (GogAxisBaseView, gog_axis_base_view,
           gog_axis_base_view_class_init, NULL,
           GOG_TYPE_VIEW)
 
+unsigned
+gog_axis_base_get_ticks (GogAxisBase *axis_base, GogAxisTick **ticks)
+{
+       g_return_val_if_fail (GOG_IS_AXIS_BASE (axis_base), 0);
+       g_return_val_if_fail (ticks != NULL, 0);
+
+       if (GOG_IS_AXIS_LINE (axis_base)) {
+               unsigned ret = gog_axis_line_get_ticks (GOG_AXIS_LINE (axis_base), ticks);
+               if (ret > 0)
+                       return ret;
+       }
+       return gog_axis_get_ticks (axis_base->axis, ticks);
+}
+
 /*****************************************************************************/
 /*****************************************************************************/
 /*****************************************************************************/
 
+/*
+ * Some fields are common to GogAxis and GogAxisLine, so they should go to
+ * the common base class when we have a new development branch
+ */
 struct _GogAxisLine {
-       GogAxisBase     base;
+       GogAxisBase       base;
+       GogDatasetElement custom_ticks[2];
+       GogAxisTick      *ticks;
+       unsigned          tick_nbr;
+       GOFormat         *format, *assigned_format;
+};
+
+
+enum {
+       AXIS_LINE_BASE_PROP_0,
+       AXIS_LINE_PROP_ASSIGNED_FORMAT_STR_XL
 };
 
 typedef GogAxisBaseClass GogAxisLineClass;
 
 static GObjectClass *gal_parent_klass;
 
+static GOFormat *
+gog_axis_line_get_effective_format (GogAxisLine const *line)
+{
+       if (line->assigned_format &&
+           !go_format_is_general (line->assigned_format))
+               return line->assigned_format;
+       return line->format;
+}
+
+static void
+axis_line_format_value (GogAxisLine *line, double val, GOString **str)
+{
+       GOFormat *fmt = gog_axis_line_get_effective_format (line);
+       GODateConventions const *date_conv = gog_axis_get_date_conv (line->base.axis);
+       GOFormatNumberError err;
+       PangoContext *context = pango_context_new ();
+       PangoLayout *layout = pango_layout_new (context);
+       g_object_unref (context);
+
+       g_return_if_fail (layout != NULL);
+
+       go_string_unref (*str);
+
+       err = go_format_value_gstring
+               (layout, NULL,
+                go_format_measure_strlen,
+                go_font_metrics_unit,
+                fmt,
+                val, 'F', NULL, NULL,
+                -1, date_conv, TRUE);
+       if (err)
+               *str = go_string_new ("#####");
+       else {
+               *str = go_string_new_rich
+                       (pango_layout_get_text (layout), -1,
+                        pango_attr_list_ref
+                        (pango_layout_get_attributes (layout)),
+                        NULL);
+               *str = go_string_trim (*str, TRUE);
+       }
+
+       g_object_unref (layout);
+}
+
+static void
+gog_axis_line_update_ticks (GogAxisLine *line)
+{
+       GODataVector *pos, *labels;
+       if (line->ticks != NULL) {
+               unsigned i;
+               for (i = 0; i < line->tick_nbr; i++)
+                       go_string_unref (line->ticks[i].str);
+
+               g_free (line->ticks);
+       }
+       line->ticks = NULL;
+       pos = GO_DATA_VECTOR (line->custom_ticks[0].data);
+       labels = GO_DATA_VECTOR (line->custom_ticks[1].data);
+       if (pos != NULL && go_data_has_value (GO_DATA (pos)) && go_data_is_varying_uniformly (GO_DATA (pos))) 
{
+               unsigned len = go_data_vector_get_len (pos), cur, i, labels_nb;
+               double val;
+               char *lbl;
+               line->ticks = g_new0 (GogAxisTick, len);
+               labels_nb = (labels)? go_data_vector_get_len (labels): 0;
+               for (cur = i = 0; i < len; i++) {
+                       val = go_data_vector_get_value (pos, i);
+                       if (!go_finite (val))
+                               continue;
+                       line->ticks[cur].position = val;
+                       if (i < labels_nb) {
+                               val = go_data_vector_get_value (labels, i);
+                               if (go_finite (val)) {
+                                       axis_line_format_value (line, val, &line->ticks[cur].str);
+                                       line->ticks[cur].type = GOG_AXIS_TICK_MAJOR;
+                               } else {
+                                       lbl = go_data_vector_get_str (labels, i);
+                                       if (lbl && *lbl) {
+                                               line->ticks[cur].str = go_string_new (lbl);
+                                               line->ticks[cur].type = GOG_AXIS_TICK_MAJOR;
+                                       } else
+                                               line->ticks[cur].type = GOG_AXIS_TICK_MINOR;
+                               }
+                       } else if (labels_nb == 0) {
+                                       line->ticks[cur].str = go_string_new (go_data_vector_get_str (pos, 
i));
+                                       line->ticks[cur].type = GOG_AXIS_TICK_MAJOR;
+                       } else
+                               line->ticks[cur].type = GOG_AXIS_TICK_MINOR;
+                       cur++;
+               }
+               line->tick_nbr = cur;
+       }
+}
+
+#ifdef GOFFICE_WITH_GTK
+
+static void
+cb_axis_line_fmt_changed (G_GNUC_UNUSED GtkWidget *widget,
+                    char *fmt,
+                    GogAxis *axis)
+{
+       g_object_set (axis, "assigned-format-string-XL", fmt, NULL);
+}
+
+static void
+gog_axis_line_populate_editor (GogObject *gobj,
+                              GOEditor *editor,
+                              GogDataAllocator *dalloc,
+                              GOCmdContext *cc)
+{
+       GogAxisLine *line = GOG_AXIS_LINE (gobj);
+       GogDataset *set = GOG_DATASET (gobj);
+       GogDataEditor *gde;
+       unsigned i;
+       GtkBuilder *gui;
+       GtkGrid *grid;
+
+       (GOG_OBJECT_CLASS(gal_parent_klass)->populate_editor) (gobj, editor, dalloc, cc);
+
+       gui = go_gtk_builder_load_internal ("res:go:graph/gog-axis-prefs.ui", GETTEXT_PACKAGE, cc);
+       if (gui == NULL)
+               return;
+
+       grid = GTK_GRID (gtk_builder_get_object (gui, "custom-ticks-grid"));
+       for (i = 1; i < 3; i++) {
+               gde = gog_data_allocator_editor (dalloc, set, GOG_AXIS_ELEM_CROSS_POINT + i, GOG_DATA_VECTOR);
+               g_object_set (G_OBJECT (gde), "hexpand", TRUE, NULL);
+               gtk_grid_attach (grid, GTK_WIDGET (gde), 1, i, 1, 1);
+       }
+       gtk_widget_show_all (GTK_WIDGET (grid));
+       go_editor_add_page (editor, grid, _("Ticks"));
+
+       /* Format page */
+    {
+           GOFormat *fmt = gog_axis_line_get_effective_format (line);
+           GtkWidget *w = go_format_sel_new_full (TRUE);
+
+           if (fmt)
+                   go_format_sel_set_style_format (GO_FORMAT_SEL (w),
+                                                   fmt);
+               gtk_widget_show (w);
+
+           go_editor_add_page (editor, w, _("Format"));
+
+           g_signal_connect (G_OBJECT (w),
+                   "format_changed", G_CALLBACK (cb_axis_line_fmt_changed), line);
+    }
+}
+#endif
+
+static void
+gog_axis_line_set_property (GObject *obj, guint param_id,
+                      GValue const *value, GParamSpec *pspec)
+{
+       GogAxisLine *line = GOG_AXIS_LINE (obj);
+
+       switch (param_id) {
+       case AXIS_LINE_PROP_ASSIGNED_FORMAT_STR_XL : {
+               char const *str = g_value_get_string (value);
+               GOFormat *newfmt = str ? go_format_new_from_XL (str) : NULL;
+               if (go_format_eq (newfmt, line->assigned_format))
+                       go_format_unref (newfmt);
+               else {
+                       go_format_unref (line->assigned_format);
+                       line->assigned_format = newfmt;
+               }
+               gog_axis_line_update_ticks (line);
+               gog_object_emit_changed (GOG_OBJECT (obj), TRUE);
+               break;
+       }
+
+       default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+               return; /* NOTE : RETURN */
+       }
+}
+
+static void
+gog_axis_line_get_property (GObject *obj, guint param_id,
+                      GValue *value, GParamSpec *pspec)
+{
+       GogAxisLine const *line = GOG_AXIS_LINE (obj);
+
+       switch (param_id) {
+       case AXIS_LINE_PROP_ASSIGNED_FORMAT_STR_XL :
+               if (line->assigned_format != NULL)
+                       g_value_set_string (value,
+                               go_format_as_XL (line->assigned_format));
+               else
+                       g_value_set_static_string (value, NULL);
+               break;
+
+       default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+                break;
+       }
+}
+
+static void
+gog_axis_line_finalize (GObject *obj)
+{
+       GogAxisLine *line = GOG_AXIS_LINE (obj);
+
+       if (line->ticks != NULL) {
+               unsigned i;
+               for (i = 0; i < line->tick_nbr; i++)
+                       go_string_unref (line->ticks[i].str);
+
+               g_free (line->ticks);
+       }
+       go_format_unref (line->assigned_format);
+       go_format_unref (line->format);
+
+       gog_dataset_finalize (GOG_DATASET (line));
+       (gal_parent_klass->finalize) (obj);
+}
+
+static GogGridLine *
+gog_axis_line_get_grid_line (GogAxisLine *line, gboolean major)
+{
+       GogGridLine *grid_line;
+       GSList *children;
+
+       children = gog_object_get_children (GOG_OBJECT (line),
+               gog_object_find_role_by_name (GOG_OBJECT (line),
+                       major ? "MajorGrid" : "MinorGrid"));
+       if (children != NULL) {
+               grid_line = GOG_GRID_LINE (children->data);
+               g_slist_free (children);
+               return grid_line;
+       }
+       return NULL;
+}
+
+static gboolean
+role_grid_line_major_can_add (GogObject const *parent)
+{
+       GogAxisLine *line = GOG_AXIS_LINE (parent);
+       GogAxis *axis = line->base.axis;
+       GogAxisType type = gog_axis_get_atype (axis);
+
+       return (!gog_axis_is_discrete (axis) &&
+               (type == GOG_AXIS_X || type == GOG_AXIS_Y || type == GOG_AXIS_Z ||
+                type == GOG_AXIS_RADIAL || type == GOG_AXIS_CIRCULAR) &&
+                gog_axis_line_get_grid_line (line, TRUE) == NULL);
+}
+
+static gboolean
+role_grid_line_minor_can_add (GogObject const *parent)
+{
+       GogAxisLine *line = GOG_AXIS_LINE (parent);
+       GogAxis *axis = line->base.axis;
+       GogAxisType type = gog_axis_get_atype (axis);
+
+       return (!gog_axis_is_discrete (axis) &&
+               (type == GOG_AXIS_X || type == GOG_AXIS_Y || type == GOG_AXIS_Z ||
+                type == GOG_AXIS_RADIAL || type == GOG_AXIS_CIRCULAR) &&
+                gog_axis_line_get_grid_line (line, FALSE) == NULL);
+}
+
+static void
+role_grid_line_major_post_add (GogObject *parent, GogObject *child)
+{
+       g_object_set (G_OBJECT (child), "is-minor", (gboolean)FALSE, NULL);
+}
+
+static void
+role_grid_line_minor_post_add (GogObject *parent, GogObject *child)
+{
+       g_object_set (G_OBJECT (child), "is-minor", (gboolean)TRUE, NULL);
+}
+
 static void
 gog_axis_line_class_init (GObjectClass *gobject_klass)
 {
+       static GogObjectRole const roles[] = {
+               { N_("MajorGrid"), "GogGridLine", 0,
+                 GOG_POSITION_SPECIAL, GOG_POSITION_SPECIAL, GOG_OBJECT_NAME_BY_ROLE,
+                 role_grid_line_major_can_add, NULL, NULL, role_grid_line_major_post_add, NULL, NULL, { -1 } 
},
+               { N_("MinorGrid"), "GogGridLine", 1,
+                 GOG_POSITION_SPECIAL, GOG_POSITION_SPECIAL, GOG_OBJECT_NAME_BY_ROLE,
+                 role_grid_line_minor_can_add, NULL, NULL, role_grid_line_minor_post_add, NULL, NULL, { -1 } 
},
+       };
+       GogObjectClass *gog_klass = (GogObjectClass *) gobject_klass;
+
        gal_parent_klass = g_type_class_peek_parent (gobject_klass);
+#ifdef GOFFICE_WITH_GTK
+       gog_klass->populate_editor      = gog_axis_line_populate_editor;
+#endif
+       gobject_klass->set_property = gog_axis_line_set_property;
+       gobject_klass->get_property = gog_axis_line_get_property;
+       gobject_klass->finalize = gog_axis_line_finalize;
+
+       gog_object_register_roles (gog_klass, roles, G_N_ELEMENTS (roles));
+
+       g_object_class_install_property (gobject_klass, AXIS_LINE_PROP_ASSIGNED_FORMAT_STR_XL,
+               g_param_spec_string ("assigned-format-string-XL",
+                       _("Assigned XL format"),
+                       _("The user assigned format to use for non-discrete axis labels (XL format)"),
+                       "General",
+                       GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 }
 
 static void
 gog_axis_line_dataset_dims (GogDataset const *set, int *first, int *last)
 {
        *first = GOG_AXIS_ELEM_CROSS_POINT;
-       *last  = GOG_AXIS_ELEM_CROSS_POINT;
+       *last  = GOG_AXIS_ELEM_CROSS_POINT + 2;
 }
 
 static GogDatasetElement *
 gog_axis_line_dataset_get_elem (GogDataset const *set, int dim_i)
 {
-       GogAxisBase *axis_base = GOG_AXIS_BASE (set);
+       GogAxisLine *line = GOG_AXIS_LINE (set);
 
-       g_return_val_if_fail (dim_i == GOG_AXIS_ELEM_CROSS_POINT, NULL);
+       g_return_val_if_fail (dim_i >= GOG_AXIS_ELEM_CROSS_POINT && dim_i <= GOG_AXIS_ELEM_CROSS_POINT + 2, 
NULL);
 
-       return &axis_base->cross_location;
+       return (dim_i == GOG_AXIS_ELEM_CROSS_POINT)?
+               &line->base.cross_location:
+               line->custom_ticks + dim_i - 1 - GOG_AXIS_ELEM_CROSS_POINT;
 }
 
 static void
 gog_axis_line_dim_changed (GogDataset *set, int dim_i)
 {
+       if (dim_i > GOG_AXIS_ELEM_CROSS_POINT)
+               gog_axis_line_update_ticks (GOG_AXIS_LINE (set));
        gog_object_emit_changed (GOG_OBJECT (set), TRUE);
 }
 
@@ -2350,3 +2689,10 @@ GSF_CLASS_FULL (GogAxisLine, gog_axis_line,
                NULL, NULL, gog_axis_line_class_init, NULL,
                NULL /*init*/, GOG_TYPE_AXIS_BASE, 0,
                GSF_INTERFACE (gog_axis_line_dataset_init, GOG_TYPE_DATASET))
+
+unsigned
+gog_axis_line_get_ticks (GogAxisLine *axis_line, GogAxisTick **ticks)
+{
+       *ticks = axis_line->ticks;
+       return axis_line->tick_nbr;
+}
diff --git a/goffice/graph/gog-axis-line.h b/goffice/graph/gog-axis-line.h
index 156e96c..d9faf2b 100644
--- a/goffice/graph/gog-axis-line.h
+++ b/goffice/graph/gog-axis-line.h
@@ -52,12 +52,20 @@ typedef enum {
        GOG_AXIS_TICK_MINOR
 } GogAxisTickTypes;
 
+typedef struct {
+       double           position;
+       GogAxisTickTypes type;
+       GOString        *str;
+} GogAxisTick;
+
 #define GOG_TYPE_AXIS_LINE     (gog_axis_line_get_type ())
 #define GOG_AXIS_LINE(o)       (G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_TYPE_AXIS_LINE, GogAxisLine))
 #define GOG_IS_AXIS_LINE(o)    (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_TYPE_AXIS_LINE))
 
 GType gog_axis_line_get_type (void);
 
+unsigned        gog_axis_line_get_ticks (GogAxisLine *axis_line, GogAxisTick **ticks);
+
 G_END_DECLS
 
 #endif /*GOG_AXIS_BASE_H*/
diff --git a/goffice/graph/gog-axis-prefs.ui b/goffice/graph/gog-axis-prefs.ui
index 5b74c56..86e31ec 100644
--- a/goffice/graph/gog-axis-prefs.ui
+++ b/goffice/graph/gog-axis-prefs.ui
@@ -1,105 +1,211 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
 <interface>
-  <!-- interface-requires gtk+ 3.0 -->
+  <requires lib="gtk+" version="3.0"/>
   <object class="GtkAdjustment" id="adjustment1">
     <property name="lower">-180</property>
     <property name="upper">180</property>
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
-  <object class="GtkAdjustment" id="adjustment2">
-    <property name="lower">-10000</property>
-    <property name="upper">10000</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-  </object>
-  <object class="GtkGrid" id="area-grid">
+  <object class="GtkGrid" id="axis-pref-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>
-      <object class="GtkLabel" id="label13">
+      <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">&lt;b&gt;Effective area&lt;/b&gt; (as % of available 
room)</property>
-        <property name="use_markup">True</property>
+        <property name="label" translatable="yes">Bounds</property>
+        <attributes>
+          <attribute name="weight" value="bold"/>
+        </attributes>
       </object>
       <packing>
         <property name="left_attach">0</property>
         <property name="top_attach">0</property>
-        <property name="width">3</property>
-        <property name="height">1</property>
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="label14">
+      <object class="GtkGrid" id="bound-grid">
         <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">Start:</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">12</property>
+        <child>
+          <object class="GtkLabel" id="label2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Automatic</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
       </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="GtkSpinButton" id="start-btn">
-        <property name="visible">True</property>
-        <property name="can_focus">True</property>
-        <property name="invisible_char">●</property>
-        <property name="invisible_char_set">True</property>
-        <property name="adjustment">start-adj</property>
-        <property name="digits">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>
-      <object class="GtkSpinButton" id="end-btn">
+      <object class="GtkGrid" id="grid1">
         <property name="visible">True</property>
-        <property name="can_focus">True</property>
-        <property name="invisible_char">●</property>
-        <property name="invisible_char_set">True</property>
-        <property name="adjustment">end-adj</property>
-        <property name="digits">1</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">12</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">12</property>
+        <child>
+          <object class="GtkComboBoxText" id="map-type-combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="map-label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">_Type:</property>
+            <property name="use_underline">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="invert-axis">
+            <property name="label" translatable="yes">_Invert axis</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_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">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="circular-grid">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">12</property>
+            <child>
+              <object class="GtkLabel" id="unit-lbl">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">_Unit:</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label9">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">_Rotation:</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSpinButton" id="circular-rotation-spinbutton">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">●</property>
+                <property name="adjustment">adjustment1</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBoxText" id="polar-unit-combo">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label10">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">degrees</property>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
       </object>
       <packing>
-        <property name="left_attach">1</property>
-        <property name="top_attach">2</property>
-        <property name="width">1</property>
-        <property name="height">1</property>
+        <property name="left_attach">0</property>
+        <property name="top_attach">3</property>
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="label15">
+      <object class="GtkLabel" id="label7">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="label" translatable="yes">End:</property>
+        <property name="margin_top">6</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Mapping</property>
+        <attributes>
+          <attribute name="weight" value="bold"/>
+        </attributes>
       </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/>
-    </child>
-    <child>
-      <placeholder/>
-    </child>
+  </object>
+  <object class="GtkAdjustment" id="adjustment2">
+    <property name="lower">-10000</property>
+    <property name="upper">10000</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
   </object>
   <object class="GtkGrid" id="axis-base-pref-grid">
     <property name="visible">True</property>
@@ -120,8 +226,6 @@
       <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>
@@ -132,7 +236,6 @@
         <property name="can_focus">True</property>
         <property name="receives_default">False</property>
         <property name="margin_left">12</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>
@@ -140,8 +243,6 @@
       <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>
@@ -152,7 +253,6 @@
         <property name="can_focus">True</property>
         <property name="receives_default">False</property>
         <property name="margin_left">12</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>
@@ -160,8 +260,6 @@
       <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>
@@ -172,7 +270,6 @@
         <property name="can_focus">True</property>
         <property name="receives_default">False</property>
         <property name="margin_left">12</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>
@@ -180,8 +277,6 @@
       <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>
@@ -204,8 +299,6 @@
           <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>
@@ -216,7 +309,6 @@
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="margin_left">12</property>
-            <property name="use_action_appearance">False</property>
             <property name="use_underline">True</property>
             <property name="xalign">0</property>
             <property name="active">True</property>
@@ -225,8 +317,6 @@
           <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>
@@ -238,7 +328,6 @@
             <property name="receives_default">False</property>
             <property name="valign">center</property>
             <property name="margin_left">12</property>
-            <property name="use_action_appearance">False</property>
             <property name="use_underline">True</property>
             <property name="xalign">0</property>
             <property name="active">True</property>
@@ -248,8 +337,6 @@
           <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>
@@ -266,7 +353,6 @@
                 <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="active">True</property>
@@ -276,8 +362,6 @@
               <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>
@@ -289,8 +373,6 @@
               <packing>
                 <property name="left_attach">2</property>
                 <property name="top_attach">0</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
               </packing>
             </child>
             <child>
@@ -301,16 +383,12 @@
               <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>
           </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>
@@ -329,8 +407,6 @@
               <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>
@@ -338,7 +414,6 @@
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="invisible_char">•</property>
-                <property name="invisible_char_set">True</property>
                 <property name="adjustment">adjustment2</property>
                 <property name="climb_rate">1</property>
                 <property name="numeric">True</property>
@@ -346,8 +421,6 @@
               <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>
@@ -359,16 +432,12 @@
               <packing>
                 <property name="left_attach">2</property>
                 <property name="top_attach">0</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
               </packing>
             </child>
           </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>
       </object>
@@ -376,7 +445,6 @@
         <property name="left_attach">0</property>
         <property name="top_attach">4</property>
         <property name="width">2</property>
-        <property name="height">1</property>
       </packing>
     </child>
     <child>
@@ -398,8 +466,6 @@
           <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>
@@ -410,7 +476,6 @@
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="margin_left">12</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>
@@ -418,8 +483,6 @@
           <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>
@@ -430,7 +493,6 @@
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="margin_left">12</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>
@@ -438,15 +500,12 @@
           <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>
       </object>
       <packing>
         <property name="left_attach">1</property>
         <property name="top_attach">0</property>
-        <property name="width">1</property>
         <property name="height">3</property>
       </packing>
     </child>
@@ -454,226 +513,6 @@
       <placeholder/>
     </child>
   </object>
-  <object class="GtkGrid" id="axis-pref-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>
-      <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">Bounds</property>
-        <attributes>
-          <attribute name="weight" value="bold"/>
-        </attributes>
-      </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="GtkGrid" id="bound-grid">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="margin_left">12</property>
-        <property name="row_spacing">6</property>
-        <property name="column_spacing">12</property>
-        <child>
-          <object class="GtkLabel" id="label2">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="xalign">0</property>
-            <property name="label" translatable="yes">Automatic</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>
-      </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="GtkGrid" id="grid1">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="margin_left">12</property>
-        <property name="row_spacing">6</property>
-        <property name="column_spacing">12</property>
-        <child>
-          <object class="GtkComboBoxText" id="map-type-combo">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="halign">start</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>
-          <object class="GtkLabel" id="map-label">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="halign">start</property>
-            <property name="xalign">0</property>
-            <property name="label" translatable="yes">_Type:</property>
-            <property name="use_underline">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>
-          <object class="GtkCheckButton" id="invert-axis">
-            <property name="label" translatable="yes">_Invert axis</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">2</property>
-            <property name="height">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkGrid" id="circular-grid">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="row_spacing">6</property>
-            <property name="column_spacing">12</property>
-            <child>
-              <object class="GtkLabel" id="unit-lbl">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">_Unit:</property>
-                <property name="use_underline">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>
-              <object class="GtkLabel" id="label9">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_Rotation:</property>
-                <property name="use_underline">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>
-              <object class="GtkSpinButton" id="circular-rotation-spinbutton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="invisible_char">●</property>
-                <property name="adjustment">adjustment1</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>
-              <object class="GtkComboBoxText" id="polar-unit-combo">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-              </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="GtkLabel" id="label10">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">degrees</property>
-              </object>
-              <packing>
-                <property name="left_attach">2</property>
-                <property name="top_attach">1</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
-              </packing>
-            </child>
-            <child>
-              <placeholder/>
-            </child>
-          </object>
-          <packing>
-            <property name="left_attach">0</property>
-            <property name="top_attach">2</property>
-            <property name="width">2</property>
-            <property name="height">1</property>
-          </packing>
-        </child>
-      </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="label7">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="margin_top">6</property>
-        <property name="xalign">0</property>
-        <property name="label" translatable="yes">Mapping</property>
-        <attributes>
-          <attribute name="weight" value="bold"/>
-        </attributes>
-      </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>
-  </object>
   <object class="GtkListStore" id="color-map-list">
     <columns>
       <!-- column-name Name -->
@@ -701,7 +540,6 @@
         <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>
@@ -713,8 +551,6 @@
       <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>
@@ -733,7 +569,6 @@
             <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>
@@ -751,7 +586,6 @@
             <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>
@@ -768,7 +602,6 @@
             <property name="receives_default">True</property>
             <property name="has_tooltip">True</property>
             <property name="tooltip_text" translatable="yes">Saves the color map to the local 
disk.</property>
-            <property name="use_action_appearance">False</property>
             <property name="image_position">right</property>
           </object>
           <packing>
@@ -781,8 +614,6 @@
       <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>
@@ -792,6 +623,65 @@
       <placeholder/>
     </child>
   </object>
+  <object class="GtkGrid" id="custom-ticks-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>
+      <object class="GtkLabel" id="label8">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Custom ticks</property>
+        <attributes>
+          <attribute name="weight" value="bold"/>
+        </attributes>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+        <property name="width">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label17">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">1</property>
+        <property name="label" translatable="yes">Positions:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label18">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">1</property>
+        <property name="label" translatable="yes">Labels:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+  </object>
   <object class="GtkAdjustment" id="end-adj">
     <property name="upper">100</property>
     <property name="value">100</property>
@@ -809,4 +699,81 @@
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
+  <object class="GtkGrid" id="area-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>
+      <object class="GtkLabel" id="label13">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">&lt;b&gt;Effective area&lt;/b&gt; (as % of available 
room)</property>
+        <property name="use_markup">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+        <property name="width">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label14">
+        <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">Start:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="start-btn">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">●</property>
+        <property name="adjustment">start-adj</property>
+        <property name="digits">1</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkSpinButton" id="end-btn">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">●</property>
+        <property name="adjustment">end-adj</property>
+        <property name="digits">1</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label15">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">End:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+  </object>
 </interface>
diff --git a/goffice/graph/gog-axis.h b/goffice/graph/gog-axis.h
index d2d107b..d58e603 100644
--- a/goffice/graph/gog-axis.h
+++ b/goffice/graph/gog-axis.h
@@ -51,12 +51,6 @@ typedef enum {
        GOG_AXIS_METRICS_MAX
 } GogAxisMetrics;
 
-typedef struct {
-       double           position;
-       GogAxisTickTypes type;
-       GOString        *str;
-} GogAxisTick;
-
 typedef struct _GogAxisMap GogAxisMap;
 
 GType            gog_axis_map_get_type (void);
diff --git a/goffice/graph/gog-chart.c b/goffice/graph/gog-chart.c
index 1977cc4..4a15553 100644
--- a/goffice/graph/gog-chart.c
+++ b/goffice/graph/gog-chart.c
@@ -1482,6 +1482,22 @@ grid_line_render (GSList *start_ptr, GogViewAllocation const *bbox)
                                                major_grid_lines = g_slist_prepend (major_grid_lines,
                                                                                    axis_child_view);
                                }
+                               else if (GOG_IS_AXIS_LINE (axis_child_view->model)) {
+                                       GogView *grid_child_view;
+                                       GSList *lptr;
+                                       for (lptr = axis_child_view->children; lptr != NULL; lptr = 
lptr->next) {
+                                               grid_child_view = lptr->data;
+                                       if (GOG_IS_GRID_LINE (grid_child_view->model)) {
+                                               if (gog_grid_line_is_minor (GOG_GRID_LINE 
(grid_child_view->model)))
+                                                       minor_grid_lines = g_slist_prepend (minor_grid_lines,
+                                                                                               
grid_child_view);
+                                               else
+                                                       major_grid_lines = g_slist_prepend (major_grid_lines,
+                                                                                               
grid_child_view);
+                               }
+
+                                       }
+                               }
                        }
                }
        }
diff --git a/goffice/graph/gog-grid-line.c b/goffice/graph/gog-grid-line.c
index 7adb2e8..b1fe62d 100644
--- a/goffice/graph/gog-grid-line.c
+++ b/goffice/graph/gog-grid-line.c
@@ -831,6 +831,7 @@ gog_grid_line_view_render (GogView *view, gboolean stripes)
 {
        GogGridLine *grid_line = GOG_GRID_LINE (view->model);
        GogAxis *axis;
+       GogAxisLine *line;
        GogChart *chart;
        GogView *chart_view;
        GOStyle *style;
@@ -839,16 +840,24 @@ gog_grid_line_view_render (GogView *view, gboolean stripes)
        unsigned tick_nbr;
        GogViewAllocation const *plot_area;
 
-       axis = GOG_AXIS (view->model->parent);
+       if (GOG_IS_AXIS_LINE (view->model->parent)) {
+               line = GOG_AXIS_LINE (view->model->parent);
+               axis = GOG_AXIS (view->model->parent->parent);
+       }
+       else {
+               line = NULL;
+               axis = GOG_AXIS (view->model->parent);
+       }
        g_return_if_fail (axis != NULL);
-       chart = GOG_CHART (view->model->parent->parent);
+       chart = GOG_CHART (GOG_OBJECT (axis)->parent);
        g_return_if_fail (chart != NULL);
        g_return_if_fail (view->parent != NULL);
-       chart_view = GOG_VIEW (view->parent->parent);
+       chart_view = GOG_VIEW ((line)? view->parent->parent->parent: view->parent->parent);
        g_return_if_fail (chart_view != NULL);
 
        axis_type = gog_axis_get_atype (axis);
-       tick_nbr = gog_axis_get_ticks (axis, &ticks);
+       tick_nbr = (line)? gog_axis_line_get_ticks (line, &ticks):
+                                          gog_axis_get_ticks (axis, &ticks);
        if (tick_nbr < 1)
                return;
 


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