X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcellrenderertoggle.c;h=f94ff2a71a04b09382fb2c7b698bd7712cff0034;hb=6f1476edd3fbe31259e59ca3f03a01bf0f8ff67b;hp=66f20eccae27107b36c8e3f52f3055656acdc33c;hpb=35af5c4eba6c95646a5719bae796ece1dbf92275;p=~andy%2Fgtk diff --git a/gtk/gtkcellrenderertoggle.c b/gtk/gtkcellrenderertoggle.c index 66f20ecca..f94ff2a71 100644 --- a/gtk/gtkcellrenderertoggle.c +++ b/gtk/gtkcellrenderertoggle.c @@ -12,15 +12,30 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ +#include "config.h" #include -#include -#include +#include "gtkcellrenderertoggle.h" #include "gtkintl.h" +#include "gtkmarshalers.h" +#include "gtkprivate.h" +#include "gtktreeprivate.h" +#include "a11y/gtkbooleancellaccessible.h" + + +/** + * SECTION:gtkcellrenderertoggle + * @Short_description: Renders a toggle button in a cell + * @Title: GtkCellRendererToggle + * + * #GtkCellRendererToggle renders a toggle button in a cell. The + * button is drawn as a radio or a checkbutton, depending on the + * #GtkCellRendererToggle:radio property. + * When activated, it emits the #GtkCellRendererToggle::toggled signal. + */ + static void gtk_cell_renderer_toggle_get_property (GObject *object, guint param_id, @@ -30,26 +45,26 @@ static void gtk_cell_renderer_toggle_set_property (GObject * guint param_id, const GValue *value, GParamSpec *pspec); -static void gtk_cell_renderer_toggle_init (GtkCellRendererToggle *celltext); -static void gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class); static void gtk_cell_renderer_toggle_get_size (GtkCellRenderer *cell, GtkWidget *widget, + const GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, gint *width, gint *height); static void gtk_cell_renderer_toggle_render (GtkCellRenderer *cell, - GdkWindow *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - guint flags); -static gint gtk_cell_renderer_toggle_event (GtkCellRenderer *cell, - GdkEvent *event, + cairo_t *cr, GtkWidget *widget, - gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - guint flags); + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags); +static gboolean gtk_cell_renderer_toggle_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags); enum { @@ -58,50 +73,51 @@ enum { }; enum { - PROP_ZERO, + PROP_0, + PROP_ACTIVATABLE, PROP_ACTIVE, - PROP_RADIO + PROP_RADIO, + PROP_INCONSISTENT, + PROP_INDICATOR_SIZE }; - -#define TOGGLE_WIDTH 12 +#define TOGGLE_WIDTH 16 static guint toggle_cell_signals[LAST_SIGNAL] = { 0 }; - -GtkType -gtk_cell_renderer_toggle_get_type (void) +struct _GtkCellRendererTogglePrivate { - static GtkType cell_toggle_type = 0; + gint indicator_size; - if (!cell_toggle_type) - { - static const GTypeInfo cell_toggle_info = - { - sizeof (GtkCellRendererToggleClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_cell_renderer_toggle_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkCellRendererToggle), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_cell_renderer_toggle_init, - }; - - cell_toggle_type = g_type_register_static (GTK_TYPE_CELL_RENDERER, "GtkCellRendererToggle", &cell_toggle_info, 0); - } + guint active : 1; + guint activatable : 1; + guint inconsistent : 1; + guint radio : 1; +}; + + +G_DEFINE_TYPE (GtkCellRendererToggle, gtk_cell_renderer_toggle, GTK_TYPE_CELL_RENDERER) - return cell_toggle_type; -} static void gtk_cell_renderer_toggle_init (GtkCellRendererToggle *celltoggle) { - celltoggle->active = FALSE; - celltoggle->radio = FALSE; - GTK_CELL_RENDERER (celltoggle)->xpad = 2; - GTK_CELL_RENDERER (celltoggle)->ypad = 2; + GtkCellRendererTogglePrivate *priv; + + celltoggle->priv = G_TYPE_INSTANCE_GET_PRIVATE (celltoggle, + GTK_TYPE_CELL_RENDERER_TOGGLE, + GtkCellRendererTogglePrivate); + priv = celltoggle->priv; + + priv->activatable = TRUE; + priv->active = FALSE; + priv->radio = FALSE; + + g_object_set (celltoggle, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); + gtk_cell_renderer_set_padding (GTK_CELL_RENDERER (celltoggle), 2, 2); + + priv->indicator_size = TOGGLE_WIDTH; + priv->inconsistent = FALSE; } static void @@ -115,35 +131,72 @@ gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class) cell_class->get_size = gtk_cell_renderer_toggle_get_size; cell_class->render = gtk_cell_renderer_toggle_render; - cell_class->event = gtk_cell_renderer_toggle_event; + cell_class->activate = gtk_cell_renderer_toggle_activate; g_object_class_install_property (object_class, PROP_ACTIVE, g_param_spec_boolean ("active", - _("Toggle state"), - _("The toggle state of the button"), + P_("Toggle state"), + P_("The toggle state of the button"), FALSE, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); + GTK_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_INCONSISTENT, + g_param_spec_boolean ("inconsistent", + P_("Inconsistent state"), + P_("The inconsistent state of the button"), + FALSE, + GTK_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ACTIVATABLE, + g_param_spec_boolean ("activatable", + P_("Activatable"), + P_("The toggle button can be activated"), + TRUE, + GTK_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_RADIO, g_param_spec_boolean ("radio", - _("Radio state"), - _("Draw the toggle button as a radio button"), + P_("Radio state"), + P_("Draw the toggle button as a radio button"), FALSE, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); + GTK_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_INDICATOR_SIZE, + g_param_spec_int ("indicator-size", + P_("Indicator size"), + P_("Size of check or radio indicator"), + 0, + G_MAXINT, + TOGGLE_WIDTH, + GTK_PARAM_READWRITE)); + + /** + * GtkCellRendererToggle::toggled: + * @cell_renderer: the object which received the signal + * @path: string representation of #GtkTreePath describing the + * event location + * + * The ::toggled signal is emitted when the cell is toggled. + **/ toggle_cell_signals[TOGGLED] = - gtk_signal_new ("toggled", - GTK_RUN_LAST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkCellRendererToggleClass, toggled), - gtk_marshal_VOID__POINTER, - GTK_TYPE_NONE, 1, - GTK_TYPE_POINTER); + g_signal_new (I_("toggled"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCellRendererToggleClass, toggled), + NULL, NULL, + _gtk_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + g_type_class_add_private (object_class, sizeof (GtkCellRendererTogglePrivate)); + + gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_BOOLEAN_CELL_ACCESSIBLE); } static void @@ -153,14 +206,24 @@ gtk_cell_renderer_toggle_get_property (GObject *object, GParamSpec *pspec) { GtkCellRendererToggle *celltoggle = GTK_CELL_RENDERER_TOGGLE (object); - + GtkCellRendererTogglePrivate *priv = celltoggle->priv; + switch (param_id) { case PROP_ACTIVE: - g_value_set_boolean (value, celltoggle->active); + g_value_set_boolean (value, priv->active); + break; + case PROP_INCONSISTENT: + g_value_set_boolean (value, priv->inconsistent); + break; + case PROP_ACTIVATABLE: + g_value_set_boolean (value, priv->activatable); break; case PROP_RADIO: - g_value_set_boolean (value, celltoggle->radio); + g_value_set_boolean (value, priv->radio); + break; + case PROP_INDICATOR_SIZE: + g_value_set_int (value, priv->indicator_size); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -176,16 +239,24 @@ gtk_cell_renderer_toggle_set_property (GObject *object, GParamSpec *pspec) { GtkCellRendererToggle *celltoggle = GTK_CELL_RENDERER_TOGGLE (object); - + GtkCellRendererTogglePrivate *priv = celltoggle->priv; + switch (param_id) { case PROP_ACTIVE: - celltoggle->active = g_value_get_boolean (value); - g_object_notify (G_OBJECT(object), "active"); + priv->active = g_value_get_boolean (value); + break; + case PROP_INCONSISTENT: + priv->inconsistent = g_value_get_boolean (value); + break; + case PROP_ACTIVATABLE: + priv->activatable = g_value_get_boolean (value); break; case PROP_RADIO: - celltoggle->radio = g_value_get_boolean (value); - g_object_notify (G_OBJECT(object), "radio"); + priv->radio = g_value_get_boolean (value); + break; + case PROP_INDICATOR_SIZE: + priv->indicator_size = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -195,7 +266,7 @@ gtk_cell_renderer_toggle_set_property (GObject *object, /** * gtk_cell_renderer_toggle_new: - * + * * Creates a new #GtkCellRendererToggle. Adjust rendering * parameters using object properties. Object properties can be set * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you @@ -203,111 +274,156 @@ gtk_cell_renderer_toggle_set_property (GObject *object, * can bind the "active" property on the cell renderer to a boolean value * in the model, thus causing the check button to reflect the state of * the model. - * + * * Return value: the new cell renderer **/ GtkCellRenderer * gtk_cell_renderer_toggle_new (void) { - return GTK_CELL_RENDERER (gtk_type_new (gtk_cell_renderer_toggle_get_type ())); + return g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE, NULL); } static void -gtk_cell_renderer_toggle_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - gint *width, - gint *height) +gtk_cell_renderer_toggle_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + const GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) { + GtkCellRendererTogglePrivate *priv; + gint calc_width; + gint calc_height; + gint xpad, ypad; + + priv = GTK_CELL_RENDERER_TOGGLE (cell)->priv; + + gtk_cell_renderer_get_padding (cell, &xpad, &ypad); + calc_width = xpad * 2 + priv->indicator_size; + calc_height = ypad * 2 + priv->indicator_size; + if (width) - *width = (gint) cell->xpad * 2 + TOGGLE_WIDTH; + *width = calc_width; if (height) - *height = (gint) cell->ypad * 2 + TOGGLE_WIDTH; + *height = calc_height; + + if (cell_area) + { + gfloat xalign, yalign; + + gtk_cell_renderer_get_alignment (cell, &xalign, &yalign); + + if (x_offset) + { + *x_offset = ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ? + (1.0 - xalign) : xalign) * (cell_area->width - calc_width); + *x_offset = MAX (*x_offset, 0); + } + if (y_offset) + { + *y_offset = yalign * (cell_area->height - calc_height); + *y_offset = MAX (*y_offset, 0); + } + } + else + { + if (x_offset) *x_offset = 0; + if (y_offset) *y_offset = 0; + } } static void -gtk_cell_renderer_toggle_render (GtkCellRenderer *cell, - GdkWindow *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - guint flags) +gtk_cell_renderer_toggle_render (GtkCellRenderer *cell, + cairo_t *cr, + GtkWidget *widget, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags) { - GtkCellRendererToggle *celltoggle = (GtkCellRendererToggle *) cell; + GtkCellRendererToggle *celltoggle = GTK_CELL_RENDERER_TOGGLE (cell); + GtkCellRendererTogglePrivate *priv = celltoggle->priv; + GtkStyleContext *context; gint width, height; - gint real_xoffset, real_yoffset; - GtkShadowType shadow; - GtkStateType state; - - width = MIN (TOGGLE_WIDTH, cell_area->width - cell->xpad * 2); - height = MIN (TOGGLE_WIDTH, cell_area->height - cell->ypad * 2); + gint x_offset, y_offset; + gint xpad, ypad; + GtkStateFlags state; + + context = gtk_widget_get_style_context (widget); + gtk_cell_renderer_toggle_get_size (cell, widget, cell_area, + &x_offset, &y_offset, + &width, &height); + gtk_cell_renderer_get_padding (cell, &xpad, &ypad); + width -= xpad * 2; + height -= ypad * 2; if (width <= 0 || height <= 0) return; - real_xoffset = cell->xalign * (cell_area->width - width - (2 * cell->xpad)); - real_xoffset = MAX (real_xoffset, 0) + cell->xpad; - real_yoffset = cell->yalign * (cell_area->height - height - (2 * cell->ypad)); - real_yoffset = MAX (real_yoffset, 0) + cell->ypad; + state = gtk_cell_renderer_get_state (cell, widget, flags); - shadow = celltoggle->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + if (!priv->activatable) + state |= GTK_STATE_FLAG_INSENSITIVE; - if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) - state = GTK_STATE_SELECTED; - else - state = GTK_STATE_NORMAL; - - if (celltoggle->radio) + state &= ~(GTK_STATE_FLAG_INCONSISTENT | GTK_STATE_FLAG_ACTIVE); + + if (priv->inconsistent) + state |= GTK_STATE_FLAG_INCONSISTENT; + else if (priv->active) + state |= GTK_STATE_FLAG_ACTIVE; + + cairo_save (cr); + + gdk_cairo_rectangle (cr, cell_area); + cairo_clip (cr); + + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + + if (priv->radio) { - gtk_paint_option (widget->style, - window, - state, shadow, - cell_area, widget, "cellradio", - cell_area->x + real_xoffset, - cell_area->y + real_yoffset, - width, height); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RADIO); + gtk_render_option (context, cr, + cell_area->x + x_offset + xpad, + cell_area->y + y_offset + ypad, + width, height); } else { - gtk_paint_check (widget->style, - window, - state, shadow, - cell_area, widget, "cellcheck", - cell_area->x + real_xoffset, - cell_area->y + real_yoffset, - width, height); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_CHECK); + gtk_render_check (context, cr, + cell_area->x + x_offset + xpad, + cell_area->y + y_offset + ypad, + width, height); } + + gtk_style_context_restore (context); + cairo_restore (cr); } static gint -gtk_cell_renderer_toggle_event (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - guint flags) +gtk_cell_renderer_toggle_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags) { + GtkCellRendererTogglePrivate *priv; GtkCellRendererToggle *celltoggle; - gint retval = FALSE; - + celltoggle = GTK_CELL_RENDERER_TOGGLE (cell); - - switch (event->type) - { - case GDK_BUTTON_PRESS: - { - gtk_signal_emit (GTK_OBJECT (cell), toggle_cell_signals[TOGGLED], path); - retval = TRUE; - } - break; + priv = celltoggle->priv; - default: - break; + if (priv->activatable) + { + g_signal_emit (cell, toggle_cell_signals[TOGGLED], 0, path); + return TRUE; } - - return retval; + + return FALSE; } /** @@ -327,14 +443,20 @@ void gtk_cell_renderer_toggle_set_radio (GtkCellRendererToggle *toggle, gboolean radio) { + GtkCellRendererTogglePrivate *priv; + g_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle)); - toggle->radio = radio; + priv = toggle->priv; + + priv->radio = radio; } /** * gtk_cell_renderer_toggle_get_radio: * @toggle: a #GtkCellRendererToggle + * + * Returns whether we're rendering radio toggles rather than checkboxes. * * Return value: %TRUE if we're rendering radio toggles rather than checkboxes **/ @@ -343,22 +465,83 @@ gtk_cell_renderer_toggle_get_radio (GtkCellRendererToggle *toggle) { g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle), FALSE); - return toggle->radio; + return toggle->priv->radio; } +/** + * gtk_cell_renderer_toggle_get_active: + * @toggle: a #GtkCellRendererToggle + * + * Returns whether the cell renderer is active. See + * gtk_cell_renderer_toggle_set_active(). + * + * Return value: %TRUE if the cell renderer is active. + **/ gboolean gtk_cell_renderer_toggle_get_active (GtkCellRendererToggle *toggle) { g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle), FALSE); - return toggle->active; + return toggle->priv->active; } +/** + * gtk_cell_renderer_toggle_set_active: + * @toggle: a #GtkCellRendererToggle. + * @setting: the value to set. + * + * Activates or deactivates a cell renderer. + **/ void gtk_cell_renderer_toggle_set_active (GtkCellRendererToggle *toggle, gboolean setting) { g_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle)); - g_object_set (G_OBJECT (toggle), "active", !! setting, NULL); + g_object_set (toggle, "active", setting ? TRUE : FALSE, NULL); +} + +/** + * gtk_cell_renderer_toggle_get_activatable: + * @toggle: a #GtkCellRendererToggle + * + * Returns whether the cell renderer is activatable. See + * gtk_cell_renderer_toggle_set_activatable(). + * + * Return value: %TRUE if the cell renderer is activatable. + * + * Since: 2.18 + **/ +gboolean +gtk_cell_renderer_toggle_get_activatable (GtkCellRendererToggle *toggle) +{ + g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle), FALSE); + + return toggle->priv->activatable; +} + +/** + * gtk_cell_renderer_toggle_set_activatable: + * @toggle: a #GtkCellRendererToggle. + * @setting: the value to set. + * + * Makes the cell renderer activatable. + * + * Since: 2.18 + **/ +void +gtk_cell_renderer_toggle_set_activatable (GtkCellRendererToggle *toggle, + gboolean setting) +{ + GtkCellRendererTogglePrivate *priv; + + g_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle)); + + priv = toggle->priv; + + if (priv->activatable != setting) + { + priv->activatable = setting ? TRUE : FALSE; + g_object_notify (G_OBJECT (toggle), "activatable"); + } }