X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcellrenderertoggle.c;h=f94ff2a71a04b09382fb2c7b698bd7712cff0034;hb=f9f6c4fa49cb630f169c2fa4ce6b4ed2b44be8f3;hp=6830604b4efa3d01b162b72d50482332a585d7a4;hpb=3ff4a2c081e5225f010ecaed91b162eabbb9caf5;p=~andy%2Fgtk diff --git a/gtk/gtkcellrenderertoggle.c b/gtk/gtkcellrenderertoggle.c index 6830604b4..f94ff2a71 100644 --- a/gtk/gtkcellrenderertoggle.c +++ b/gtk/gtkcellrenderertoggle.c @@ -12,50 +12,59 @@ * 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 - -#ifndef _ -#define _(x) x -#endif - - -static void gtk_cell_renderer_toggle_get_param (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec, - const gchar *trailer); -static void gtk_cell_renderer_toggle_set_param (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec, - const gchar *trailer); -static void gtk_cell_renderer_toggle_init (GtkCellRendererToggle *celltext); -static void gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class); +#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, + GValue *value, + GParamSpec *pspec); +static void gtk_cell_renderer_toggle_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); 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, + cairo_t *cr, GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - guint flags); -static gint gtk_cell_renderer_toggle_event (GtkCellRenderer *cell, - GdkEvent *event, - 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 { @@ -64,50 +73,51 @@ enum { }; enum { - PROP_ZERO, - PROP_STATE, - PROP_RADIO + PROP_0, + PROP_ACTIVATABLE, + PROP_ACTIVE, + 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); - } + 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->state = 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 @@ -116,206 +126,422 @@ gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class) GObjectClass *object_class = G_OBJECT_CLASS (class); GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class); - object_class->get_param = gtk_cell_renderer_toggle_get_param; - object_class->set_param = gtk_cell_renderer_toggle_set_param; + object_class->get_property = gtk_cell_renderer_toggle_get_property; + object_class->set_property = gtk_cell_renderer_toggle_set_property; 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; - - g_object_class_install_param (object_class, - PROP_STATE, - g_param_spec_boolean ("state", - _("Toggle state"), - _("The toggle-state of the button."), - FALSE, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); - - g_object_class_install_param (object_class, - PROP_RADIO, - g_param_spec_boolean ("radio", - _("Radio state"), - _("Draw the toggle button as a radio button."), - FALSE, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); - - + cell_class->activate = gtk_cell_renderer_toggle_activate; + + g_object_class_install_property (object_class, + PROP_ACTIVE, + g_param_spec_boolean ("active", + P_("Toggle state"), + P_("The toggle state of the button"), + FALSE, + 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", + P_("Radio state"), + P_("Draw the toggle button as a radio button"), + FALSE, + 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_NONE__POINTER, - GTK_TYPE_NONE, 1, - GTK_TYPE_POINTER); - - gtk_object_class_add_signals (GTK_OBJECT_CLASS (object_class), toggle_cell_signals, LAST_SIGNAL); + 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 -gtk_cell_renderer_toggle_get_param (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec, - const gchar *trailer) +gtk_cell_renderer_toggle_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) { GtkCellRendererToggle *celltoggle = GTK_CELL_RENDERER_TOGGLE (object); + GtkCellRendererTogglePrivate *priv = celltoggle->priv; switch (param_id) { - case PROP_STATE: - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, celltoggle->state); + case PROP_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_init (value, G_TYPE_BOOLEAN); - 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); break; } } static void -gtk_cell_renderer_toggle_set_param (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec, - const gchar *trailer) +gtk_cell_renderer_toggle_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) { GtkCellRendererToggle *celltoggle = GTK_CELL_RENDERER_TOGGLE (object); + GtkCellRendererTogglePrivate *priv = celltoggle->priv; switch (param_id) { - case PROP_STATE: - celltoggle->state = g_value_get_boolean (value); + case PROP_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); + 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); break; } } +/** + * 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 + * can bind a property to a value in a #GtkTreeModel. For example, you + * 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; - - 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); - gdk_gc_set_clip_rectangle (widget->style->black_gc, cell_area); + if (!priv->activatable) + state |= GTK_STATE_FLAG_INSENSITIVE; - 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) { - gdk_draw_rectangle (window, - widget->style->black_gc, - FALSE, - cell_area->x + real_xoffset, - cell_area->y + real_yoffset, - width, height); - if (celltoggle->state) - { - gdk_draw_line (window, - widget->style->black_gc, - cell_area->x + real_xoffset, - cell_area->y + real_yoffset, - cell_area->x + real_xoffset + width, - cell_area->y + real_yoffset + height); - gdk_draw_line (window, - widget->style->black_gc, - cell_area->x + real_xoffset + width, - cell_area->y + real_yoffset, - cell_area->x + real_xoffset, - cell_area->y + real_yoffset + 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 { - gdk_draw_arc (window, - widget->style->black_gc, - FALSE, - cell_area->x + real_xoffset, - cell_area->y + real_yoffset, - width, - height, - 0, 360*64); - if (celltoggle->state) - { - gdk_draw_arc (window, - widget->style->black_gc, - TRUE, - cell_area->x + real_xoffset + 2, - cell_area->y + real_yoffset + 2, - width - 4, - height - 4, - 0, 360*64); - } + 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); } - - gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL); + 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) { - gtk_signal_emit (GTK_OBJECT (cell), toggle_cell_signals[TOGGLED], path); - return TRUE; + GtkCellRendererTogglePrivate *priv; + GtkCellRendererToggle *celltoggle; + + celltoggle = GTK_CELL_RENDERER_TOGGLE (cell); + priv = celltoggle->priv; + + if (priv->activatable) + { + g_signal_emit (cell, toggle_cell_signals[TOGGLED], 0, path); + return TRUE; + } + + return FALSE; } +/** + * gtk_cell_renderer_toggle_set_radio: + * @toggle: a #GtkCellRendererToggle + * @radio: %TRUE to make the toggle look like a radio button + * + * If @radio is %TRUE, the cell renderer renders a radio toggle + * (i.e. a toggle in a group of mutually-exclusive toggles). + * If %FALSE, it renders a check toggle (a standalone boolean option). + * This can be set globally for the cell renderer, or changed just + * before rendering each cell in the model (for #GtkTreeView, you set + * up a per-row setting using #GtkTreeViewColumn to associate model + * columns with cell renderer properties). + **/ void gtk_cell_renderer_toggle_set_radio (GtkCellRendererToggle *toggle, gboolean radio) { - g_return_if_fail (toggle != NULL); + GtkCellRendererTogglePrivate *priv; + + g_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle)); + + 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 + **/ +gboolean +gtk_cell_renderer_toggle_get_radio (GtkCellRendererToggle *toggle) +{ + g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle), FALSE); + + 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->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 (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)); - toggle->radio = radio; + priv = toggle->priv; + + if (priv->activatable != setting) + { + priv->activatable = setting ? TRUE : FALSE; + g_object_notify (G_OBJECT (toggle), "activatable"); + } }