pspp-dev
[Top][All Lists]
Advanced

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

[PATCH 16/17] psppire-cell-renderer-button: New cell renderer for GtkBut


From: Ben Pfaff
Subject: [PATCH 16/17] psppire-cell-renderer-button: New cell renderer for GtkButton.
Date: Sun, 22 Apr 2012 11:12:34 -0700

This allows one to put a clickable GtkButton inside a PsppSheetView row.
---
 src/ui/gui/automake.mk                    |    8 +-
 src/ui/gui/include/gtk/gtk.in.h           |   21 ++
 src/ui/gui/psppire-button-editable.c      |  179 ++++++++++
 src/ui/gui/psppire-button-editable.h      |   48 +++
 src/ui/gui/psppire-cell-renderer-button.c |  527 +++++++++++++++++++++++++++++
 src/ui/gui/psppire-cell-renderer-button.h |   65 ++++
 src/ui/gui/psppire.gtkrc                  |    7 +
 7 files changed, 853 insertions(+), 2 deletions(-)
 create mode 100644 src/ui/gui/psppire-button-editable.c
 create mode 100644 src/ui/gui/psppire-button-editable.h
 create mode 100644 src/ui/gui/psppire-cell-renderer-button.c
 create mode 100644 src/ui/gui/psppire-cell-renderer-button.h
 create mode 100644 src/ui/gui/psppire.gtkrc

diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk
index 924379f..6071830 100644
--- a/src/ui/gui/automake.mk
+++ b/src/ui/gui/automake.mk
@@ -129,8 +129,8 @@ dist_src_ui_gui_psppire_DATA = \
        $(top_srcdir)/src/ui/gui/icons/16x16/scale.png \
        $(top_srcdir)/src/ui/gui/icons/16x16/string.png \
        $(top_srcdir)/src/ui/gui/icons/16x16/date-scale.png \
-       $(top_srcdir)/src/ui/gui/icons/splash.png 
-
+       $(top_srcdir)/src/ui/gui/icons/splash.png \
+       $(top_srcdir)/src/ui/gui/psppire.gtkrc
 
 src_ui_gui_psppire_SOURCES = \
        src/ui/gui/pspp-sheet-selection.c \
@@ -141,6 +141,10 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/pspp-sheet-view.h \
        src/ui/gui/pspp-widget-facade.c \
        src/ui/gui/pspp-widget-facade.h \
+       src/ui/gui/psppire-button-editable.c \
+       src/ui/gui/psppire-button-editable.h \
+       src/ui/gui/psppire-cell-renderer-button.c \
+       src/ui/gui/psppire-cell-renderer-button.h \
        src/ui/gui/psppire-dialog.c \
        src/ui/gui/psppire-keypad.c \
        src/ui/gui/psppire-selector.c \
diff --git a/src/ui/gui/include/gtk/gtk.in.h b/src/ui/gui/include/gtk/gtk.in.h
index 83f0b64..966111d 100644
--- a/src/ui/gui/include/gtk/gtk.in.h
+++ b/src/ui/gui/include/gtk/gtk.in.h
@@ -163,4 +163,25 @@ gtk_widget_set_can_focus (GtkWidget *widget,
 }
 #endif  /* gtk < 2.18 */
 
+#if !GTK_CHECK_VERSION(2,22,0)
+/**
+ * gtk_button_get_event_window:
+ * @button: a #GtkButton
+ *
+ * Returns the button's event window if it is realized, %NULL otherwise.
+ * This function should be rarely needed.
+ *
+ * Return value: (transfer none): @button's event window.
+ *
+ * Since: 2.22
+ */
+static inline GdkWindow*
+gtk_button_get_event_window (GtkButton *button)
+{
+  g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
+
+  return button->event_window;
+}
+#endif  /* gtk < 2.22 */
+
 #endif /* PSPP_GTK_GTK_H */
diff --git a/src/ui/gui/psppire-button-editable.c 
b/src/ui/gui/psppire-button-editable.c
new file mode 100644
index 0000000..cefc7a5
--- /dev/null
+++ b/src/ui/gui/psppire-button-editable.c
@@ -0,0 +1,179 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "ui/gui/psppire-button-editable.h"
+
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+/* GtkCellEditable interface. */
+static void gtk_cell_editable_interface_init (GtkCellEditableIface *iface);
+static void button_editable_editing_done (GtkCellEditable *cell_editable);
+static void button_editable_remove_widget (GtkCellEditable *cell_editable);
+static void button_editable_start_editing (GtkCellEditable *cell_editable,
+                                           GdkEvent        *event);
+
+G_DEFINE_TYPE_EXTENDED (PsppireButtonEditable,
+                        psppire_button_editable,
+                        GTK_TYPE_BUTTON,
+                        0,
+                        G_IMPLEMENT_INTERFACE (
+                          GTK_TYPE_CELL_EDITABLE,
+                          gtk_cell_editable_interface_init));
+
+enum
+  {
+    PROP_0,
+    PROP_PATH
+  };
+
+static void
+psppire_button_editable_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_PATH:
+      g_free (obj->path);
+      obj->path = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+psppire_button_editable_get_property (GObject      *object,
+                                      guint         prop_id,
+                                      GValue       *value,
+                                      GParamSpec   *pspec)
+{
+  PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_PATH:
+      g_value_set_string (value, obj->path);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+psppire_button_editable_dispose (GObject *gobject)
+{
+  PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (gobject);
+
+  g_free (obj->path);
+  obj->path = NULL;
+
+  G_OBJECT_CLASS (psppire_button_editable_parent_class)->dispose (gobject);
+}
+
+static gboolean
+psppire_button_editable_button_release (GtkWidget      *widget,
+                                        GdkEventButton *event)
+{
+  GtkButton *button;
+
+  if (event->button == 1)
+    {
+      button = GTK_BUTTON (widget);
+      gtk_button_released (button);
+    }
+
+  return TRUE;
+}
+
+static void
+psppire_button_editable_class_init (PsppireButtonEditableClass *class)
+{
+  GObjectClass *gobject_class;
+  GtkWidgetClass *widget_class;
+
+  gobject_class = G_OBJECT_CLASS (class);
+  widget_class = GTK_WIDGET_CLASS (class);
+
+  gobject_class->set_property = psppire_button_editable_set_property;
+  gobject_class->get_property = psppire_button_editable_get_property;
+  gobject_class->dispose = psppire_button_editable_dispose;
+
+  widget_class->button_release_event = psppire_button_editable_button_release;
+
+  g_object_class_install_property (G_OBJECT_CLASS (class),
+                                   PROP_PATH,
+                                   g_param_spec_string ("path",
+                                                       _("TreeView path"),
+                                                       _("The path to the row 
in the GtkTreeView, as a string"),
+                                                       "",
+                                                       G_PARAM_READWRITE));
+}
+
+static void
+psppire_button_editable_init (PsppireButtonEditable *obj)
+{
+  obj->path = g_strdup ("");
+}
+
+PsppireButtonEditable *
+psppire_button_editable_new (void)
+{
+  return PSPPIRE_BUTTON_EDITABLE (g_object_new (PSPPIRE_TYPE_BUTTON_EDITABLE, 
NULL));
+}
+
+/* GtkCellEditable interface. */
+
+static void
+gtk_cell_editable_interface_init (GtkCellEditableIface *iface)
+{
+  g_return_if_fail (iface != NULL);
+
+  iface->editing_done = button_editable_editing_done;
+  iface->remove_widget = button_editable_remove_widget;
+  iface->start_editing = button_editable_start_editing;
+}
+
+static void
+button_editable_editing_done (GtkCellEditable *cell_editable)
+{
+
+
+}
+
+static void
+button_editable_remove_widget (GtkCellEditable *cell_editable)
+{
+
+
+}
+
+static void
+button_editable_start_editing (GtkCellEditable *cell_editable,
+                               GdkEvent        *event)
+{
+}
diff --git a/src/ui/gui/psppire-button-editable.h 
b/src/ui/gui/psppire-button-editable.h
new file mode 100644
index 0000000..7949b87
--- /dev/null
+++ b/src/ui/gui/psppire-button-editable.h
@@ -0,0 +1,48 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef PSPPIRE_BUTTON_EDITABLE_H
+#define PSPPIRE_BUTTON_EDITABLE_H 1
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define PSPPIRE_TYPE_BUTTON_EDITABLE             
(psppire_button_editable_get_type())
+#define PSPPIRE_BUTTON_EDITABLE(obj)             (G_TYPE_CHECK_INSTANCE_CAST 
((obj),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditable))
+#define PSPPIRE_BUTTON_EDITABLE_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST 
((class),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditableClass))
+#define PSPPIRE_IS_BUTTON_EDITABLE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE 
((obj),PSPPIRE_TYPE_BUTTON_EDITABLE))
+#define PSPPIRE_IS_BUTTON_EDITABLE_CLASS(class)  (G_TYPE_CHECK_CLASS_TYPE 
((class),PSPPIRE_TYPE_BUTTON_EDITABLE))
+#define PSPPIRE_BUTTON_EDITABLE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS 
((obj),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditableClass))
+
+typedef struct _PsppireButtonEditable      PsppireButtonEditable;
+typedef struct _PsppireButtonEditableClass PsppireButtonEditableClass;
+
+struct _PsppireButtonEditable {
+  GtkButton parent;
+  gchar *path;
+};
+
+struct _PsppireButtonEditableClass {
+  GtkButtonClass parent_class;
+};
+
+GType psppire_button_editable_get_type (void) G_GNUC_CONST;
+PsppireButtonEditable* psppire_button_editable_new (void);
+
+G_END_DECLS
+
+#endif /* PSPPIRE_BUTTON_EDITABLE_H */
diff --git a/src/ui/gui/psppire-cell-renderer-button.c 
b/src/ui/gui/psppire-cell-renderer-button.c
new file mode 100644
index 0000000..6c251ba
--- /dev/null
+++ b/src/ui/gui/psppire-cell-renderer-button.c
@@ -0,0 +1,527 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "ui/gui/psppire-cell-renderer-button.h"
+
+#include <math.h>
+#include <string.h>
+
+#include "ui/gui/psppire-button-editable.h"
+#include "ui/gui/pspp-widget-facade.h"
+
+#include "gl/configmake.h"
+#include "gl/relocatable.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static void psppire_cell_renderer_button_destroy (GtkObject *);
+
+static void update_style_cache (PsppireCellRendererButton *button,
+                                GtkWidget                 *widget);
+
+static void psppire_cell_renderer_button_load_gtkrc (void);
+
+G_DEFINE_TYPE_EXTENDED (PsppireCellRendererButton,
+                        psppire_cell_renderer_button,
+                        GTK_TYPE_CELL_RENDERER,
+                        0,
+                        psppire_cell_renderer_button_load_gtkrc ());
+
+static void
+psppire_cell_renderer_button_load_gtkrc (void)
+{
+  const char *gtkrc_file;
+
+  gtkrc_file = relocate (PKGDATADIR "/psppire.gtkrc");
+  gtk_rc_add_default_file (gtkrc_file);
+  gtk_rc_parse (gtkrc_file);
+}
+
+enum
+  {
+    PROP_0,
+    PROP_EDITABLE,
+    PROP_LABEL
+  };
+
+static void
+psppire_cell_renderer_button_set_property (GObject      *object,
+                                           guint         prop_id,
+                                           const GValue *value,
+                                           GParamSpec   *pspec)
+{
+  PsppireCellRendererButton *obj = PSPPIRE_CELL_RENDERER_BUTTON (object);
+
+  switch (prop_id)
+    {
+    case PROP_EDITABLE:
+      obj->editable = g_value_get_boolean (value);
+      if (obj->editable)
+        GTK_CELL_RENDERER (obj)->mode = GTK_CELL_RENDERER_MODE_EDITABLE;
+      else
+        GTK_CELL_RENDERER (obj)->mode = GTK_CELL_RENDERER_MODE_INERT;
+      break;
+
+    case PROP_LABEL:
+      g_free (obj->label);
+      obj->label = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+psppire_cell_renderer_button_get_property (GObject      *object,
+                                           guint         prop_id,
+                                           GValue       *value,
+                                           GParamSpec   *pspec)
+{
+  PsppireCellRendererButton *obj = PSPPIRE_CELL_RENDERER_BUTTON (object);
+
+  switch (prop_id)
+    {
+    case PROP_EDITABLE:
+      g_value_set_boolean (value, obj->editable);
+      break;
+
+    case PROP_LABEL:
+      g_value_set_string (value, obj->label);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+on_style_set (GtkWidget                 *base,
+              GtkStyle                  *previous_style,
+              PsppireCellRendererButton *button)
+{
+  update_style_cache (button, NULL);
+}
+
+static void
+on_destroy (GtkObject                 *base,
+            PsppireCellRendererButton *button)
+{
+  update_style_cache (button, NULL);
+}
+
+static void
+update_style_cache (PsppireCellRendererButton *button,
+                    GtkWidget                 *widget)
+{
+  if (button->base == widget)
+    return;
+
+  /* Clear old cache. */
+  if (button->button_style)
+    {
+      g_object_unref (button->button_style);
+      button->button_style = NULL;
+    }
+  if (button->label_style)
+    {
+      g_object_unref (button->label_style);
+      button->label_style = NULL;
+    }
+  if (button->base != NULL)
+    {
+      if (button->style_set_handler)
+        {
+          g_signal_handler_disconnect (button->base,
+                                       button->style_set_handler);
+          button->style_set_handler = 0;
+        }
+      if (button->destroy_handler)
+        {
+          g_signal_handler_disconnect (button->base, button->destroy_handler);
+          button->destroy_handler = 0;
+        }
+      g_object_unref (button->base);
+      button->base = NULL;
+    }
+
+  /* Populate cache. */
+  if (widget)
+    {
+      button->button_style = facade_get_style (widget, GTK_TYPE_BUTTON, 0);
+      button->label_style = facade_get_style (widget, GTK_TYPE_BUTTON,
+                                              GTK_TYPE_LABEL, 0);
+      button->base = widget;
+      button->style_set_handler = g_signal_connect (widget, "style-set",
+                                                    G_CALLBACK (on_style_set),
+                                                    button);
+      button->destroy_handler = g_signal_connect (widget, "destroy",
+                                                  G_CALLBACK (on_destroy),
+                                                  button);
+
+      g_object_ref (widget);
+      g_object_ref (button->button_style);
+      g_object_ref (button->label_style);
+    }
+}
+
+static void
+psppire_cell_renderer_button_render (GtkCellRenderer      *cell,
+                                     GdkDrawable          *window,
+                                     GtkWidget            *widget,
+                                     GdkRectangle         *background_area,
+                                     GdkRectangle         *cell_area,
+                                     GdkRectangle         *expose_area,
+                                     GtkCellRendererState  flags)
+{
+  PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
+  GtkStateType state_type;
+
+  if (!button->editable || !cell->sensitive)
+    state_type = GTK_STATE_INSENSITIVE;
+  else if (flags & GTK_CELL_RENDERER_SELECTED)
+    {
+      if (gtk_widget_has_focus (widget))
+        state_type = GTK_STATE_SELECTED;
+      else
+        state_type = GTK_STATE_ACTIVE;
+    }
+  else if (flags & GTK_CELL_RENDERER_PRELIT)
+    state_type = GTK_STATE_PRELIGHT;
+  else
+    {
+      if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
+        state_type = GTK_STATE_INSENSITIVE;
+      else
+        state_type = GTK_STATE_NORMAL;
+    }
+
+  update_style_cache (button, widget);
+  facade_button_render (widget, window, expose_area,
+                        cell_area, button->border_width, button->button_style,
+                        state_type,
+                        button->label_style, button->label, button->xpad,
+                        button->ypad, cell->xalign, cell->yalign);
+}
+
+static void
+psppire_cell_renderer_button_get_size (GtkCellRenderer      *cell,
+                                       GtkWidget            *widget,
+                                       GdkRectangle         *cell_area,
+                                       gint                 *x_offset,
+                                       gint                 *y_offset,
+                                       gint                 *width,
+                                       gint                 *height)
+{
+  PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
+
+  update_style_cache (button, widget);
+  if (cell_area != NULL)
+    {
+      /* The caller is really asking for the placement of the focus rectangle.
+         The focus rectangle should surround the whole label area, so calculate
+         that area. */
+      GtkBorder inset;
+
+      facade_button_get_focus_inset (button->border_width, widget,
+                                     button->button_style, &inset);
+
+      if (x_offset)
+        *x_offset = inset.left;
+      if (y_offset)
+        *y_offset = inset.top;
+      if (width)
+        *width = MAX (1, cell_area->width - inset.left - inset.right);
+      if (height)
+        *height = MAX (1, cell_area->height - inset.top - inset.bottom);
+    }
+  else
+    {
+      /* The caller is asking for the preferred size of the cell. */
+      GtkRequisition label_req;
+      GtkRequisition request;
+
+      facade_label_get_size_request (button->xpad, button->ypad,
+                                     widget, button->label, &label_req);
+      facade_button_get_size_request (button->border_width, widget,
+                                      button->button_style, &label_req,
+                                      &request);
+
+      if (x_offset)
+        *x_offset = 0;
+      if (y_offset)
+        *y_offset = 0;
+      if (width)
+        *width = request.width;
+      if (height)
+        *height = request.height;
+    }
+}
+
+static void
+psppire_cell_renderer_button_clicked (GtkButton *button,
+                                      gpointer   data)
+{
+  PsppireCellRendererButton *cell_button = data;
+  gchar *path;
+
+  g_object_get (button, "path", &path, NULL);
+  g_signal_emit_by_name (cell_button, "clicked", path);
+  g_free (path);
+}
+
+static gboolean
+psppire_cell_renderer_button_focus_out_event (GtkWidget *widget,
+                                              GdkEvent  *event,
+                                              gpointer   data)
+{
+  PsppireCellRendererButton *cell_button = data;
+
+  g_signal_handlers_disconnect_by_func (widget,
+                                        
psppire_cell_renderer_button_focus_out_event,
+                                        data);
+  g_signal_handlers_disconnect_by_func (widget,
+                                        psppire_cell_renderer_button_clicked,
+                                        data);
+
+  gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (cell_button), FALSE);
+
+  return FALSE;
+}
+
+#define IDLE_ID_STRING "psppire-cell-renderer-button-idle-id"
+
+static gboolean
+psppire_cell_renderer_button_initial_click (gpointer data)
+{
+  GtkButton *button = data;
+
+  gtk_button_clicked (button);
+  g_object_steal_data (G_OBJECT (button), IDLE_ID_STRING);
+  return FALSE;
+}
+
+static void
+psppire_cell_renderer_button_on_destroy (GObject *object, gpointer user_data)
+{
+  guint idle_id;
+
+  idle_id = GPOINTER_TO_INT (g_object_steal_data (object, IDLE_ID_STRING));
+  if (idle_id != 0)
+    g_source_remove (idle_id);
+}
+
+static void
+psppire_cell_renderer_button_double_click (GtkButton *button,
+                                           PsppireCellRendererButton 
*cell_button)
+{
+  gchar *path;
+
+  if (g_object_get_data (G_OBJECT (button), IDLE_ID_STRING))
+    psppire_cell_renderer_button_initial_click (button);
+
+  g_object_get (button, "path", &path, NULL);
+  g_signal_emit_by_name (cell_button, "double-clicked", path);
+  g_free (path);
+}
+
+static gboolean
+psppire_cell_renderer_button_press_event (GtkButton      *button,
+                                          GdkEventButton *event,
+                                          gpointer        data)
+{
+  PsppireCellRendererButton *cell_button = data;
+
+  if (cell_button->click_time != 0)
+    {
+      GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
+      GtkSettings *settings = gtk_settings_get_for_screen (screen);
+      gint double_click_distance;
+      gint double_click_time;
+
+      g_object_get (settings,
+                    "gtk-double-click-time", &double_click_time,
+                    "gtk-double-click-distance", &double_click_distance,
+                    NULL);
+
+      if (event->type == GDK_BUTTON_PRESS
+          && event->button == 1
+          && event->time <= cell_button->click_time + double_click_time
+          && ABS (event->x_root - cell_button->click_x) <= 
double_click_distance
+          && ABS (event->y_root - cell_button->click_y) <= 
double_click_distance)
+        {
+          psppire_cell_renderer_button_double_click (button, cell_button);
+          return TRUE;
+        }
+
+      cell_button->click_time = 0;
+    }
+
+  if (event->type == GDK_2BUTTON_PRESS)
+    {
+      psppire_cell_renderer_button_double_click (button, cell_button);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static GtkCellEditable *
+psppire_cell_renderer_button_start_editing (GtkCellRenderer      *cell,
+                                            GdkEvent             *event,
+                                            GtkWidget            *widget,
+                                            const gchar          *path,
+                                            GdkRectangle         
*background_area,
+                                            GdkRectangle         *cell_area,
+                                            GtkCellRendererState  flags)
+{
+  PsppireCellRendererButton *cell_button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
+  gfloat xalign, yalign;
+
+  gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
+  cell_button->button = g_object_new (PSPPIRE_TYPE_BUTTON_EDITABLE,
+                                      "label", cell_button->label,
+                                      "xalign", xalign,
+                                      "yalign", yalign,
+                                      "path", path,
+                                      NULL);
+
+  g_signal_connect (G_OBJECT (cell_button->button), "focus-out-event",
+                    G_CALLBACK (psppire_cell_renderer_button_focus_out_event),
+                    cell);
+  g_signal_connect (G_OBJECT (cell_button->button), "clicked",
+                    G_CALLBACK (psppire_cell_renderer_button_clicked),
+                    cell);
+  g_signal_connect (G_OBJECT (cell_button->button), "button-press-event",
+                    G_CALLBACK (psppire_cell_renderer_button_press_event),
+                    cell);
+
+  gtk_widget_show (cell_button->button);
+
+  if (event != NULL && event->any.type == GDK_BUTTON_RELEASE)
+    {
+      guint idle_id;
+
+      cell_button->click_time = event->button.time;
+      cell_button->click_x = event->button.x_root;
+      cell_button->click_y = event->button.y_root;
+      idle_id = g_idle_add (psppire_cell_renderer_button_initial_click,
+                            cell_button->button);
+      g_object_set_data (G_OBJECT (cell_button->button), IDLE_ID_STRING,
+                         GINT_TO_POINTER (idle_id));
+      g_signal_connect (G_OBJECT (cell_button->button), "destroy",
+                        G_CALLBACK (psppire_cell_renderer_button_on_destroy),
+                        NULL);
+    }
+  else
+    {
+      cell_button->click_time = 0;
+      cell_button->click_x = 0;
+      cell_button->click_y = 0;
+    }
+
+  return GTK_CELL_EDITABLE (cell_button->button);
+}
+
+static void
+psppire_cell_renderer_button_class_init (PsppireCellRendererButtonClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
+  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
+
+  gobject_class->set_property = psppire_cell_renderer_button_set_property;
+  gobject_class->get_property = psppire_cell_renderer_button_get_property;
+
+  gtk_object_class->destroy = psppire_cell_renderer_button_destroy;
+
+  cell_class->get_size = psppire_cell_renderer_button_get_size;
+  cell_class->render = psppire_cell_renderer_button_render;
+  cell_class->start_editing = psppire_cell_renderer_button_start_editing;
+
+  g_signal_new ("clicked",
+                G_TYPE_FROM_CLASS (gobject_class),
+                G_SIGNAL_RUN_LAST,
+                0,
+                NULL, NULL,
+                g_cclosure_marshal_VOID__STRING,
+                G_TYPE_NONE,
+                1, G_TYPE_STRING);
+
+  g_signal_new ("double-clicked",
+                G_TYPE_FROM_CLASS (gobject_class),
+                G_SIGNAL_RUN_LAST,
+                0,
+                NULL, NULL,
+                g_cclosure_marshal_VOID__STRING,
+                G_TYPE_NONE,
+                1, G_TYPE_STRING);
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_EDITABLE,
+                                   g_param_spec_boolean ("editable",
+                                                         _("Editable"),
+                                                         _("Whether the button 
may be clicked."),
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_LABEL,
+                                   g_param_spec_string ("label",
+                                                        _("Label"),
+                                                        _("Text to appear in 
button."),
+                                                        "",
+                                                        G_PARAM_READWRITE));
+}
+
+static void
+psppire_cell_renderer_button_init (PsppireCellRendererButton *obj)
+{
+  obj->editable = FALSE;
+  obj->label = g_strdup ("");
+  obj->border_width = 0;
+  obj->xpad = 0;
+  obj->ypad = 0;
+
+  obj->button = NULL;
+
+  obj->button_style = NULL;
+  obj->label_style = NULL;
+  obj->base = NULL;
+  obj->style_set_handler = 0;
+  obj->destroy_handler = 0;
+}
+
+static void
+psppire_cell_renderer_button_destroy (GtkObject *obj)
+{
+  PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (obj);
+
+  update_style_cache (button, NULL);
+
+  GTK_OBJECT_CLASS (psppire_cell_renderer_button_parent_class)->destroy (obj);
+}
+
+GtkCellRenderer *
+psppire_cell_renderer_button_new (void)
+{
+  return GTK_CELL_RENDERER (g_object_new (PSPPIRE_TYPE_CELL_RENDERER_BUTTON, 
NULL));
+}
diff --git a/src/ui/gui/psppire-cell-renderer-button.h 
b/src/ui/gui/psppire-cell-renderer-button.h
new file mode 100644
index 0000000..821a6e9
--- /dev/null
+++ b/src/ui/gui/psppire-cell-renderer-button.h
@@ -0,0 +1,65 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef PSPPIRE_CELL_RENDERER_BUTTON_H
+#define PSPPIRE_CELL_RENDERER_BUTTON_H 1
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define PSPPIRE_TYPE_CELL_RENDERER_BUTTON             
(psppire_cell_renderer_button_get_type())
+#define PSPPIRE_CELL_RENDERER_BUTTON(obj)             
(G_TYPE_CHECK_INSTANCE_CAST 
((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButton))
+#define PSPPIRE_CELL_RENDERER_BUTTON_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST 
((class),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButtonClass))
+#define PSPPIRE_IS_CELL_RENDERER_BUTTON(obj)          
(G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON))
+#define PSPPIRE_IS_CELL_RENDERER_BUTTON_CLASS(class)  (G_TYPE_CHECK_CLASS_TYPE 
((class),PSPPIRE_TYPE_CELL_RENDERER_BUTTON))
+#define PSPPIRE_CELL_RENDERER_BUTTON_GET_CLASS(obj)   
(G_TYPE_INSTANCE_GET_CLASS 
((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButtonClass))
+
+typedef struct _PsppireCellRendererButton      PsppireCellRendererButton;
+typedef struct _PsppireCellRendererButtonClass PsppireCellRendererButtonClass;
+
+struct _PsppireCellRendererButton {
+  GtkCellRenderer parent;
+
+  gboolean editable;
+  gchar *label;
+  gint border_width;
+  gint xpad;
+  gint ypad;
+
+  GtkWidget *button;
+  guint32 click_time;
+  gdouble click_x;
+  gdouble click_y;
+
+  /* Style caching. */
+  GtkStyle *button_style;
+  GtkStyle *label_style;
+  GtkWidget *base;
+  gulong style_set_handler;
+  gulong destroy_handler;
+};
+
+struct _PsppireCellRendererButtonClass {
+  GtkCellRendererClass parent_class;
+};
+
+GType psppire_cell_renderer_button_get_type (void) G_GNUC_CONST;
+GtkCellRenderer* psppire_cell_renderer_button_new (void);
+
+G_END_DECLS
+
+#endif /* PSPPIRE_CELL_RENDERER_BUTTON_H */
diff --git a/src/ui/gui/psppire.gtkrc b/src/ui/gui/psppire.gtkrc
new file mode 100644
index 0000000..d6c0478
--- /dev/null
+++ b/src/ui/gui/psppire.gtkrc
@@ -0,0 +1,7 @@
+#
+# Avoid making buttons inside the PSPPIRE data sheet and variable sheet
+# extra-tall.  This allows more rows to fit on the screen, making data
+# easier to review.
+#
+style "thinbuttons" { ythickness = 0 }
+widget_class "*<PsppSheetView>*GtkButton" style : rc "thinbuttons"
-- 
1.7.2.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]