Fix GUI bug risizing columns.
[pspp-builds.git] / lib / gtk-contrib / psppire-sheet.c
index 908081e1a0abaafe0e2627e6ff8a6a9ded3e6fa2..b14ede139083456c9e1ce3a748f320c030e1c9f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 2006, 2008 Free Software Foundation
+   Copyright (C) 2006, 2008, 2009 Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -69,7 +69,9 @@
 #include "psppire-sheet.h"
 #include <ui/gui/psppire-marshal.h>
 #include <ui/gui/sheet/psppire-sheetmodel.h>
+#include <ui/gui/sheet/psppire-axis.h>
 #include <libpspp/misc.h>
+
 #include <math.h>
 
 /* sheet flags */
@@ -477,9 +479,7 @@ static void psppire_sheet_size_allocate              (GtkWidget *widget,
                                                  GtkAllocation *allocation);
 
 static gboolean psppire_sheet_focus_in               (GtkWidget     *widget,
-                                                     GdkEventFocus *event,
-                                                     gpointer       user_data);
-
+                                                     GdkEventFocus *event);
 
 /* Sheet queries */
 
@@ -699,6 +699,7 @@ enum
     PROP_0,
     PROP_VAXIS,
     PROP_HAXIS,
+    PROP_CELL_PADDING,
     PROP_MODEL
   };
 
@@ -758,6 +759,7 @@ psppire_sheet_set_vertical_axis (PsppireSheet *sheet, PsppireAxis *a)
     g_object_ref (sheet->vaxis);
 }
 
+static const GtkBorder default_cell_padding = {3, 3, 3, 3};
 
 static void
 psppire_sheet_set_property (GObject         *object,
@@ -770,11 +772,37 @@ psppire_sheet_set_property (GObject         *object,
 
   switch (prop_id)
     {
+    case PROP_CELL_PADDING:
+      if ( sheet->cell_padding)
+       g_boxed_free (GTK_TYPE_BORDER, sheet->cell_padding);
+
+      sheet->cell_padding = g_value_dup_boxed (value);
+
+     if (NULL == sheet->cell_padding)
+       sheet->cell_padding = g_boxed_copy (GTK_TYPE_BORDER,
+                                          &default_cell_padding);
+
+     if (sheet->vaxis)
+       g_object_set (sheet->vaxis, "padding",
+                    sheet->cell_padding->top + sheet->cell_padding->bottom,
+                    NULL);
+
+     if (sheet->haxis)
+       g_object_set (sheet->haxis, "padding",
+                    sheet->cell_padding->left + sheet->cell_padding->right,
+                    NULL);
+      break;
     case PROP_VAXIS:
       psppire_sheet_set_vertical_axis (sheet, g_value_get_pointer (value));
+      g_object_set (sheet->vaxis, "padding",
+                   sheet->cell_padding->top + sheet->cell_padding->bottom,
+                   NULL);
       break;
     case PROP_HAXIS:
       psppire_sheet_set_horizontal_axis (sheet, g_value_get_pointer (value));
+      g_object_set (sheet->haxis, "padding",
+                   sheet->cell_padding->left + sheet->cell_padding->right,
+                   NULL);
       break;
     case PROP_MODEL:
       psppire_sheet_set_model (sheet, g_value_get_pointer (value));
@@ -795,6 +823,9 @@ psppire_sheet_get_property (GObject         *object,
 
   switch (prop_id)
     {
+    case PROP_CELL_PADDING:
+      g_value_set_boxed (value, sheet->cell_padding);
+      break;
     case PROP_VAXIS:
       g_value_set_pointer (value, sheet->vaxis);
       break;
@@ -819,6 +850,7 @@ psppire_sheet_class_init (PsppireSheetClass *klass)
   GParamSpec *haxis_spec ;
   GParamSpec *vaxis_spec ;
   GParamSpec *model_spec ;
+  GParamSpec *cell_padding_spec ;
 
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
@@ -1015,10 +1047,17 @@ psppire_sheet_class_init (PsppireSheetClass *klass)
   container_class->add = NULL;
   container_class->remove = NULL;
   container_class->forall = psppire_sheet_forall;
+  container_class->set_focus_child = NULL;
 
   object_class->dispose = psppire_sheet_dispose;
   object_class->finalize = psppire_sheet_finalize;
 
+  cell_padding_spec =
+    g_param_spec_boxed ("cell-padding",
+                       "Cell Padding",
+                       "The space between a cell's contents and its border",
+                       GTK_TYPE_BORDER,
+                       G_PARAM_CONSTRUCT | G_PARAM_READABLE | G_PARAM_WRITABLE);
 
   vaxis_spec =
     g_param_spec_pointer ("vertical-axis",
@@ -1050,6 +1089,10 @@ psppire_sheet_class_init (PsppireSheetClass *klass)
                                    PROP_HAXIS,
                                    haxis_spec);
 
+  g_object_class_install_property (object_class,
+                                   PROP_CELL_PADDING,
+                                   cell_padding_spec);
+
   g_object_class_install_property (object_class,
                                    PROP_MODEL,
                                    model_spec);
@@ -1753,6 +1796,9 @@ psppire_sheet_dispose  (GObject *object)
 
   sheet->dispose_has_run = TRUE;
 
+  if ( sheet->cell_padding)
+    g_boxed_free (GTK_TYPE_BORDER, sheet->cell_padding);
+
   if (sheet->model) g_object_unref (sheet->model);
   if (sheet->vaxis) g_object_unref (sheet->vaxis);
   if (sheet->haxis) g_object_unref (sheet->haxis);
@@ -1810,7 +1856,6 @@ psppire_sheet_style_set (GtkWidget *widget,
   set_entry_widget_font (sheet);
 }
 
-#define BORDER_WIDTH 3
 
 static void
 psppire_sheet_realize (GtkWidget *widget)
@@ -1918,7 +1963,10 @@ psppire_sheet_realize (GtkWidget *widget)
   values.foreground = widget->style->white;
   values.function = GDK_INVERT;
   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
-  values.line_width = BORDER_WIDTH;
+  values.line_width = MAX (sheet->cell_padding->left,
+                          MAX (sheet->cell_padding->right,
+                               MAX (sheet->cell_padding->top,
+                                    sheet->cell_padding->bottom)));
 
   sheet->xor_gc = gdk_gc_new_with_values (widget->window,
                                          &values,
@@ -1928,13 +1976,15 @@ psppire_sheet_realize (GtkWidget *widget)
                                          GDK_GC_LINE_WIDTH
                                          );
 
-
   gtk_widget_set_parent_window (sheet->entry_widget, sheet->sheet_window);
   gtk_widget_set_parent (sheet->entry_widget, GTK_WIDGET (sheet));
 
   gtk_widget_set_parent_window (sheet->button, sheet->sheet_window);
   gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
 
+  sheet->button->style = gtk_style_attach (sheet->button->style,
+                                          sheet->sheet_window);
+
 
   sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS);
 
@@ -2092,13 +2142,18 @@ psppire_sheet_unmap (GtkWidget *widget)
     gdk_window_hide (sheet->row_title_window);
   gdk_window_hide (widget->window);
 
-  if (GTK_WIDGET_MAPPED (sheet->entry_widget))
-    gtk_widget_unmap (sheet->entry_widget);
-
-  if (GTK_WIDGET_MAPPED (sheet->button))
-    gtk_widget_unmap (sheet->button);
+  gtk_widget_unmap (sheet->entry_widget);
+  gtk_widget_unmap (sheet->button);
+  gtk_widget_unmap (sheet->hover_window->window);
 }
 
+/* get cell attributes of the given cell */
+/* TRUE means that the cell is currently allocated */
+static gboolean psppire_sheet_get_attributes (const PsppireSheet *sheet,
+                                             gint row, gint col,
+                                             PsppireSheetCellAttr *attributes);
+
+
 
 static void
 psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint col)
@@ -2167,6 +2222,19 @@ psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint col)
   if ( !pango_font_description_get_size_is_absolute (font_desc))
     font_height /= PANGO_SCALE;
 
+
+  if ( sheet->cell_padding )
+    {
+      area.x += sheet->cell_padding->left;
+      area.width -= sheet->cell_padding->right
+       + sheet->cell_padding->left;
+
+      area.y += sheet->cell_padding->top;
+      area.height -= sheet->cell_padding->bottom
+       +
+       sheet->cell_padding->top;
+    }
+
   /* Centre the text vertically */
   area.y += (area.height - font_height) / 2.0;
 
@@ -3018,11 +3086,24 @@ psppire_sheet_draw_border (PsppireSheet *sheet, PsppireSheetRange new_range)
 
   rectangle_from_range (sheet, &new_range, &area);
 
-  gdk_draw_rectangle (sheet->sheet_window,
-                     sheet->xor_gc,
+  area.width ++;
+  area.height ++;
+
+  gdk_gc_set_clip_rectangle (sheet->xor_gc, &area);
+
+  area.x += sheet->cell_padding->left / 2;
+  area.y += sheet->cell_padding->top / 2;
+  area.width -= (sheet->cell_padding->left + sheet->cell_padding->right ) / 2;
+  area.height -= (sheet->cell_padding->top + sheet->cell_padding->bottom ) / 2;
+
+  gdk_draw_rectangle (sheet->sheet_window,  sheet->xor_gc,
                      FALSE,
-                     area.x, area.y,
-                     area.width, area.height);
+                     area.x,
+                     area.y,
+                     area.width,
+                     area.height);
+
+  gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
 }
 
 
@@ -3686,7 +3767,8 @@ create_hover_window (void)
 #define HOVER_WINDOW_Y_OFFSET 2
 
 static void
-show_subtitle (PsppireSheet *sheet, gint row, gint column, const gchar *subtitle)
+show_subtitle (PsppireSheet *sheet, gint row, gint column,
+              const gchar *subtitle)
 {
   gint x, y;
   gint px, py;
@@ -3736,6 +3818,8 @@ motion_timeout_callback (gpointer data)
   PsppireSheet *sheet = PSPPIRE_SHEET (data);
   gint x, y;
   gint row, column;
+
+  gdk_threads_enter ();
   gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
 
   if ( psppire_sheet_get_pixel_info (sheet, x, y, &row, &column) )
@@ -3759,6 +3843,7 @@ motion_timeout_callback (gpointer data)
        }
     }
 
+  gdk_threads_leave ();
   return FALSE;
 }
 
@@ -4054,14 +4139,16 @@ psppire_sheet_crossing_notify (GtkWidget *widget,
   else if (event->window == sheet->row_title_window)
     sheet->row_title_under = event->type == GDK_ENTER_NOTIFY;
 
+  if (event->type == GDK_LEAVE_NOTIFY)
+    gtk_widget_hide (sheet->hover_window->window);
+
   return TRUE;
 }
 
 
 static gboolean
 psppire_sheet_focus_in (GtkWidget     *w,
-                       GdkEventFocus *event,
-                       gpointer       user_data)
+                       GdkEventFocus *event)
 {
   PsppireSheet *sheet = PSPPIRE_SHEET (w);
 
@@ -4600,10 +4687,10 @@ psppire_sheet_size_allocate_entry (PsppireSheet *sheet)
   rectangle_from_cell (sheet, sheet->active_cell.row,
                       sheet->active_cell.col, &entry_alloc);
 
-  entry_alloc.width -= BORDER_WIDTH ;
-  entry_alloc.height -= BORDER_WIDTH ;
-  entry_alloc.x += DIV_RND_UP (BORDER_WIDTH, 2);
-  entry_alloc.y += DIV_RND_UP (BORDER_WIDTH, 2);
+  entry_alloc.x += sheet->cell_padding->left;
+  entry_alloc.y += sheet->cell_padding->right;
+  entry_alloc.width -= sheet->cell_padding->left + sheet->cell_padding->right;
+  entry_alloc.height -= sheet->cell_padding->top + sheet->cell_padding->bottom;
 
 
   gtk_widget_set_size_request (sheet->entry_widget, entry_alloc.width,
@@ -4728,8 +4815,9 @@ draw_button (PsppireSheet *sheet, GdkWindow *window,
 
   gtk_paint_box (sheet->button->style, window,
                 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
-                &allocation, GTK_WIDGET (sheet->button),
-                "buttondefault",
+                &allocation,
+                GTK_WIDGET (sheet->button),
+                NULL,
                 allocation.x, allocation.y,
                 allocation.width, allocation.height);
 
@@ -4745,10 +4833,30 @@ draw_button (PsppireSheet *sheet, GdkWindow *window,
     gtk_paint_box (sheet->button->style, window,
                   button->state, shadow_type,
                   &allocation, GTK_WIDGET (sheet->button),
-                  "button",
+                  NULL,
                   allocation.x, allocation.y,
                   allocation.width, allocation.height);
 
+  if ( button->overstruck)
+    {
+      GdkPoint points[2] = {
+       {allocation.x,  allocation.y},
+       {allocation.x + allocation.width,
+        allocation.y + allocation.height}
+      };
+
+      gtk_paint_polygon (sheet->button->style,
+                        window,
+                        button->state,
+                        shadow_type,
+                        NULL,
+                        GTK_WIDGET (sheet),
+                        NULL,
+                        points,
+                        2,
+                        TRUE);
+    }
+
   if (button->label_visible)
     {
       text_height = DEFAULT_ROW_HEIGHT -
@@ -5194,7 +5302,9 @@ set_column_width (PsppireSheet *sheet,
   if ( width <= 0)
     return;
 
-  psppire_axis_resize (sheet->haxis, column, width);
+  psppire_axis_resize (sheet->haxis, column,
+                      width - sheet->cell_padding->left -
+                      sheet->cell_padding->right);
 
   if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
     {
@@ -5219,7 +5329,9 @@ set_row_height (PsppireSheet *sheet,
   if (height <= 0)
     return;
 
-  psppire_axis_resize (sheet->vaxis, row, height);
+  psppire_axis_resize (sheet->vaxis, row,
+                      height - sheet->cell_padding->top -
+                      sheet->cell_padding->bottom);
 
   if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) )
     {
@@ -5230,7 +5342,7 @@ set_row_height (PsppireSheet *sheet,
     }
 }
 
-gboolean
+static gboolean
 psppire_sheet_get_attributes (const PsppireSheet *sheet, gint row, gint col,
                          PsppireSheetCellAttr *attr)
 {
@@ -5253,8 +5365,6 @@ psppire_sheet_get_attributes (const PsppireSheet *sheet, gint row, gint col,
   attr->border.mask = 0;
   attr->border.color = GTK_WIDGET (sheet)->style->black;
 
-  attr->is_editable = psppire_sheet_model_is_editable (sheet->model, row, col);
-
   colormap = gtk_widget_get_colormap (GTK_WIDGET (sheet));
   fg = psppire_sheet_model_get_foreground (sheet->model, row, col);
   if ( fg )
@@ -5337,6 +5447,7 @@ psppire_sheet_button_new (void)
   button->label = NULL;
   button->label_visible = TRUE;
   button->justification = GTK_JUSTIFY_FILL;
+  button->overstruck = FALSE;
 
   return button;
 }