From: Ben Pfaff Date: Tue, 24 Apr 2012 05:49:30 +0000 (-0700) Subject: psppire-cell-renderer-button: New cell renderer for GtkButton. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=f95002ec226b18f52773e747cae7e1d00302ad1a psppire-cell-renderer-button: New cell renderer for GtkButton. This allows one to put a clickable GtkButton inside a PsppSheetView row. --- diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index e184975e5c..cbeb490ea4 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-private.h \ @@ -142,6 +142,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 83f0b6462d..966111d425 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 0000000000..cefc7a594d --- /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 . */ + +#include + +#include "ui/gui/psppire-button-editable.h" + +#include +#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 0000000000..7949b876c7 --- /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 . */ + +#ifndef PSPPIRE_BUTTON_EDITABLE_H +#define PSPPIRE_BUTTON_EDITABLE_H 1 + +#include + +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 0000000000..6f72698425 --- /dev/null +++ b/src/ui/gui/psppire-cell-renderer-button.c @@ -0,0 +1,538 @@ +/* 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 . */ + +#include + +#include "ui/gui/psppire-cell-renderer-button.h" + +#include +#include + +#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 psppire_cell_renderer_button_finalize (GObject *); + +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; + gobject_class->finalize = psppire_cell_renderer_button_finalize; + + 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_finalize (GObject *obj) +{ + PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (obj); + + g_free (button->label); +} + +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 0000000000..821a6e9ea4 --- /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 . */ + +#ifndef PSPPIRE_CELL_RENDERER_BUTTON_H +#define PSPPIRE_CELL_RENDERER_BUTTON_H 1 + +#include + +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 0000000000..d6c04787d2 --- /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 "**GtkButton" style : rc "thinbuttons"