+
+#define DEFAULT_ROW_HEIGHT 25
+
+static void
+new_data_callback (PsppireDataStore *ds, gpointer data)
+{
+ gint i;
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
+
+ casenumber n_cases = psppire_data_store_get_case_count (ds);
+
+ for (i = 0; i < 2; ++i)
+ {
+ psppire_axis_clear (de->vaxis[i]);
+ psppire_axis_append_n (de->vaxis[i], n_cases, DEFAULT_ROW_HEIGHT);
+ }
+}
+
+static void
+case_inserted_callback (PsppireDataStore *ds, gint before, gpointer data)
+{
+ gint i;
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
+
+ for (i = 0; i < 2; ++i)
+ psppire_axis_insert (de->vaxis[i], before, DEFAULT_ROW_HEIGHT);
+}
+
+
+static void
+cases_deleted_callback (PsppireDataStore *ds, gint first, gint n_cases, gpointer data)
+{
+ gint i;
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
+
+ for (i = 0; i < 2; ++i)
+ psppire_axis_delete (de->vaxis[0], first, n_cases);
+}
+
+
+
+/* Return the width (in pixels) of an upper case M when rendered in the
+ current font of W
+*/
+static gint
+width_of_m (GtkWidget *w)
+{
+ PangoRectangle rect;
+ PangoLayout *layout = gtk_widget_create_pango_layout (w, "M");
+
+ pango_layout_get_pixel_extents (layout, NULL, &rect);
+
+ g_object_unref (layout);
+
+ return rect.width;
+}
+
+/* Callback for the axis' resize signal.
+ Changes the variable's display width */
+static void
+rewidth_variable (GtkWidget *w, gint unit, glong size)
+{
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (w);
+
+ const PsppireDict *dict = de->data_store->dict;
+ struct variable *var = psppire_dict_get_variable (dict, unit);
+
+ if (NULL == var)
+ return;
+
+ var_set_display_width (var, size / (float) width_of_m (w));
+}
+
+
+static void
+new_variables_callback (PsppireDict *dict, gpointer data)
+{
+ gint v;
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
+ gint m_width = width_of_m (GTK_WIDGET (de));
+
+ PsppireAxis *vaxis;
+ g_object_get (de->var_sheet, "vertical-axis", &vaxis, NULL);
+
+ psppire_axis_clear (vaxis);
+ psppire_axis_append_n (vaxis, 1 + psppire_dict_get_var_cnt (dict), DEFAULT_ROW_HEIGHT);
+
+ g_signal_connect_swapped (de->haxis, "resize-unit",
+ G_CALLBACK (rewidth_variable), de);
+
+ psppire_axis_clear (de->haxis);
+
+ for (v = 0 ; v < psppire_dict_get_var_cnt (dict); ++v)
+ {
+ const struct variable *var = psppire_dict_get_variable (dict, v);
+
+ psppire_axis_append (de->haxis, m_width * var_get_display_width (var));
+ }
+}
+
+static void
+insert_variable_callback (PsppireDict *dict, gint x, gpointer data)
+{
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
+
+ gint m_width = width_of_m (GTK_WIDGET (de));
+
+ PsppireAxis *var_vaxis;
+
+ const struct variable *var = psppire_dict_get_variable (dict, x);
+
+ g_object_get (de->var_sheet, "vertical-axis", &var_vaxis, NULL);
+
+ psppire_axis_insert (var_vaxis, x, DEFAULT_ROW_HEIGHT);
+
+
+ psppire_axis_insert (de->haxis, x, m_width * var_get_display_width (var));
+}
+
+
+static void
+delete_variable_callback (PsppireDict *dict, gint posn,
+ gint x UNUSED, gint y UNUSED, gpointer data)
+{
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
+
+ PsppireAxis *var_vaxis;
+ g_object_get (de->var_sheet, "vertical-axis", &var_vaxis, NULL);
+
+ psppire_axis_delete (var_vaxis, posn, 1);
+
+ psppire_axis_delete (de->haxis, posn, 1);
+}
+
+
+static void
+rewidth_variable_callback (PsppireDict *dict, gint posn, gpointer data)
+{
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
+ gint m_width = width_of_m (GTK_WIDGET (de));
+
+ const struct variable *var = psppire_dict_get_variable (dict, posn);
+
+ gint var_width = var_get_display_width (var);
+
+ /* Don't allow zero width */
+ if ( var_width < 1 )
+ var_width = 1;
+
+ psppire_axis_resize (de->haxis, posn, m_width * var_width);
+}
+
+