[goffice] Add limits to the regression curve display range. [#669252]



commit df77465105df27abfe3d70348e639a8ed2993f65
Author: Jean Brefort <jean brefort normalesup org>
Date:   Fri Feb 10 15:34:22 2012 +0100

    Add limits to the regression curve display range. [#669252]

 ChangeLog                            |   15 +++
 NEWS                                 |    1 +
 goffice/canvas/goc-group.h           |    2 +-
 goffice/graph/gog-reg-curve-prefs.ui |  168 ++++++++++++++++++++++----
 goffice/graph/gog-reg-curve.c        |  215 +++++++++++++++++++++++++++++++---
 goffice/graph/gog-reg-curve.h        |   12 ++-
 goffice/utils/go-format.c            |   54 +++++-----
 goffice/utils/go-format.h            |    4 +-
 plugins/plot_distrib/gog-boxplot.c   |    2 +-
 plugins/reg_linear/gog-lin-reg.c     |    5 +-
 plugins/reg_linear/gog-polynom-reg.c |   16 +--
 11 files changed, 407 insertions(+), 87 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index ead3073..beed693 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2012-02-10  Jean Brefort  <jean brefort normalesup org>
+
+	* goffice/graph/gog-reg-curve-prefs.ui: add limits to the regression curve
+	display range. [#669252]
+	* goffice/graph/gog-reg-curve.c (limits_changed_cb),
+	(gog_reg_curve_populate_editor), (gog_reg_curve_get_property),
+	(gog_reg_curve_set_property), (gog_reg_curve_class_init),
+	(gog_reg_curve_init), (gog_reg_curve_dataset_dims),
+	(gog_reg_curve_dataset_get_elem), (gog_reg_curve_view_render): ditto.
+	* goffice/graph/gog-reg-curve.h: ditto.
+	* plugins/reg_linear/gog-lin-reg.c
+	(gog_lin_reg_curve_populate_editor): ditto.
+	* plugins/reg_linear/gog-polynom-reg.c
+	(gog_polynom_reg_curve_populate_editor): ditto.
+
 2012-02-07  Jean Brefort  <jean brefort normalesup org>
 
 	* goffice/graph/gog-renderer.c (gog_renderer_draw_gostring): take subscript
diff --git a/NEWS b/NEWS
index d388650..ce0fef2 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,7 @@ Jean:
 	* Fixed graph type selector position. [#667793]
 	* Fix bounds for partial range logarithmic axes. [#669257]
 	* Fix Y-axis label position. [#669325]
+	* Add limits to the regression curve display range. [#669252]
 
 Morten:
 	* Embed library ui files into library.
diff --git a/goffice/canvas/goc-group.h b/goffice/canvas/goc-group.h
index 15a1434..f786293 100644
--- a/goffice/canvas/goc-group.h
+++ b/goffice/canvas/goc-group.h
@@ -47,7 +47,7 @@ struct _GocGroupClass
 	void (*reserved2) (void);
 	void (*reserved3) (void);
 	void (*reserved4) (void);
-};																																																																																																																																																																								
+};
 
 #define GOC_TYPE_GROUP	(goc_group_get_type ())
 #define GOC_GROUP(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_GROUP, GocGroup))
diff --git a/goffice/graph/gog-reg-curve-prefs.ui b/goffice/graph/gog-reg-curve-prefs.ui
index 1e2e497..77408ed 100644
--- a/goffice/graph/gog-reg-curve-prefs.ui
+++ b/goffice/graph/gog-reg-curve-prefs.ui
@@ -1,78 +1,194 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 3.0 -->
-  <!-- interface-naming-policy toplevel-contextual -->
-  <object class="GtkTable" id="reg-curve-prefs">
+  <object class="GtkGrid" id="reg-curve-prefs">
     <property name="visible">True</property>
+    <property name="can_focus">False</property>
     <property name="border_width">12</property>
-    <property name="n_rows">4</property>
-    <property name="n_columns">2</property>
-    <property name="column_spacing">12</property>
     <property name="row_spacing">6</property>
+    <property name="column_spacing">12</property>
+    <child>
+      <object class="GtkLabel" id="name-label">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">(_Name):</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="label1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">12</property>
         <property name="xalign">0</property>
         <property name="xpad">5</property>
         <property name="label" translatable="yes">Low bound:</property>
       </object>
       <packing>
-        <property name="top_attach">1</property>
-        <property name="bottom_attach">2</property>
-        <property name="x_options">GTK_FILL</property>
-        <property name="y_options"></property>
+        <property name="left_attach">0</property>
+        <property name="top_attach">2</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
       </packing>
     </child>
     <child>
       <object class="GtkLabel" id="label2">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">12</property>
         <property name="xalign">0</property>
         <property name="xpad">5</property>
         <property name="label" translatable="yes">High bound:</property>
       </object>
       <packing>
-        <property name="top_attach">2</property>
-        <property name="bottom_attach">3</property>
-        <property name="x_options">GTK_FILL</property>
-        <property name="y_options"></property>
+        <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="GtkCheckButton" id="skip-invalid">
         <property name="label" translatable="yes">Skip invalid data</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="margin_left">12</property>
+        <property name="margin_bottom">6</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="right_attach">2</property>
-        <property name="top_attach">3</property>
-        <property name="bottom_attach">4</property>
-        <property name="x_options">GTK_FILL</property>
-        <property name="y_options"></property>
+        <property name="left_attach">0</property>
+        <property name="top_attach">4</property>
+        <property name="width">3</property>
+        <property name="height">1</property>
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="name-label">
+      <object class="GtkLabel" id="label3">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="xalign">0</property>
-        <property name="label" translatable="yes">(_Name):</property>
-        <property name="use_underline">True</property>
+        <property name="label" translatable="yes">&lt;b&gt;Used data&lt;/b&gt;</property>
+        <property name="use_markup">True</property>
       </object>
       <packing>
-        <property name="y_options"></property>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+        <property name="width">3</property>
+        <property name="height">1</property>
       </packing>
     </child>
     <child>
-      <placeholder/>
+      <object class="GtkLabel" id="label4">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">&lt;b&gt;Drawing Limits:&lt;/b&gt;</property>
+        <property name="use_markup">True</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">5</property>
+        <property name="width">2</property>
+        <property name="height">1</property>
+      </packing>
     </child>
     <child>
-      <placeholder/>
+      <object class="GtkComboBoxText" id="draw-limits-box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="has_tooltip">True</property>
+        <property name="tooltip_markup" translatable="yes">None: the line will be displayed for the whole visible range.
+Absolute: the line will be displayed between the given limits.
+Relative: the line will be displayed between the data range expanded according to the values given below.</property>
+        <property name="tooltip_text" translatable="yes">None: the line will be displayed for the whole visible range.
+Absolute: the line will be displayed between the given limits.
+Relative: the line will be displayed between the data range expanded according to the values given below, with positive values enlarging the range.</property>
+        <items>
+          <item translatable="yes">None</item>
+          <item translatable="yes">Absolute</item>
+          <item translatable="yes">Relative</item>
+        </items>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="top_attach">5</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="low-lbl">
+        <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">Low limit:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">6</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="high-lbl">
+        <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">High limit:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">7</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="first-lbl">
+        <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">Low span:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">6</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
     </child>
     <child>
-      <placeholder/>
+      <object class="GtkLabel" id="last-lbl">
+        <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">High span:</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">7</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
     </child>
+
   </object>
 </interface>
diff --git a/goffice/graph/gog-reg-curve.c b/goffice/graph/gog-reg-curve.c
index a93f840..dce4e35 100644
--- a/goffice/graph/gog-reg-curve.c
+++ b/goffice/graph/gog-reg-curve.c
@@ -34,6 +34,7 @@ static GType gog_reg_curve_view_get_type (void);
 enum {
 	REG_CURVE_PROP_0,
 	REG_CURVE_PROP_SKIP_INVALID,
+	REG_CURVE_PROP_DRAWING_BOUNDS
 };
 
 static void
@@ -45,12 +46,53 @@ gog_reg_curve_init_style (GogStyledObject *gso, GOStyle *style)
 }
 
 #ifdef GOFFICE_WITH_GTK
+
+struct reg_curve_closure {
+	GtkWidget *al1, *al2, *rl1, *rl2, *fe1, *fe2;
+	GObject *rc;
+};
+
 static void
 skip_invalid_toggled_cb (GtkToggleButton* btn, GObject *obj)
 {
 	g_object_set (obj, "skip-invalid", gtk_toggle_button_get_active (btn), NULL);
 }
 
+
+static void
+limits_changed_cb (GtkComboBox* btn, struct reg_curve_closure *cl)
+{
+	GogRegCurveDrawingBounds db = gtk_combo_box_get_active (btn);
+	switch (db) {
+	case GOG_REG_CURVE_DRAWING_BOUNDS_NONE:
+		gtk_widget_hide (cl->al1);
+		gtk_widget_hide (cl->al2);
+		gtk_widget_hide (cl->rl1);
+		gtk_widget_hide (cl->rl2);
+		gtk_widget_hide (cl->fe1);
+		gtk_widget_hide (cl->fe2);
+		break;
+	case GOG_REG_CURVE_DRAWING_BOUNDS_ABSOLUTE:
+		gtk_widget_show (cl->al1);
+		gtk_widget_show (cl->al2);
+		gtk_widget_hide (cl->rl1);
+		gtk_widget_hide (cl->rl2);
+		gtk_widget_show (cl->fe1);
+		gtk_widget_show (cl->fe2);
+		break;
+	case GOG_REG_CURVE_DRAWING_BOUNDS_RELATIVE:
+		gtk_widget_hide (cl->al1);
+		gtk_widget_hide (cl->al2);
+		gtk_widget_show (cl->rl1);
+		gtk_widget_show (cl->rl2);
+		gtk_widget_show (cl->fe1);
+		gtk_widget_show (cl->fe2);
+		break;
+	}
+	GOG_REG_CURVE (cl->rc)->drawing_bounds = db;
+	gog_object_emit_changed (GOG_OBJECT (cl->rc), FALSE);
+}
+
 static void
 gog_reg_curve_populate_editor (GogObject	*gobj,
 			       GOEditor	*editor,
@@ -58,9 +100,11 @@ gog_reg_curve_populate_editor (GogObject	*gobj,
 			       GOCmdContext	*cc)
 {
 	GtkWidget *w;
-	GtkTable *table;
+	GtkGrid *grid;
 	GtkBuilder *gui;
 	GogDataset *set = GOG_DATASET (gobj);
+	struct reg_curve_closure *cl;
+	GogRegCurveDrawingBounds db = GOG_REG_CURVE (gobj)->drawing_bounds;
 
 	gui = go_gtk_builder_new_internal ("res:go:graph/gog-reg-curve-prefs.ui", GETTEXT_PACKAGE, cc);
 	if (gui == NULL)
@@ -70,24 +114,59 @@ gog_reg_curve_populate_editor (GogObject	*gobj,
 			     go_gtk_builder_get_widget (gui, "reg-curve-prefs"),
 			     _("Details"));
 
-	table = GTK_TABLE (gtk_builder_get_object (gui, "reg-curve-prefs"));
+	cl = g_new0 (struct reg_curve_closure, 1);
+	cl->rc = G_OBJECT (gobj);
+	grid = GTK_GRID (gtk_builder_get_object (gui, "reg-curve-prefs"));
 	w = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, -1, GOG_DATA_SCALAR));
 	gtk_widget_show (w);
-	gtk_table_attach (table, w, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_grid_attach (grid, w, 1, 0, 2, 1);
 	w = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 0, GOG_DATA_SCALAR));
 	gtk_widget_show (w);
-	gtk_table_attach (table, w, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_grid_attach (grid, w, 1, 2, 2, 1);
 	w = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 1, GOG_DATA_SCALAR));
 	gtk_widget_show (w);
-	gtk_table_attach (table, w, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_grid_attach (grid, w, 1, 3, 2, 1);
 	w = go_gtk_builder_get_widget (gui, "skip-invalid");
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
 					(GOG_REG_CURVE (gobj))->skip_invalid);
 	g_signal_connect (G_OBJECT (w), "toggled",
 		G_CALLBACK (skip_invalid_toggled_cb), gobj);
+	cl->fe1 = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 2, GOG_DATA_SCALAR));
+	gtk_grid_attach (grid, cl->fe1, 1, 6, 2, 1);
+	cl->fe2 = GTK_WIDGET (gog_data_allocator_editor (dalloc, set, 3, GOG_DATA_SCALAR));
+	gtk_grid_attach (grid, cl->fe2, 1, 7, 2, 1);
+	cl->al1 = go_gtk_builder_get_widget (gui, "low-lbl");
+	cl->al2 = go_gtk_builder_get_widget (gui, "high-lbl");
+	cl->rl1 = go_gtk_builder_get_widget (gui, "first-lbl");
+	cl->rl2 = go_gtk_builder_get_widget (gui, "last-lbl");
+	switch (db) {
+	case GOG_REG_CURVE_DRAWING_BOUNDS_NONE:
+		gtk_widget_hide (cl->al1);
+		gtk_widget_hide (cl->al2);
+		gtk_widget_hide (cl->rl1);
+		gtk_widget_hide (cl->rl2);
+		break;
+	case GOG_REG_CURVE_DRAWING_BOUNDS_ABSOLUTE:
+		gtk_widget_hide (cl->rl1);
+		gtk_widget_hide (cl->rl2);
+		gtk_widget_show (cl->fe1);
+		gtk_widget_show (cl->fe2);
+		break;
+	case GOG_REG_CURVE_DRAWING_BOUNDS_RELATIVE:
+		gtk_widget_hide (cl->al1);
+		gtk_widget_hide (cl->al2);
+		gtk_widget_show (cl->fe1);
+		gtk_widget_show (cl->fe2);
+		break;
+	}
+	w = go_gtk_builder_get_widget (gui, "draw-limits-box");
+	gtk_combo_box_set_active (GTK_COMBO_BOX (w), db);
+	g_signal_connect (G_OBJECT (w), "changed",
+		G_CALLBACK (limits_changed_cb), cl);
 	if ((GOG_REG_CURVE_GET_CLASS (gobj))->populate_editor != NULL)
-		(GOG_REG_CURVE_GET_CLASS (gobj))->populate_editor (GOG_REG_CURVE (gobj), table);
+		(GOG_REG_CURVE_GET_CLASS (gobj))->populate_editor (GOG_REG_CURVE (gobj), grid);
 
+	g_object_set_data_full (G_OBJECT (grid), "rc-closure", cl, g_free);
 	g_object_unref (gui);
 
 	(GOG_OBJECT_CLASS (reg_curve_parent_klass)->populate_editor) (gobj, editor, dalloc, cc);
@@ -103,10 +182,24 @@ gog_reg_curve_get_property (GObject *obj, guint param_id,
 	case REG_CURVE_PROP_SKIP_INVALID:
 		g_value_set_boolean (value, rc->skip_invalid);
 		break;
+	case REG_CURVE_PROP_DRAWING_BOUNDS:
+		switch (rc->drawing_bounds) {
+		case GOG_REG_CURVE_DRAWING_BOUNDS_NONE:
+			g_value_set_string (value, "none");
+			break;
+		case GOG_REG_CURVE_DRAWING_BOUNDS_ABSOLUTE:
+			g_value_set_string (value, "absolute");
+			break;
+		case GOG_REG_CURVE_DRAWING_BOUNDS_RELATIVE:
+			g_value_set_string (value, "relative");
+			break;
+		}
+		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
 		 break;
 	}
+	gog_object_emit_changed (GOG_OBJECT (rc), FALSE);
 }
 
 static void
@@ -119,6 +212,17 @@ gog_reg_curve_set_property (GObject *obj, guint param_id,
 		rc->skip_invalid = g_value_get_boolean (value);
 		gog_object_request_update (GOG_OBJECT (obj));
 		break;
+	case REG_CURVE_PROP_DRAWING_BOUNDS: {
+		char const *str = g_value_get_string (value);
+		if (!strcmp (str, "absolute"))
+			rc->drawing_bounds = GOG_REG_CURVE_DRAWING_BOUNDS_ABSOLUTE;
+		else if (!strcmp (str, "relative"))
+			rc->drawing_bounds = GOG_REG_CURVE_DRAWING_BOUNDS_RELATIVE;
+		else
+			rc->drawing_bounds = GOG_REG_CURVE_DRAWING_BOUNDS_NONE;
+		gog_object_emit_changed (GOG_OBJECT (rc), FALSE);
+		break;
+	}
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
 		 return; /* NOTE : RETURN */
@@ -183,27 +287,33 @@ gog_reg_curve_class_init (GogObjectClass *gog_klass)
 			_("Skip invalid data"),
 			FALSE,
 			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+	g_object_class_install_property (gobject_klass, REG_CURVE_PROP_DRAWING_BOUNDS,
+		g_param_spec_string ("drawing-bounds",
+			_("Drawing bounds"),
+			_("How the regression line should be limited, acceptable values are \"none\", \"absolute\", and \"relative\"."),
+			"none",
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
 }
 
 static void
 gog_reg_curve_init (GogRegCurve *reg_curve)
 {
 	reg_curve->ninterp = 100;
-	reg_curve->bounds = g_new0 (GogDatasetElement,3) + 1;
+	reg_curve->bounds = g_new0 (GogDatasetElement,5) + 1;
 }
 
 static void
 gog_reg_curve_dataset_dims (GogDataset const *set, int *first, int *last)
 {
 	*first = -1;
-	*last = 1;
+	*last = 3;
 }
 
 static GogDatasetElement *
 gog_reg_curve_dataset_get_elem (GogDataset const *set, int dim_i)
 {
 	GogRegCurve const *rc = GOG_REG_CURVE (set);
-	g_return_val_if_fail (2 > dim_i, NULL);
+	g_return_val_if_fail (4 > dim_i, NULL);
 	g_return_val_if_fail (dim_i >= -1, NULL);
 	return rc->bounds + dim_i;
 }
@@ -287,7 +397,7 @@ gog_reg_curve_view_render (GogView *view, GogViewAllocation const *bbox)
 	GogSeries *series = GOG_SERIES ((GOG_OBJECT (rc))->parent);
 	GogPlot *plot = series->plot;
 	GogChart *chart = GOG_CHART (GOG_OBJECT (plot)->parent);
-	GogAxisMap *x_map, *y_map;
+	GogAxisMap *x_map;
 	GogChartMap *chart_map;
 	GOStyle *style;
 	GOPath *path;
@@ -306,17 +416,92 @@ gog_reg_curve_view_render (GogView *view, GogViewAllocation const *bbox)
 	}
 
 	x_map = gog_chart_map_get_axis_map (chart_map, 0);
-	y_map = gog_chart_map_get_axis_map (chart_map, 1);
 
 	gog_renderer_push_clip_rectangle (view->renderer, view->residual.x, view->residual.y,
 					  view->residual.w, view->residual.h);
 
 	x = g_new (double, rc->ninterp + 1);
 	y = g_new (double, rc->ninterp + 1);
-	delta_x = view->residual.w / rc->ninterp;
-	for (i = 0; i <= rc->ninterp; i++) {
-		x[i] = gog_axis_map_from_view (x_map, i * delta_x + view->residual.x);
-		y[i] = gog_reg_curve_get_value_at (rc, x[i]);
+	switch (rc->drawing_bounds) {
+	case GOG_REG_CURVE_DRAWING_BOUNDS_NONE:
+		delta_x = view->residual.w / rc->ninterp;
+		for (i = 0; i <= rc->ninterp; i++) {
+			x[i] = gog_axis_map_from_view (x_map, i * delta_x + view->residual.x);
+			y[i] = gog_reg_curve_get_value_at (rc, x[i]);
+		}
+		break;
+	case GOG_REG_CURVE_DRAWING_BOUNDS_ABSOLUTE: {
+		double min, max;
+		if (rc->bounds[2].data) {
+			min = go_data_get_scalar_value (rc->bounds[2].data);
+			if (min == go_nan || !go_finite (min))
+				min = gog_axis_map_from_view (x_map, view->residual.x);
+
+		} else
+			min = gog_axis_map_from_view (x_map, view->residual.x);
+		if (rc->bounds[3].data) {
+			max = go_data_get_scalar_value (rc->bounds[3].data);
+			if (max == go_nan || !go_finite (max))
+				max = gog_axis_map_from_view (x_map, view->residual.x + view->residual.w);
+
+		} else
+			max = gog_axis_map_from_view (x_map, view->residual.x + view->residual.w);
+
+		delta_x = (max - min) / rc->ninterp;
+		for (i = 0; i <= rc->ninterp; i++) {
+			x[i] = min + i * delta_x;
+			y[i] = gog_reg_curve_get_value_at (rc, x[i]);
+		}
+		break;
+	}
+	case GOG_REG_CURVE_DRAWING_BOUNDS_RELATIVE: {
+		double min, max, val;
+		GOData *data = NULL;
+		GogSeries *series = GOG_SERIES (gog_object_get_parent (GOG_OBJECT (rc)));
+		GogSeriesDesc *desc = &GOG_PLOT_GET_CLASS (series->plot)->desc.series;
+		int i;
+		/* first, look for the index values */
+		for (i = 0; i < (int) desc->num_dim; i++)
+			if (desc->dim[i].val_type == GOG_DIM_INDEX) {
+				data = series->values[i].data;
+				break;
+			}
+		if (data)
+			go_data_get_bounds (data, &min, &max);
+		else {
+			min = 0.;
+			max = series->num_elements - 1;
+		}
+		if (rc->bounds[0].data) {
+			val = go_data_get_scalar_value (rc->bounds[0].data);
+			if (val != go_nan && go_finite (val))
+				min = val;
+		}
+		if (rc->bounds[1].data) {
+			val = go_data_get_scalar_value (rc->bounds[1].data);
+			if (val != go_nan && go_finite (val))
+				max = val;
+		}
+		if (rc->bounds[2].data) {
+			val = go_data_get_scalar_value (rc->bounds[2].data);
+			if (val != go_nan && go_finite (val))
+				min -= val;
+
+		}
+		if (rc->bounds[3].data) {
+			val = go_data_get_scalar_value (rc->bounds[3].data);
+			if (val != go_nan && go_finite (val))
+				max += val;
+
+		}
+
+		delta_x = (max - min) / rc->ninterp;
+		for (i = 0; i <= rc->ninterp; i++) {
+			x[i] = min + i * delta_x;
+			y[i] = gog_reg_curve_get_value_at (rc, x[i]);
+		}
+		break;
+	}
 	}
 
 	path = gog_chart_map_make_path (chart_map, x, y, rc->ninterp + 1, GO_LINE_INTERPOLATION_CUBIC_SPLINE, FALSE, NULL);
diff --git a/goffice/graph/gog-reg-curve.h b/goffice/graph/gog-reg-curve.h
index 7e3061c..5fed398 100644
--- a/goffice/graph/gog-reg-curve.h
+++ b/goffice/graph/gog-reg-curve.h
@@ -26,18 +26,24 @@
 
 G_BEGIN_DECLS
 
+typedef enum {
+	GOG_REG_CURVE_DRAWING_BOUNDS_NONE,
+	GOG_REG_CURVE_DRAWING_BOUNDS_ABSOLUTE,
+	GOG_REG_CURVE_DRAWING_BOUNDS_RELATIVE
+} GogRegCurveDrawingBounds;
+
 struct  _GogRegCurve {
 	GogTrendLine	base;
 
-	GogSeries 	  *series;
 	gboolean  	   weighted;
-	GODataVector 	  *weights;
 	GogDatasetElement *bounds;       /* aliased to include the name as -1 */
 	gboolean	   skip_invalid; /* do not take into account invalid data */
 	int		   ninterp;	 /* how many points to use for display the curve as a vpath */
 	double		  *a;		 /* calculated coefficients, must be allocated by derived class */
 	double		   R2;		 /* squared regression coefficient */
 	char		  *equation;
+	GogRegCurveDrawingBounds drawing_bounds;
+	gpointer	   priv;
 };
 
 typedef struct {
@@ -46,6 +52,8 @@ typedef struct {
 	double 		(*get_value_at) (GogRegCurve *reg_curve, double x);
 	char const * 	(*get_equation) (GogRegCurve *reg_curve);
 	void 		(*populate_editor) (GogRegCurve *reg_curve, gpointer table);
+	void	        (*reserved1) (void);
+	void	        (*reserved2) (void);
 } GogRegCurveClass;
 
 #define GOG_TYPE_REG_CURVE	(gog_reg_curve_get_type ())
diff --git a/goffice/utils/go-format.c b/goffice/utils/go-format.c
index 9d222f2..0f55cc9 100644
--- a/goffice/utils/go-format.c
+++ b/goffice/utils/go-format.c
@@ -302,7 +302,7 @@ typedef enum {
 	GO_FMT_SHAPE_SIGNS = 1,
 	/* GENERAL implies GO_FMT_POSITION_MARKERS whether this is set or not */
 	/* This is only useful for Chinese/Japanese/Korean numerals           */
-	GO_FMT_POSITION_MARKERS = 2 
+	GO_FMT_POSITION_MARKERS = 2
 } GOFormatShapeFlags;
 
 typedef struct {
@@ -703,7 +703,7 @@ go_format_parse_locale (const char *str, GOFormatLocale *locale, gsize *nchars)
 	if (*str == '-') {
 		str++;
 		ull = g_ascii_strtoull (str, &end, 16);
-		if (str == end || errno == ERANGE || 
+		if (str == end || errno == ERANGE ||
 		    ull > G_GINT64_CONSTANT(0x0001ffffffffffffU))
 			return FALSE;
 	} else {
@@ -1276,19 +1276,19 @@ handle_common_token (const char *tstr, GOFormatToken t, GString *prg)
 			char *lname = NULL;
 			oldlocale = g_strdup (setlocale (LC_ALL, NULL));
 			ok = setlocale (LC_ALL, lang) != NULL;
-			
+
 			if (!ok) {
 				lname = g_strdup_printf ("%s.utf-8",lang);
 				lang = lname;
 				ok = setlocale (LC_ALL, lang) != NULL;
 			}
-			
+
 			setlocale (LC_ALL, oldlocale);
 			g_free (oldlocale);
-			
+
 			if (ok) {
 				ADD_OP (OP_LOCALE);
-				g_string_append_len (prg, (void *)&locale, 
+				g_string_append_len (prg, (void *)&locale,
 						     sizeof (locale));
 				/* Include the terminating zero: */
 				g_string_append_len (prg, lang, strlen (lang) + 1);
@@ -2396,8 +2396,8 @@ go_format_dump_program (const guchar *prg)
 			prg += sizeof (locale);
 			lang = (const char *)prg;
 			prg += strlen (lang) + 1;
-			g_printerr ("OP_LOCALE -- \"%s\" -- numeral shape: %#x -- calendar: %#x\n", 
-				    lang, 
+			g_printerr ("OP_LOCALE -- \"%s\" -- numeral shape: %#x -- calendar: %#x\n",
+				    lang,
 				    (guint)((locale.locale & 0xFFF000000) >> 24),
 				    (guint)((locale.locale & 0x000FF0000) >> 16));
 			break;
@@ -2870,7 +2870,7 @@ static char const *minus_shapes[] =
 		UTF8_FULLWIDTH_MINUS,    /* 24 Korean 1 ? */
 		UTF8_FULLWIDTH_MINUS,    /* 25 Korean 2 ? */
 		UTF8_FULLWIDTH_MINUS,    /* 26 Korean 3 ? */
-		UTF8_FULLWIDTH_MINUS,    /* 27 Korean 4 ? */	
+		UTF8_FULLWIDTH_MINUS,    /* 27 Korean 4 ? */
 	};
 
 static char const *plus_shapes[] =
@@ -2914,14 +2914,14 @@ static char const *plus_shapes[] =
 		UTF8_FULLWIDTH_PLUS,    /* 24 Korean 1 ? */
 		UTF8_FULLWIDTH_PLUS,    /* 25 Korean 2 ? */
 		UTF8_FULLWIDTH_PLUS,    /* 26 Korean 3 ? */
-		UTF8_FULLWIDTH_PLUS,    /* 27 Korean 4 ? */	
+		UTF8_FULLWIDTH_PLUS,    /* 27 Korean 4 ? */
 	};
 #endif
 
 
 #ifdef DEFINE_COMMON
 
-static char const *numeral_shapes[][10] 
+static char const *numeral_shapes[][10]
 = {{NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL},                           /* 00 Unused */
    {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL},                           /* 01 Unused */
    {"\331\240","\331\241","\331\242","\331\243","\331\244","\331\245","\331\246",
@@ -3319,7 +3319,7 @@ convert_numerals (GString *str, gsize from, gsize to, guint shape)
 				go_string_replace (str, i, 1, num_str, -1);
 				val = TRUE;
 			}
-		} else if (shape == 0x11 && 
+		} else if (shape == 0x11 &&
 			   str->str[i] >= 'a' &&
 			   str->str[i] <= 'k') {
 			gint num = str->str[i] - 'a';
@@ -3327,7 +3327,7 @@ convert_numerals (GString *str, gsize from, gsize to, guint shape)
 			if (*num_str != 0) {
 				go_string_replace (str, i, 1, num_str, -1);
 				val = TRUE;
-			}			
+			}
 		}
 	}
 	return val;
@@ -3353,8 +3353,8 @@ convert_sign (GString *str, size_t i, guint shape, guint shape_flags)
 		return FALSE;
 	}
 
-	if (((shape_flags & GO_FMT_SHAPE_SIGNS) == 0) || 
-	    (shape <= 1) || 
+	if (((shape_flags & GO_FMT_SHAPE_SIGNS) == 0) ||
+	    (shape <= 1) ||
 	    (shape > G_N_ELEMENTS (minus_shapes)))
 		shaped_sign = sign;
 	else
@@ -3366,7 +3366,7 @@ convert_sign (GString *str, size_t i, guint shape, guint shape_flags)
 }
 
 static void
-handle_ethiopic (GString *numtxt, const char **dot, guint numeral_shape, 
+handle_ethiopic (GString *numtxt, const char **dot, guint numeral_shape,
 		guint shape_flags)
 {
 	gint last;
@@ -3374,7 +3374,7 @@ handle_ethiopic (GString *numtxt, const char **dot, guint numeral_shape,
 	gboolean cnt = 0;
 	gint tail = 0;
 
-	if ((shape_flags & GO_FMT_POSITION_MARKERS) == 0 || 
+	if ((shape_flags & GO_FMT_POSITION_MARKERS) == 0 ||
 	    numeral_shape != 0x11)
 		return;
 	if (dot && *dot) {
@@ -3409,7 +3409,7 @@ handle_ethiopic (GString *numtxt, const char **dot, guint numeral_shape,
 					} else {
 						numtxt->str[last] += ('a'-'1');
 						if (numtxt->str[last + 1] == '0')
-							g_string_erase (numtxt, last + 1, 1);	
+							g_string_erase (numtxt, last + 1, 1);
 					}
 				}
 				hundred = !hundred;
@@ -3434,7 +3434,7 @@ handle_ethiopic (GString *numtxt, const char **dot, guint numeral_shape,
 
 
 static void
-handle_chinese (GString *numtxt, const char **dot, guint numeral_shape, 
+handle_chinese (GString *numtxt, const char **dot, guint numeral_shape,
 		guint shape_flags)
 {
 	GString *ntxt;
@@ -3443,7 +3443,7 @@ handle_chinese (GString *numtxt, const char **dot, guint numeral_shape,
 	gboolean wan_written = TRUE;
 	gboolean digit_written = FALSE;
 	gboolean suppress_ten, suppress_ten_always;
-	if ((shape_flags & GO_FMT_POSITION_MARKERS) == 0 || 
+	if ((shape_flags & GO_FMT_POSITION_MARKERS) == 0 ||
 	    numeral_shape < 0x1B || numeral_shape > 0x27)
 		return;
 	last = ((dot && *dot) ? *dot - 1 : numtxt->str + (numtxt->len - 1));
@@ -3451,7 +3451,7 @@ handle_chinese (GString *numtxt, const char **dot, guint numeral_shape,
 		return;
 
 	ntxt = g_string_sized_new (100);
-	suppress_ten = (numeral_shape == 0x1b || numeral_shape == 0x1d 
+	suppress_ten = (numeral_shape == 0x1b || numeral_shape == 0x1d
 			|| numeral_shape == 0x26);
 	suppress_ten_always = (numeral_shape == 0x26);
 	i = 0;
@@ -3469,7 +3469,7 @@ handle_chinese (GString *numtxt, const char **dot, guint numeral_shape,
 				if (i > 0)
 					g_string_prepend_c (ntxt, 'a' + i - 1);
 				if (!suppress_ten_always ||
-				    !(suppress_ten && wan == 0) || 
+				    !(suppress_ten && wan == 0) ||
 				    *last != '1')
 					g_string_prepend_c (ntxt, *last);
 				digit_written = TRUE;
@@ -3976,9 +3976,9 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 				numtxt = g_string_sized_new (100);
 			g_string_printf (numtxt, "%.*" FORMAT_f, n, val);
 			dot = strstr (numtxt->str, decimal->str);
-			handle_chinese (numtxt, &dot, 
+			handle_chinese (numtxt, &dot,
 					numeral_shape, shape_flags);
-			handle_ethiopic (numtxt, &dot, 
+			handle_ethiopic (numtxt, &dot,
 					 numeral_shape, shape_flags);
 			if (dot) {
 				size_t i = numtxt->len;
@@ -4125,7 +4125,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 			}
 			g_string_append_c (dst, c);
 			if ((numeral_shape) > 1)  /* 0: not set; 1: Western */
-				convert_numerals (dst, dst->len - 1, dst->len - 1, 
+				convert_numerals (dst, dst->len - 1, dst->len - 1,
 						  numeral_shape);
 			break;
 		}
@@ -4199,7 +4199,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 				/* FIXME: we need to fix the exponent handling */
 				/* until that time use only latin numerals */
 				numeral_shape = 0;
-				
+
 				markup_stack = g_slist_prepend
 					(markup_stack, GSIZE_TO_POINTER (dst->len));
 			}
@@ -4562,7 +4562,7 @@ go_format_measure_strlen (const GString *str,
 		convert_numerals (str, 0, str->len - 1, num_shape);	\
 	}								\
 	} while (0)
-	  
+
 /*
  * go_format_general:
  * @layout: Optional PangoLayout, probably preseeded with font attribute.
diff --git a/goffice/utils/go-format.h b/goffice/utils/go-format.h
index 08780d7..f6a6220 100644
--- a/goffice/utils/go-format.h
+++ b/goffice/utils/go-format.h
@@ -136,7 +136,7 @@ void go_render_general  (PangoLayout *layout, GString *str,
 			 const GOFontMetrics *metrics,
 			 double val,
 			 int col_width,
-			 gboolean unicode_minus, 
+			 gboolean unicode_minus,
 			 guint numeral_shape,
 			 guint custom_shape_flags);
 #ifdef GOFFICE_WITH_LONG_DOUBLE
@@ -145,7 +145,7 @@ void go_render_generall (PangoLayout *layout, GString *str,
 			 const GOFontMetrics *metrics,
 			 long double val,
 			 int col_width,
-			 gboolean unicode_minus, 
+			 gboolean unicode_minus,
 			 guint numeral_shape,
 			 guint custom_shape_flags);
 #endif
diff --git a/plugins/plot_distrib/gog-boxplot.c b/plugins/plot_distrib/gog-boxplot.c
index d8157ed..5f0c88a 100644
--- a/plugins/plot_distrib/gog-boxplot.c
+++ b/plugins/plot_distrib/gog-boxplot.c
@@ -109,7 +109,7 @@ display_before_grid_cb (GtkToggleButton *btn, GObject *obj)
 static gpointer
 gog_box_plot_pref (GogObject *obj,
 		   GogDataAllocator *dalloc, GOCmdContext *cc)
-{	
+{
 	GogBoxPlot *boxplot = GOG_BOX_PLOT (obj);
 	GtkBuilder *gui =
 		go_gtk_builder_new ("res:go:plot_distrib/gog-boxplot-prefs.ui",
diff --git a/plugins/reg_linear/gog-lin-reg.c b/plugins/reg_linear/gog-lin-reg.c
index b78c97b..f855531 100644
--- a/plugins/reg_linear/gog-lin-reg.c
+++ b/plugins/reg_linear/gog-lin-reg.c
@@ -150,16 +150,13 @@ affine_toggled_cb (GtkToggleButton *btn, GObject *obj)
 static void
 gog_lin_reg_curve_populate_editor (GogRegCurve *reg_curve, gpointer table)
 {
-	int rows, columns;
 	GtkWidget *w;
 	GogLinRegCurve *lin = GOG_LIN_REG_CURVE (reg_curve);
 
-	g_object_get (G_OBJECT (table), "n-rows", &rows, "n-columns", &columns, NULL);
-	gtk_table_resize (table, rows + 1, columns);
 	w = gtk_check_button_new_with_label (_("Affine"));
 	gtk_widget_set_tooltip_text (w, _("Uncheck to force zero intercept"));
 	gtk_widget_show (w);
-	gtk_table_attach (table, w, 0, columns, rows, rows + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_grid_attach_next_to (table, w, NULL, GTK_POS_BOTTOM, 1, 3);
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), lin->affine);
 	g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (affine_toggled_cb), lin);
 }
diff --git a/plugins/reg_linear/gog-polynom-reg.c b/plugins/reg_linear/gog-polynom-reg.c
index 6209832..f9c683a 100644
--- a/plugins/reg_linear/gog-polynom-reg.c
+++ b/plugins/reg_linear/gog-polynom-reg.c
@@ -193,21 +193,19 @@ order_changed_cb (GtkSpinButton *btn, GObject *obj)
 static void
 gog_polynom_reg_curve_populate_editor (GogRegCurve *reg_curve, gpointer table)
 {
-	int rows, columns;
-	GtkWidget *w;
+	GtkWidget *l, *w;
 	GogLinRegCurve *lin = GOG_LIN_REG_CURVE (reg_curve);
 
 	((GogRegCurveClass*) gog_polynom_reg_curve_parent_klass)->populate_editor (reg_curve, table);
-	g_object_get (G_OBJECT (table), "n-rows", &rows, "n-columns", &columns, NULL);
-	gtk_table_resize (table, rows + 1, columns);
-	w = gtk_label_new (_("Order:"));
-	gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);
-	gtk_widget_show (w);
-	gtk_table_attach (table, w, 0, 1, rows, rows + 1, 0, 0, 0, 0);
+	l = gtk_label_new (_("Order:"));
+	gtk_misc_set_alignment (GTK_MISC (l), 0., 0.5);
+	gtk_label_set_justify (GTK_LABEL (l), GTK_JUSTIFY_LEFT);
+	gtk_widget_show (l);
+	gtk_grid_attach_next_to (table, l, NULL, GTK_POS_BOTTOM, 1, 1);
 	w = gtk_spin_button_new_with_range (2, 10, 1);
 	gtk_spin_button_set_digits (GTK_SPIN_BUTTON (w), 0);
 	gtk_widget_show (w);
-	gtk_table_attach (table, w, 1, columns, rows, rows + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+	gtk_grid_attach_next_to (table, w, l, GTK_POS_RIGHT, 1, 1);
 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), lin->dims);
 	g_signal_connect (G_OBJECT (w), "value-changed", G_CALLBACK (order_changed_cb), lin);
 }



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