Compare commits

...

5 Commits

Author SHA1 Message Date
Ryan Lortie
8713d6bff6 GtkButton: move GtkToggleButton functionality up
Move 'active', 'inconsistent' and 'toggled' functionality from
GtkToggleButton into GtkButton.  Nuke GtkToggleButtonPrivate.  Remove
the special enter/leave/press/release handles for toggle as well as the
state update function and merge its logic into the GtkButton one.
2010-12-01 02:14:52 -05:00
Ryan Lortie
9a01b164e3 GtkButton: 'is-toggle' was a mistake
Do it differently.
2010-12-01 01:23:23 -05:00
Ryan Lortie
7c7a10c7c1 GtkButton: remove some unused variables 2010-12-01 01:18:54 -05:00
Ryan Lortie
1a423ac766 More GtkButton cleanup
Patch from Matthias in bug #636101 to merge drawing code up and turn the
subclasses into empty shells.
2010-12-01 01:10:41 -05:00
Ryan Lortie
da39db7b2f GtkButton: link to a GAction
Link GtkButton to GAction and track the state of the action.

Make the 'active' state of GtkToggleButton decided from the state of the
GAction.  Do no internal tracking of this state.

Bug #636108
2010-12-01 01:08:57 -05:00
10 changed files with 812 additions and 821 deletions

View File

@@ -76,6 +76,7 @@ enum {
ENTER, ENTER,
LEAVE, LEAVE,
ACTIVATE, ACTIVATE,
TOGGLED,
LAST_SIGNAL LAST_SIGNAL
}; };
@@ -90,6 +91,10 @@ enum {
PROP_XALIGN, PROP_XALIGN,
PROP_YALIGN, PROP_YALIGN,
PROP_IMAGE_POSITION, PROP_IMAGE_POSITION,
PROP_ACTION,
PROP_INDICATOR_STYLE,
PROP_ACTIVE,
PROP_INCONSISTENT,
/* activatable properties */ /* activatable properties */
PROP_ACTIVATABLE_RELATED_ACTION, PROP_ACTIVATABLE_RELATED_ACTION,
@@ -99,6 +104,7 @@ enum {
static void gtk_button_destroy (GtkWidget *widget); static void gtk_button_destroy (GtkWidget *widget);
static void gtk_button_dispose (GObject *object); static void gtk_button_dispose (GObject *object);
static void gtk_button_finalize (GObject *object);
static void gtk_button_set_property (GObject *object, static void gtk_button_set_property (GObject *object,
guint prop_id, guint prop_id,
const GValue *value, const GValue *value,
@@ -188,6 +194,7 @@ gtk_button_class_init (GtkButtonClass *klass)
gobject_class->dispose = gtk_button_dispose; gobject_class->dispose = gtk_button_dispose;
gobject_class->set_property = gtk_button_set_property; gobject_class->set_property = gtk_button_set_property;
gobject_class->get_property = gtk_button_get_property; gobject_class->get_property = gtk_button_get_property;
gobject_class->finalize = gtk_button_finalize;
widget_class->get_preferred_width = gtk_button_get_preferred_width; widget_class->get_preferred_width = gtk_button_get_preferred_width;
widget_class->get_preferred_height = gtk_button_get_preferred_height; widget_class->get_preferred_height = gtk_button_get_preferred_height;
@@ -330,6 +337,46 @@ gtk_button_class_init (GtkButtonClass *klass)
GTK_POS_LEFT, GTK_POS_LEFT,
GTK_PARAM_READWRITE)); GTK_PARAM_READWRITE));
/**
* GtkButton:action:
*
* The #GAction that the button activates.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_ACTION,
g_param_spec_object ("action",
P_("Action"),
P_("The GAction that the button activates."),
G_TYPE_ACTION,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_INDICATOR_STYLE,
g_param_spec_enum ("indicator-style",
P_("Indicator style"),
P_("Whether the button looks like a plain button, check or radio button"),
GTK_TYPE_INDICATOR_STYLE,
GTK_INDICATOR_STYLE_PLAIN,
GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ACTIVE,
g_param_spec_boolean ("active",
P_("Active"),
P_("If the toggle button should be pressed in"),
FALSE,
GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_INCONSISTENT,
g_param_spec_boolean ("inconsistent",
P_("Inconsistent"),
P_("If the toggle button is in an \"in between\" state"),
FALSE,
GTK_PARAM_READWRITE));
g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action"); g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance"); g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
@@ -435,6 +482,15 @@ gtk_button_class_init (GtkButtonClass *klass)
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
widget_class->activate_signal = button_signals[ACTIVATE]; widget_class->activate_signal = button_signals[ACTIVATE];
button_signals[TOGGLED] =
g_signal_new (I_("toggled"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkButtonClass, toggled),
NULL, NULL,
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/** /**
* GtkButton:default-border: * GtkButton:default-border:
* *
@@ -526,6 +582,20 @@ gtk_button_class_init (GtkButtonClass *klass)
2, 2,
GTK_PARAM_READABLE)); GTK_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("indicator-size",
P_("Indicator Size"),
P_("Size of check or radio indicator"),
0, G_MAXINT, 13,
GTK_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("indicator-spacing",
P_("Indicator Spacing"),
P_("Spacing around check or radio indicator"),
0, G_MAXINT, 2,
GTK_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate)); g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate));
} }
@@ -561,6 +631,7 @@ gtk_button_init (GtkButton *button)
priv->image_is_stock = TRUE; priv->image_is_stock = TRUE;
priv->image_position = GTK_POS_LEFT; priv->image_position = GTK_POS_LEFT;
priv->use_action_appearance = TRUE; priv->use_action_appearance = TRUE;
priv->indicator_style = GTK_INDICATOR_STYLE_PLAIN;
} }
static void static void
@@ -578,6 +649,77 @@ gtk_button_destroy (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_button_parent_class)->destroy (widget); GTK_WIDGET_CLASS (gtk_button_parent_class)->destroy (widget);
} }
static void
gtk_button_action_state_changed (GAction *action,
GParamSpec *pspec,
gpointer user_data)
{
GtkButton *button = GTK_BUTTON (user_data);
GVariant *state;
gboolean active;
state = g_action_get_state (action);
active = g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN) &&
g_variant_get_boolean (state);
if (active != button->priv->active)
{
button->priv->active = active;
gtk_button_toggled (button);
gtk_button_update_state (button);
g_object_notify (G_OBJECT (button), "active");
}
g_variant_unref (state);
}
static void
gtk_button_release_action (GtkButton *button)
{
if (button->priv->state_id)
g_signal_handler_disconnect (button->priv->g_action,
button->priv->state_id);
if (button->priv->g_action)
g_object_unref (button->priv->g_action);
button->priv->state_id = 0;
}
static void
gtk_button_setup_action (GtkButton *button)
{
GVariant *state;
gboolean active;
state = g_action_get_state (button->priv->g_action);
if (state != NULL)
{
button->priv->state_id =
g_signal_connect (button->priv->g_action, "notify::state",
G_CALLBACK (gtk_button_action_state_changed), button);
active = g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN) &&
g_variant_get_boolean (state);
g_variant_unref (state);
}
else
active = FALSE;
if (active != button->priv->active)
{
button->priv->active = active;
gtk_button_toggled (button);
gtk_button_update_state (button);
g_object_notify (G_OBJECT (button), "active");
}
}
static GObject* static GObject*
gtk_button_constructor (GType type, gtk_button_constructor (GType type,
guint n_construct_properties, guint n_construct_properties,
@@ -596,9 +738,22 @@ gtk_button_constructor (GType type,
priv->constructed = TRUE; priv->constructed = TRUE;
if (priv->g_action == NULL)
{
priv->g_action = G_ACTION (g_simple_action_new ("anonymous", NULL));
gtk_button_setup_action (button);
}
if (priv->label_text != NULL) if (priv->label_text != NULL)
gtk_button_construct_child (button); gtk_button_construct_child (button);
/* This should be a default handler, but for compatibility reasons
* we need to support derived classes that don't chain up their
* clicked handler.
*/
g_signal_connect_after (button, "clicked",
G_CALLBACK (gtk_real_button_clicked), NULL);
return object; return object;
} }
@@ -662,9 +817,21 @@ gtk_button_dispose (GObject *object)
gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL); gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL);
priv->action = NULL; priv->action = NULL;
} }
G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object); G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object);
} }
static void
gtk_button_finalize (GObject *object)
{
GtkButton *button = GTK_BUTTON (object);
gtk_button_release_action (button);
G_OBJECT_CLASS (gtk_button_parent_class)
->finalize (object);
}
static void static void
gtk_button_set_property (GObject *object, gtk_button_set_property (GObject *object,
guint prop_id, guint prop_id,
@@ -703,6 +870,19 @@ gtk_button_set_property (GObject *object,
case PROP_IMAGE_POSITION: case PROP_IMAGE_POSITION:
gtk_button_set_image_position (button, g_value_get_enum (value)); gtk_button_set_image_position (button, g_value_get_enum (value));
break; break;
case PROP_ACTION:
if (g_value_get_object (value) != NULL)
gtk_button_set_action (button, g_value_get_object (value));
break;
case PROP_INDICATOR_STYLE:
gtk_button_set_indicator_style (button, g_value_get_enum (value));
break;
case PROP_ACTIVE:
gtk_button_set_active (button, g_value_get_boolean (value));
break;
case PROP_INCONSISTENT:
gtk_button_set_inconsistent (button, g_value_get_boolean (value));
break;
case PROP_ACTIVATABLE_RELATED_ACTION: case PROP_ACTIVATABLE_RELATED_ACTION:
gtk_button_set_related_action (button, g_value_get_object (value)); gtk_button_set_related_action (button, g_value_get_object (value));
break; break;
@@ -753,6 +933,18 @@ gtk_button_get_property (GObject *object,
case PROP_IMAGE_POSITION: case PROP_IMAGE_POSITION:
g_value_set_enum (value, priv->image_position); g_value_set_enum (value, priv->image_position);
break; break;
case PROP_ACTION:
g_value_set_object (value, priv->g_action);
break;
case PROP_INDICATOR_STYLE:
g_value_set_enum (value, priv->indicator_style);
break;
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_RELATED_ACTION: case PROP_ACTIVATABLE_RELATED_ACTION:
g_value_set_object (value, priv->action); g_value_set_object (value, priv->action);
break; break;
@@ -893,6 +1085,32 @@ gtk_button_sync_action_properties (GtkActivatable *activatable,
} }
} }
GAction *
gtk_button_get_action (GtkButton *button)
{
g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
return button->priv->g_action;
}
void
gtk_button_set_action (GtkButton *button,
GAction *action)
{
g_return_if_fail (GTK_IS_BUTTON (button));
g_return_if_fail (G_IS_ACTION (action));
if (button->priv->g_action != action)
{
g_object_freeze_notify (G_OBJECT (button));
gtk_button_release_action (button);
button->priv->g_action = g_object_ref (action);
gtk_button_setup_action (button);
g_object_notify (G_OBJECT (button), "action");
g_object_thaw_notify (G_OBJECT (button));
}
}
static void static void
gtk_button_set_related_action (GtkButton *button, gtk_button_set_related_action (GtkButton *button,
GtkAction *action) GtkAction *action)
@@ -902,15 +1120,6 @@ gtk_button_set_related_action (GtkButton *button,
if (priv->action == action) if (priv->action == action)
return; return;
/* This should be a default handler, but for compatibility reasons
* we need to support derived classes that don't chain up their
* clicked handler.
*/
g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);
if (action)
g_signal_connect_after (button, "clicked",
G_CALLBACK (gtk_real_button_clicked), NULL);
gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), action); gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), action);
priv->action = action; priv->action = action;
@@ -1779,6 +1988,7 @@ gtk_real_button_pressed (GtkButton *button)
priv->button_down = TRUE; priv->button_down = TRUE;
gtk_button_update_state (button); gtk_button_update_state (button);
gtk_widget_queue_draw (GTK_WIDGET (button));
} }
static void static void
@@ -1797,6 +2007,7 @@ gtk_real_button_released (GtkButton *button)
gtk_button_clicked (button); gtk_button_clicked (button);
gtk_button_update_state (button); gtk_button_update_state (button);
gtk_widget_queue_draw (GTK_WIDGET (button));
} }
} }
@@ -1807,6 +2018,9 @@ gtk_real_button_clicked (GtkButton *button)
if (priv->action) if (priv->action)
gtk_action_activate (priv->action); gtk_action_activate (priv->action);
if (priv->g_action)
g_action_activate (priv->g_action, NULL);
} }
static gboolean static gboolean
@@ -2255,15 +2469,22 @@ static void
gtk_button_update_state (GtkButton *button) gtk_button_update_state (GtkButton *button)
{ {
GtkButtonPrivate *priv = button->priv; GtkButtonPrivate *priv = button->priv;
gboolean depressed, touchscreen;
GtkStateType new_state; GtkStateType new_state;
gboolean depressed;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (button)),
"gtk-touchscreen-mode", &touchscreen,
NULL);
if (priv->activate_timeout) if (priv->activate_timeout)
depressed = priv->depress_on_activate; depressed = priv->depress_on_activate;
else if (priv->in_button && priv->button_down)
depressed = TRUE;
else else
depressed = priv->in_button && priv->button_down; depressed = button->priv->active;
if (priv->in_button && (!priv->button_down || !depressed)) if (!touchscreen && button->priv->in_button &&
(!button->priv->button_down || button->priv->indicator_style != GTK_INDICATOR_STYLE_PLAIN))
new_state = GTK_STATE_PRELIGHT; new_state = GTK_STATE_PRELIGHT;
else else
new_state = depressed ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL; new_state = depressed ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL;
@@ -2517,3 +2738,120 @@ gtk_button_get_event_window (GtkButton *button)
return button->priv->event_window; return button->priv->event_window;
} }
void
gtk_button_set_indicator_style (GtkButton *button,
GtkIndicatorStyle style)
{
GtkButtonPrivate *priv;
g_return_if_fail (GTK_IS_BUTTON (button));
priv = button->priv;
if (priv->indicator_style != style)
{
priv->indicator_style = style;
gtk_widget_queue_resize (GTK_WIDGET (button));
g_object_notify (G_OBJECT (button), "indicator-style");
}
}
GtkIndicatorStyle
gtk_button_get_indicator_style (GtkButton *button)
{
g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_INDICATOR_STYLE_PLAIN);
return button->priv->indicator_style;
}
void
_gtk_button_set_active (GtkButton *button,
gboolean active)
{
g_warning ("this is broken...");
button->priv->active = active;
}
void
gtk_button_set_active (GtkButton *button,
gboolean active)
{
g_return_if_fail (GTK_IS_BUTTON (button));
active = active != FALSE;
if (button->priv->active != active)
gtk_button_clicked (button);
}
gboolean
gtk_button_get_active (GtkButton *button)
{
g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
return button->priv->active;
}
/**
* gtk_button_set_inconsistent:
* @button: a #GtkButton
* @inconsistent: %TRUE if state is inconsistent
*
* If the user has selected a range of elements (such as some text or
* spreadsheet cells) that are affected by a toggle button, and the
* current values in that range are inconsistent, you may want to
* display the toggle in an "in between" state. This function turns on
* "in between" display. Normally you would turn off the inconsistent
* state again if the user toggles the toggle button. This has to be
* done manually, gtk_toggle_button_set_inconsistent() only affects
* visual appearance, it doesn't affect the semantics of the button.
**/
void
gtk_button_set_inconsistent (GtkButton *button,
gboolean inconsistent)
{
GtkButtonPrivate *priv;
g_return_if_fail (GTK_IS_BUTTON (button));
priv = button->priv;
inconsistent = inconsistent != FALSE;
if (priv->inconsistent != inconsistent)
{
priv->inconsistent = inconsistent;
gtk_button_update_state (GTK_BUTTON (button));
gtk_widget_queue_draw (GTK_WIDGET (button));
g_object_notify (G_OBJECT (button), "inconsistent");
}
}
/**
* gtk_button_get_inconsistent:
* @button: a #GtkButton
*
* Gets the value set by gtk_button_set_inconsistent().
*
* Return value: %TRUE if the button is displayed as inconsistent,
* %FALSE otherwise
**/
gboolean
gtk_button_get_inconsistent (GtkButton *button)
{
g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
return button->priv->inconsistent;
}
void
gtk_button_toggled (GtkButton *button)
{
g_signal_emit (button, button_signals[TOGGLED], 0);
}

View File

@@ -34,6 +34,7 @@
#include <gtk/gtkbin.h> #include <gtk/gtkbin.h>
#include <gtk/gtkimage.h> #include <gtk/gtkimage.h>
#include <gtk/gtkenums.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@@ -67,6 +68,7 @@ struct _GtkButtonClass
void (* enter) (GtkButton *button); void (* enter) (GtkButton *button);
void (* leave) (GtkButton *button); void (* leave) (GtkButton *button);
void (* activate) (GtkButton *button); void (* activate) (GtkButton *button);
void (* toggled) (GtkButton *button);
/* Padding for future expansion */ /* Padding for future expansion */
void (*_gtk_reserved1) (void); void (*_gtk_reserved1) (void);
@@ -120,7 +122,20 @@ void gtk_button_set_image_position (GtkButton *button,
GtkPositionType gtk_button_get_image_position (GtkButton *button); GtkPositionType gtk_button_get_image_position (GtkButton *button);
GdkWindow* gtk_button_get_event_window (GtkButton *button); GdkWindow* gtk_button_get_event_window (GtkButton *button);
void gtk_button_set_action (GtkButton *button,
GAction *action);
GAction * gtk_button_get_action (GtkButton *button);
gboolean gtk_button_get_active (GtkButton *button);
void gtk_button_set_active (GtkButton *button,
gboolean active);
gboolean gtk_button_get_inconsistent (GtkButton *button);
void gtk_button_set_inconsistent (GtkButton *button,
gboolean active);
void gtk_button_set_indicator_style (GtkButton *button,
GtkIndicatorStyle style);
GtkIndicatorStyle gtk_button_get_indicator_style (GtkButton *button);
void _gtk_button_set_depressed (GtkButton *button, void _gtk_button_set_depressed (GtkButton *button,
gboolean depressed); gboolean depressed);
void _gtk_button_paint (GtkButton *button, void _gtk_button_paint (GtkButton *button,
@@ -131,6 +146,8 @@ void _gtk_button_paint (GtkButton *button,
GtkShadowType shadow_type, GtkShadowType shadow_type,
const gchar *main_detail, const gchar *main_detail,
const gchar *default_detail); const gchar *default_detail);
void _gtk_button_set_active (GtkButton *, gboolean);
void gtk_button_toggled (GtkButton *);
G_END_DECLS G_END_DECLS

View File

@@ -24,6 +24,10 @@
struct _GtkButtonPrivate struct _GtkButtonPrivate
{ {
GtkAction *action; GtkAction *action;
GAction *g_action;
guint state_id;
GVariant *state;
GtkPositionType image_position; GtkPositionType image_position;
GtkWidget *image; GtkWidget *image;
@@ -38,6 +42,8 @@ struct _GtkButtonPrivate
guint activate_timeout; guint activate_timeout;
guint32 grab_time; guint32 grab_time;
guint active : 1;
guint inconsistent : 1;
guint align_set : 1; guint align_set : 1;
guint button_down : 1; guint button_down : 1;
guint constructed : 1; guint constructed : 1;
@@ -50,6 +56,7 @@ struct _GtkButtonPrivate
guint use_action_appearance : 1; guint use_action_appearance : 1;
guint use_stock : 1; guint use_stock : 1;
guint use_underline : 1; guint use_underline : 1;
guint indicator_style : 2;
}; };
#endif /* __GTK_BUTTON_PRIVATE_H__ */ #endif /* __GTK_BUTTON_PRIVATE_H__ */

View File

@@ -34,68 +34,17 @@
#include "gtkprivate.h" #include "gtkprivate.h"
#include "gtkintl.h" #include "gtkintl.h"
#define INDICATOR_SIZE 13
#define INDICATOR_SPACING 2
static void gtk_check_button_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural);
static void gtk_check_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural);
static void gtk_check_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_check_button_draw (GtkWidget *widget,
cairo_t *cr);
static void gtk_check_button_paint (GtkWidget *widget,
cairo_t *cr);
static void gtk_check_button_draw_indicator (GtkCheckButton *check_button,
cairo_t *cr);
static void gtk_real_check_button_draw_indicator (GtkCheckButton *check_button,
cairo_t *cr);
G_DEFINE_TYPE (GtkCheckButton, gtk_check_button, GTK_TYPE_TOGGLE_BUTTON) G_DEFINE_TYPE (GtkCheckButton, gtk_check_button, GTK_TYPE_TOGGLE_BUTTON)
static void static void
gtk_check_button_class_init (GtkCheckButtonClass *class) gtk_check_button_class_init (GtkCheckButtonClass *class)
{ {
GtkWidgetClass *widget_class;
widget_class = (GtkWidgetClass*) class;
widget_class->get_preferred_width = gtk_check_button_get_preferred_width;
widget_class->get_preferred_height = gtk_check_button_get_preferred_height;
widget_class->size_allocate = gtk_check_button_size_allocate;
widget_class->draw = gtk_check_button_draw;
class->draw_indicator = gtk_real_check_button_draw_indicator;
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("indicator-size",
P_("Indicator Size"),
P_("Size of check or radio indicator"),
0,
G_MAXINT,
INDICATOR_SIZE,
GTK_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("indicator-spacing",
P_("Indicator Spacing"),
P_("Spacing around check or radio indicator"),
0,
G_MAXINT,
INDICATOR_SPACING,
GTK_PARAM_READABLE));
} }
static void static void
gtk_check_button_init (GtkCheckButton *check_button) gtk_check_button_init (GtkCheckButton *button)
{ {
gtk_widget_set_has_window (GTK_WIDGET (check_button), FALSE); gtk_button_set_indicator_style (GTK_BUTTON (button), GTK_INDICATOR_STYLE_CHECK);
gtk_widget_set_receives_default (GTK_WIDGET (check_button), FALSE);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (check_button), TRUE);
} }
GtkWidget* GtkWidget*
@@ -108,7 +57,9 @@ gtk_check_button_new (void)
GtkWidget* GtkWidget*
gtk_check_button_new_with_label (const gchar *label) gtk_check_button_new_with_label (const gchar *label)
{ {
return g_object_new (GTK_TYPE_CHECK_BUTTON, "label", label, NULL); return g_object_new (GTK_TYPE_CHECK_BUTTON,
"label", label,
NULL);
} }
/** /**
@@ -131,353 +82,3 @@ gtk_check_button_new_with_mnemonic (const gchar *label)
} }
/* This should only be called when toggle_button->draw_indicator
* is true.
*/
static void
gtk_check_button_paint (GtkWidget *widget,
cairo_t *cr)
{
GtkCheckButton *check_button = GTK_CHECK_BUTTON (widget);
gint border_width;
gint interior_focus;
gint focus_width;
gint focus_pad;
gtk_widget_style_get (widget,
"interior-focus", &interior_focus,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
gtk_check_button_draw_indicator (check_button, cr);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
if (gtk_widget_has_focus (widget))
{
GtkStateType state = gtk_widget_get_state (widget);
GtkStyle *style = gtk_widget_get_style (widget);
GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
if (interior_focus && child && gtk_widget_get_visible (child))
{
GtkAllocation child_allocation;
gtk_widget_get_allocation (child, &child_allocation);
gtk_paint_focus (style, cr, state,
widget, "checkbutton",
child_allocation.x - allocation.x - focus_width - focus_pad,
child_allocation.y - allocation.y - focus_width - focus_pad,
child_allocation.width + 2 * (focus_width + focus_pad),
child_allocation.height + 2 * (focus_width + focus_pad));
}
else
{
gtk_paint_focus (style, cr, state,
widget, "checkbutton",
border_width,
border_width,
allocation.width - 2 * border_width,
allocation.height - 2 * border_width);
}
}
}
void
_gtk_check_button_get_props (GtkCheckButton *check_button,
gint *indicator_size,
gint *indicator_spacing)
{
GtkWidget *widget = GTK_WIDGET (check_button);
if (indicator_size)
gtk_widget_style_get (widget, "indicator-size", indicator_size, NULL);
if (indicator_spacing)
gtk_widget_style_get (widget, "indicator-spacing", indicator_spacing, NULL);
}
static void
gtk_check_button_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (widget);
if (gtk_toggle_button_get_mode (toggle_button))
{
GtkWidget *child;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
guint border_width;
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_widget_style_get (GTK_WIDGET (widget),
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
*minimum = 2 * border_width;
*natural = 2 * border_width;
_gtk_check_button_get_props (GTK_CHECK_BUTTON (widget),
&indicator_size, &indicator_spacing);
child = gtk_bin_get_child (GTK_BIN (widget));
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
*minimum += child_min + indicator_spacing;
*natural += child_nat + indicator_spacing;
}
*minimum += (indicator_size + indicator_spacing * 2 + 2 * (focus_width + focus_pad));
*natural += (indicator_size + indicator_spacing * 2 + 2 * (focus_width + focus_pad));
}
else
GTK_WIDGET_CLASS (gtk_check_button_parent_class)->get_preferred_width (widget, minimum, natural);
}
static void
gtk_check_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (widget);
if (gtk_toggle_button_get_mode (toggle_button))
{
GtkWidget *child;
gint temp;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
guint border_width;
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_widget_style_get (GTK_WIDGET (widget),
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
*minimum = border_width * 2;
*natural = border_width * 2;
_gtk_check_button_get_props (GTK_CHECK_BUTTON (widget),
&indicator_size, &indicator_spacing);
child = gtk_bin_get_child (GTK_BIN (widget));
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_widget_get_preferred_height (child, &child_min, &child_nat);
*minimum += child_min;
*natural += child_nat;
}
temp = indicator_size + indicator_spacing * 2;
*minimum = MAX (*minimum, temp) + 2 * (focus_width + focus_pad);
*natural = MAX (*natural, temp) + 2 * (focus_width + focus_pad);
}
else
GTK_WIDGET_CLASS (gtk_check_button_parent_class)->get_preferred_height (widget, minimum, natural);
}
static void
gtk_check_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkCheckButton *check_button;
GtkToggleButton *toggle_button;
GtkButton *button;
GtkAllocation child_allocation;
button = GTK_BUTTON (widget);
check_button = GTK_CHECK_BUTTON (widget);
toggle_button = GTK_TOGGLE_BUTTON (widget);
if (gtk_toggle_button_get_mode (toggle_button))
{
GtkWidget *child;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
_gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing);
gtk_widget_style_get (widget,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
gtk_widget_set_allocation (widget, allocation);
if (gtk_widget_get_realized (widget))
gdk_window_move_resize (gtk_button_get_event_window (button),
allocation->x, allocation->y,
allocation->width, allocation->height);
child = gtk_bin_get_child (GTK_BIN (button));
if (child && gtk_widget_get_visible (child))
{
GtkRequisition child_requisition;
guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_widget_get_preferred_size (child, &child_requisition, NULL);
child_allocation.width = MIN (child_requisition.width,
allocation->width -
((border_width + focus_width + focus_pad) * 2
+ indicator_size + indicator_spacing * 3));
child_allocation.width = MAX (child_allocation.width, 1);
child_allocation.height = MIN (child_requisition.height,
allocation->height - (border_width + focus_width + focus_pad) * 2);
child_allocation.height = MAX (child_allocation.height, 1);
child_allocation.x = (border_width + indicator_size + indicator_spacing * 3 +
allocation->x + focus_width + focus_pad);
child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
child_allocation.x = allocation->x + allocation->width
- (child_allocation.x - allocation->x + child_allocation.width);
gtk_widget_size_allocate (child, &child_allocation);
}
}
else
GTK_WIDGET_CLASS (gtk_check_button_parent_class)->size_allocate (widget, allocation);
}
static gint
gtk_check_button_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkToggleButton *toggle_button;
GtkBin *bin;
GtkWidget *child;
toggle_button = GTK_TOGGLE_BUTTON (widget);
bin = GTK_BIN (widget);
if (gtk_toggle_button_get_mode (toggle_button))
{
gtk_check_button_paint (widget, cr);
child = gtk_bin_get_child (bin);
if (child)
gtk_container_propagate_draw (GTK_CONTAINER (widget),
child,
cr);
}
else if (GTK_WIDGET_CLASS (gtk_check_button_parent_class)->draw)
GTK_WIDGET_CLASS (gtk_check_button_parent_class)->draw (widget, cr);
return FALSE;
}
static void
gtk_check_button_draw_indicator (GtkCheckButton *check_button,
cairo_t *cr)
{
GtkCheckButtonClass *class = GTK_CHECK_BUTTON_GET_CLASS (check_button);
if (class->draw_indicator)
class->draw_indicator (check_button, cr);
}
static void
gtk_real_check_button_draw_indicator (GtkCheckButton *check_button,
cairo_t *cr)
{
GtkWidget *widget;
GtkWidget *child;
GtkButton *button;
GtkToggleButton *toggle_button;
GtkStateType state_type;
GtkShadowType shadow_type;
gint x, y;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
guint border_width;
gboolean interior_focus;
GtkAllocation allocation;
GtkStyle *style;
GdkWindow *window;
widget = GTK_WIDGET (check_button);
button = GTK_BUTTON (check_button);
toggle_button = GTK_TOGGLE_BUTTON (check_button);
gtk_widget_get_allocation (widget, &allocation);
style = gtk_widget_get_style (widget);
window = gtk_widget_get_window (widget);
gtk_widget_style_get (widget,
"interior-focus", &interior_focus,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
_gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
x = indicator_spacing + border_width;
y = (allocation.height - indicator_size) / 2;
child = gtk_bin_get_child (GTK_BIN (check_button));
if (!interior_focus || !(child && gtk_widget_get_visible (child)))
x += focus_width + focus_pad;
if (gtk_toggle_button_get_inconsistent (toggle_button))
shadow_type = GTK_SHADOW_ETCHED_IN;
else if (gtk_toggle_button_get_active (toggle_button))
shadow_type = GTK_SHADOW_IN;
else
shadow_type = GTK_SHADOW_OUT;
if (button->priv->activate_timeout || (button->priv->button_down && button->priv->in_button))
state_type = GTK_STATE_ACTIVE;
else if (button->priv->in_button)
state_type = GTK_STATE_PRELIGHT;
else if (!gtk_widget_is_sensitive (widget))
state_type = GTK_STATE_INSENSITIVE;
else
state_type = GTK_STATE_NORMAL;
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
x = allocation.width - (indicator_size + x);
if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
{
gtk_paint_flat_box (style, cr, GTK_STATE_PRELIGHT,
GTK_SHADOW_ETCHED_OUT,
widget, "checkbutton",
border_width, border_width,
allocation.width - (2 * border_width),
allocation.height - (2 * border_width));
}
gtk_paint_check (style, cr,
state_type, shadow_type,
widget, "checkbutton",
x, y, indicator_size, indicator_size);
}

View File

@@ -56,27 +56,14 @@ struct _GtkCheckButton
struct _GtkCheckButtonClass struct _GtkCheckButtonClass
{ {
GtkToggleButtonClass parent_class; GtkToggleButtonClass parent_class;
void (* draw_indicator) (GtkCheckButton *check_button,
cairo_t *cr);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
}; };
GType gtk_check_button_get_type (void) G_GNUC_CONST; GType gtk_check_button_get_type (void) G_GNUC_CONST;
GtkWidget* gtk_check_button_new (void); GtkWidget* gtk_check_button_new (void);
GtkWidget* gtk_check_button_new_with_label (const gchar *label); GtkWidget* gtk_check_button_new_with_label (const gchar *label);
GtkWidget* gtk_check_button_new_with_mnemonic (const gchar *label); GtkWidget* gtk_check_button_new_with_mnemonic (const gchar *label);
void _gtk_check_button_get_props (GtkCheckButton *check_button,
gint *indicator_size,
gint *indicator_spacing);
G_END_DECLS G_END_DECLS
#endif /* __GTK_CHECK_BUTTON_H__ */ #endif /* __GTK_CHECK_BUTTON_H__ */

View File

@@ -558,6 +558,15 @@ typedef enum
} GtkScrollablePolicy; } GtkScrollablePolicy;
typedef enum
{
GTK_INDICATOR_STYLE_PLAIN,
GTK_INDICATOR_STYLE_CHECK,
GTK_INDICATOR_STYLE_RADIO
} GtkIndicatorStyle;
G_END_DECLS G_END_DECLS

View File

@@ -121,8 +121,6 @@ static void gtk_radio_button_destroy (GtkWidget *widget);
static gboolean gtk_radio_button_focus (GtkWidget *widget, static gboolean gtk_radio_button_focus (GtkWidget *widget,
GtkDirectionType direction); GtkDirectionType direction);
static void gtk_radio_button_clicked (GtkButton *button); static void gtk_radio_button_clicked (GtkButton *button);
static void gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
cairo_t *cr);
static void gtk_radio_button_set_property (GObject *object, static void gtk_radio_button_set_property (GObject *object,
guint prop_id, guint prop_id,
const GValue *value, const GValue *value,
@@ -169,8 +167,6 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class)
button_class->clicked = gtk_radio_button_clicked; button_class->clicked = gtk_radio_button_clicked;
check_button_class->draw_indicator = gtk_radio_button_draw_indicator;
class->group_changed = NULL; class->group_changed = NULL;
/** /**
@@ -209,8 +205,9 @@ gtk_radio_button_init (GtkRadioButton *radio_button)
gtk_widget_set_has_window (GTK_WIDGET (radio_button), FALSE); gtk_widget_set_has_window (GTK_WIDGET (radio_button), FALSE);
gtk_widget_set_receives_default (GTK_WIDGET (radio_button), FALSE); gtk_widget_set_receives_default (GTK_WIDGET (radio_button), FALSE);
_gtk_button_set_active (GTK_BUTTON (radio_button), TRUE);
_gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), TRUE); gtk_button_set_indicator_style (GTK_BUTTON (radio_button),
GTK_INDICATOR_STYLE_RADIO);
GTK_BUTTON (radio_button)->priv->depress_on_activate = FALSE; GTK_BUTTON (radio_button)->priv->depress_on_activate = FALSE;
@@ -440,7 +437,9 @@ gtk_radio_button_new_with_label (GSList *group,
{ {
GtkWidget *radio_button; GtkWidget *radio_button;
radio_button = g_object_new (GTK_TYPE_RADIO_BUTTON, "label", label, NULL) ; radio_button = g_object_new (GTK_TYPE_RADIO_BUTTON,
"label", label,
NULL);
if (group) if (group)
gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_button), group); gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_button), group);
@@ -656,7 +655,7 @@ gtk_radio_button_focus (GtkWidget *widget,
/* Radio buttons with draw_indicator unset focus "normally", since /* Radio buttons with draw_indicator unset focus "normally", since
* they look like buttons to the user. * they look like buttons to the user.
*/ */
if (!gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON (widget))) if (gtk_button_get_indicator_style (GTK_BUTTON (widget)) == GTK_INDICATOR_STYLE_PLAIN)
return GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->focus (widget, direction); return GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->focus (widget, direction);
if (gtk_widget_is_focus (widget)) if (gtk_widget_is_focus (widget))
@@ -789,7 +788,7 @@ gtk_radio_button_clicked (GtkButton *button)
GtkRadioButton *radio_button = GTK_RADIO_BUTTON (button); GtkRadioButton *radio_button = GTK_RADIO_BUTTON (button);
GtkRadioButtonPrivate *priv = radio_button->priv; GtkRadioButtonPrivate *priv = radio_button->priv;
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button); GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
GtkToggleButton *tmp_button; GtkButton *tmp_button;
GtkStateType new_state; GtkStateType new_state;
GSList *tmp_list; GSList *tmp_list;
gint toggled; gint toggled;
@@ -799,7 +798,7 @@ gtk_radio_button_clicked (GtkButton *button)
g_object_ref (GTK_WIDGET (button)); g_object_ref (GTK_WIDGET (button));
if (gtk_toggle_button_get_active (toggle_button)) if (gtk_button_get_active (button))
{ {
tmp_button = NULL; tmp_button = NULL;
tmp_list = priv->group; tmp_list = priv->group;
@@ -809,8 +808,8 @@ gtk_radio_button_clicked (GtkButton *button)
tmp_button = tmp_list->data; tmp_button = tmp_list->data;
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
if (tmp_button != toggle_button && if (tmp_button != button &&
gtk_toggle_button_get_active (tmp_button)) gtk_button_get_active (tmp_button))
break; break;
tmp_button = NULL; tmp_button = NULL;
@@ -823,16 +822,14 @@ gtk_radio_button_clicked (GtkButton *button)
else else
{ {
toggled = TRUE; toggled = TRUE;
_gtk_toggle_button_set_active (toggle_button, _gtk_button_set_active (button, !gtk_button_get_active (button));
!gtk_toggle_button_get_active (toggle_button));
new_state = (button->priv->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); new_state = (button->priv->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
} }
} }
else else
{ {
toggled = TRUE; toggled = TRUE;
_gtk_toggle_button_set_active (toggle_button, _gtk_button_set_active (button, !gtk_button_get_active (button));
!gtk_toggle_button_get_active (toggle_button));
tmp_list = priv->group; tmp_list = priv->group;
while (tmp_list) while (tmp_list)
@@ -840,7 +837,7 @@ gtk_radio_button_clicked (GtkButton *button)
tmp_button = tmp_list->data; tmp_button = tmp_list->data;
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
if (gtk_toggle_button_get_active (tmp_button) && (tmp_button != toggle_button)) if (gtk_button_get_active (tmp_button) && (tmp_button != button))
{ {
gtk_button_clicked (GTK_BUTTON (tmp_button)); gtk_button_clicked (GTK_BUTTON (tmp_button));
break; break;
@@ -873,85 +870,3 @@ gtk_radio_button_clicked (GtkButton *button)
g_object_unref (button); g_object_unref (button);
} }
static void
gtk_radio_button_draw_indicator (GtkCheckButton *check_button,
cairo_t *cr)
{
GtkAllocation allocation;
GtkWidget *widget;
GtkWidget *child;
GtkButton *button;
GtkToggleButton *toggle_button;
GtkStateType state_type;
GtkShadowType shadow_type;
GtkStyle *style;
GdkWindow *window;
gint x, y;
gint indicator_size, indicator_spacing;
gint focus_width;
gint focus_pad;
guint border_width;
gboolean interior_focus;
widget = GTK_WIDGET (check_button);
button = GTK_BUTTON (check_button);
toggle_button = GTK_TOGGLE_BUTTON (check_button);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
style = gtk_widget_get_style (widget);
gtk_widget_style_get (widget,
"interior-focus", &interior_focus,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
window = gtk_widget_get_window (widget);
_gtk_check_button_get_props (check_button, &indicator_size, &indicator_spacing);
gtk_widget_get_allocation (widget, &allocation);
x = indicator_spacing + border_width;
y = (allocation.height - indicator_size) / 2;
child = gtk_bin_get_child (GTK_BIN (check_button));
if (!interior_focus || !(child && gtk_widget_get_visible (child)))
x += focus_width + focus_pad;
if (gtk_toggle_button_get_inconsistent (toggle_button))
shadow_type = GTK_SHADOW_ETCHED_IN;
else if (gtk_toggle_button_get_active (toggle_button))
shadow_type = GTK_SHADOW_IN;
else
shadow_type = GTK_SHADOW_OUT;
if (button->priv->activate_timeout || (button->priv->button_down && button->priv->in_button))
state_type = GTK_STATE_ACTIVE;
else if (button->priv->in_button)
state_type = GTK_STATE_PRELIGHT;
else if (!gtk_widget_is_sensitive (widget))
state_type = GTK_STATE_INSENSITIVE;
else
state_type = GTK_STATE_NORMAL;
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
x = allocation.width - (indicator_size + x);
if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
{
gtk_paint_flat_box (style, cr,
GTK_STATE_PRELIGHT,
GTK_SHADOW_ETCHED_OUT,
widget, "checkbutton",
border_width, border_width,
allocation.width - (2 * border_width),
allocation.height - (2 * border_width));
}
gtk_paint_option (style, cr,
state_type, shadow_type,
widget, "radiobutton",
x, y, indicator_size, indicator_size);
}

View File

@@ -73,7 +73,8 @@ static void
gtk_radio_tool_button_init (GtkRadioToolButton *button) gtk_radio_tool_button_init (GtkRadioToolButton *button)
{ {
GtkToolButton *tool_button = GTK_TOOL_BUTTON (button); GtkToolButton *tool_button = GTK_TOOL_BUTTON (button);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (_gtk_tool_button_get_button (tool_button)), FALSE); gtk_button_set_indicator_style (GTK_BUTTON (_gtk_tool_button_get_button (tool_button)),
GTK_INDICATOR_STYLE_PLAIN);
} }
static void static void

View File

@@ -38,61 +38,44 @@
#include "gtkintl.h" #include "gtkintl.h"
#define DEFAULT_LEFT_POS 4
#define DEFAULT_TOP_POS 4
#define DEFAULT_SPACING 7
struct _GtkToggleButtonPrivate
{
guint active : 1;
guint draw_indicator : 1;
guint inconsistent : 1;
};
enum {
TOGGLED,
LAST_SIGNAL
};
enum { enum {
PROP_0, PROP_0,
PROP_ACTIVE,
PROP_INCONSISTENT,
PROP_DRAW_INDICATOR PROP_DRAW_INDICATOR
}; };
static void gtk_toggle_button_get_preferred_width (GtkWidget *widget,
static gint gtk_toggle_button_draw (GtkWidget *widget, gint *minimum,
cairo_t *cr); gint *natural);
static gboolean gtk_toggle_button_mnemonic_activate (GtkWidget *widget, static void gtk_toggle_button_get_preferred_height (GtkWidget *widget,
gboolean group_cycling); gint *minimum,
static void gtk_toggle_button_pressed (GtkButton *button); gint *natural);
static void gtk_toggle_button_released (GtkButton *button); static void gtk_toggle_button_size_allocate (GtkWidget *widget,
static void gtk_toggle_button_clicked (GtkButton *button); GtkAllocation *allocation);
static gint gtk_toggle_button_draw (GtkWidget *widget,
cairo_t *cr);
static gboolean gtk_toggle_button_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
static void gtk_toggle_button_set_property (GObject *object, static void gtk_toggle_button_set_property (GObject *object,
guint prop_id, guint prop_id,
const GValue *value, const GValue *value,
GParamSpec *pspec); GParamSpec *pspec);
static void gtk_toggle_button_get_property (GObject *object, static void gtk_toggle_button_get_property (GObject *object,
guint prop_id, guint prop_id,
GValue *value, GValue *value,
GParamSpec *pspec); GParamSpec *pspec);
static void gtk_toggle_button_update_state (GtkButton *button);
static void gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface); static void gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface);
static void gtk_toggle_button_update (GtkActivatable *activatable, static void gtk_toggle_button_update (GtkActivatable *activatable,
GtkAction *action, GtkAction *action,
const gchar *property_name); const gchar *property_name);
static void gtk_toggle_button_sync_action_properties (GtkActivatable *activatable, static void gtk_toggle_button_sync_action_properties (GtkActivatable *activatable,
GtkAction *action); GtkAction *action);
static GtkActivatableIface *parent_activatable_iface; static GtkActivatableIface *parent_activatable_iface;
static guint toggle_button_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_CODE (GtkToggleButton, gtk_toggle_button, GTK_TYPE_BUTTON, G_DEFINE_TYPE_WITH_CODE (GtkToggleButton, gtk_toggle_button, GTK_TYPE_BUTTON,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE, G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
gtk_toggle_button_activatable_interface_init)) gtk_toggle_button_activatable_interface_init))
static void static void
gtk_toggle_button_class_init (GtkToggleButtonClass *class) gtk_toggle_button_class_init (GtkToggleButtonClass *class)
@@ -108,65 +91,53 @@ gtk_toggle_button_class_init (GtkToggleButtonClass *class)
gobject_class->set_property = gtk_toggle_button_set_property; gobject_class->set_property = gtk_toggle_button_set_property;
gobject_class->get_property = gtk_toggle_button_get_property; gobject_class->get_property = gtk_toggle_button_get_property;
widget_class->get_preferred_width = gtk_toggle_button_get_preferred_width;
widget_class->get_preferred_height = gtk_toggle_button_get_preferred_height;
widget_class->size_allocate = gtk_toggle_button_size_allocate;
widget_class->draw = gtk_toggle_button_draw; widget_class->draw = gtk_toggle_button_draw;
widget_class->mnemonic_activate = gtk_toggle_button_mnemonic_activate; widget_class->mnemonic_activate = gtk_toggle_button_mnemonic_activate;
button_class->pressed = gtk_toggle_button_pressed;
button_class->released = gtk_toggle_button_released;
button_class->clicked = gtk_toggle_button_clicked;
button_class->enter = gtk_toggle_button_update_state;
button_class->leave = gtk_toggle_button_update_state;
class->toggled = NULL;
g_object_class_install_property (gobject_class,
PROP_ACTIVE,
g_param_spec_boolean ("active",
P_("Active"),
P_("If the toggle button should be pressed in"),
FALSE,
GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_INCONSISTENT,
g_param_spec_boolean ("inconsistent",
P_("Inconsistent"),
P_("If the toggle button is in an \"in between\" state"),
FALSE,
GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_DRAW_INDICATOR, PROP_DRAW_INDICATOR,
g_param_spec_boolean ("draw-indicator", g_param_spec_boolean ("draw-indicator",
P_("Draw Indicator"), P_("Draw Indicator"),
P_("If the toggle part of the button is displayed"), P_("If the toggle part of the button is displayed"),
FALSE, FALSE,
GTK_PARAM_READWRITE)); GTK_PARAM_READWRITE|G_PARAM_DEPRECATED));
toggle_button_signals[TOGGLED] = gtk_widget_class_install_style_property (widget_class,
g_signal_new (I_("toggled"), g_param_spec_int ("indicator-size",
G_OBJECT_CLASS_TYPE (gobject_class), P_("Indicator Size"),
G_SIGNAL_RUN_FIRST, P_("Size of check or radio indicator"),
G_STRUCT_OFFSET (GtkToggleButtonClass, toggled), 0, G_MAXINT, 13,
NULL, NULL, GTK_PARAM_READABLE));
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_type_class_add_private (class, sizeof (GtkToggleButtonPrivate)); gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("indicator-spacing",
P_("Indicator Spacing"),
P_("Spacing around check or radio indicator"),
0, G_MAXINT, 2,
GTK_PARAM_READABLE));
}
static void
invert (GAction *action,
gpointer user_data)
{
g_action_set_state (action, g_variant_new_boolean (!g_variant_get_boolean (g_action_get_state (action))));
} }
static void static void
gtk_toggle_button_init (GtkToggleButton *toggle_button) gtk_toggle_button_init (GtkToggleButton *toggle_button)
{ {
GtkToggleButtonPrivate *priv; GSimpleAction *action;
toggle_button->priv = G_TYPE_INSTANCE_GET_PRIVATE (toggle_button, action = g_simple_action_new_stateful ("anonymous", NULL,
GTK_TYPE_TOGGLE_BUTTON, g_variant_new_boolean (FALSE));
GtkToggleButtonPrivate); g_signal_connect (action, "activate", G_CALLBACK (invert), NULL);
priv = toggle_button->priv; gtk_button_set_action (GTK_BUTTON (toggle_button), G_ACTION (action));
g_object_unref (action);
priv->active = FALSE;
priv->draw_indicator = FALSE;
GTK_BUTTON (toggle_button)->priv->depress_on_activate = TRUE; GTK_BUTTON (toggle_button)->priv->depress_on_activate = TRUE;
} }
@@ -180,8 +151,8 @@ gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface)
static void static void
gtk_toggle_button_update (GtkActivatable *activatable, gtk_toggle_button_update (GtkActivatable *activatable,
GtkAction *action, GtkAction *action,
const gchar *property_name) const gchar *property_name)
{ {
GtkToggleButton *button; GtkToggleButton *button;
@@ -200,7 +171,7 @@ gtk_toggle_button_update (GtkActivatable *activatable,
static void static void
gtk_toggle_button_sync_action_properties (GtkActivatable *activatable, gtk_toggle_button_sync_action_properties (GtkActivatable *activatable,
GtkAction *action) GtkAction *action)
{ {
GtkToggleButton *button; GtkToggleButton *button;
@@ -226,7 +197,9 @@ gtk_toggle_button_new (void)
GtkWidget* GtkWidget*
gtk_toggle_button_new_with_label (const gchar *label) gtk_toggle_button_new_with_label (const gchar *label)
{ {
return g_object_new (GTK_TYPE_TOGGLE_BUTTON, "label", label, NULL); return g_object_new (GTK_TYPE_TOGGLE_BUTTON,
"label", label,
NULL);
} }
/** /**
@@ -260,14 +233,11 @@ gtk_toggle_button_set_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_ACTIVE:
gtk_toggle_button_set_active (tb, g_value_get_boolean (value));
break;
case PROP_INCONSISTENT:
gtk_toggle_button_set_inconsistent (tb, g_value_get_boolean (value));
break;
case PROP_DRAW_INDICATOR: case PROP_DRAW_INDICATOR:
gtk_toggle_button_set_mode (tb, g_value_get_boolean (value)); gtk_button_set_indicator_style (GTK_BUTTON (tb),
g_value_get_boolean (value)
? GTK_INDICATOR_STYLE_CHECK
: GTK_INDICATOR_STYLE_PLAIN);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -277,23 +247,14 @@ gtk_toggle_button_set_property (GObject *object,
static void static void
gtk_toggle_button_get_property (GObject *object, gtk_toggle_button_get_property (GObject *object,
guint prop_id, guint prop_id,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
GtkToggleButton *tb = GTK_TOGGLE_BUTTON (object);
GtkToggleButtonPrivate *priv = tb->priv;
switch (prop_id) switch (prop_id)
{ {
case PROP_ACTIVE:
g_value_set_boolean (value, priv->active);
break;
case PROP_INCONSISTENT:
g_value_set_boolean (value, priv->inconsistent);
break;
case PROP_DRAW_INDICATOR: case PROP_DRAW_INDICATOR:
g_value_set_boolean (value, priv->draw_indicator); g_value_set_boolean (value, gtk_button_get_indicator_style (GTK_BUTTON (object)) != GTK_INDICATOR_STYLE_PLAIN);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -303,7 +264,7 @@ gtk_toggle_button_get_property (GObject *object,
/** /**
* gtk_toggle_button_set_mode: * gtk_toggle_button_set_mode:
* @toggle_button: a #GtkToggleButton * @button: a #GtkToggleButton
* @draw_indicator: if %TRUE, draw the button as a separate indicator * @draw_indicator: if %TRUE, draw the button as a separate indicator
* and label; if %FALSE, draw the button like a normal button * and label; if %FALSE, draw the button like a normal button
* *
@@ -314,93 +275,71 @@ gtk_toggle_button_get_property (GObject *object,
* This function only affects instances of classes like #GtkCheckButton * This function only affects instances of classes like #GtkCheckButton
* and #GtkRadioButton that derive from #GtkToggleButton, * and #GtkRadioButton that derive from #GtkToggleButton,
* not instances of #GtkToggleButton itself. * not instances of #GtkToggleButton itself.
*
* Deprecated:3.0: Use gtk_button_set_indicator_style() instead
*/ */
void void
gtk_toggle_button_set_mode (GtkToggleButton *toggle_button, gtk_toggle_button_set_mode (GtkToggleButton *button,
gboolean draw_indicator) gboolean draw_indicator)
{ {
GtkToggleButtonPrivate *priv; g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); gtk_button_set_indicator_style (GTK_BUTTON (button),
draw_indicator ? GTK_INDICATOR_STYLE_CHECK
priv = toggle_button->priv; : GTK_INDICATOR_STYLE_PLAIN);
g_object_notify (G_OBJECT (button), "draw-indicator");
draw_indicator = draw_indicator ? TRUE : FALSE;
if (priv->draw_indicator != draw_indicator)
{
priv->draw_indicator = draw_indicator;
GTK_BUTTON (toggle_button)->priv->depress_on_activate = !draw_indicator;
if (gtk_widget_get_visible (GTK_WIDGET (toggle_button)))
gtk_widget_queue_resize (GTK_WIDGET (toggle_button));
g_object_notify (G_OBJECT (toggle_button), "draw-indicator");
}
} }
/** /**
* gtk_toggle_button_get_mode: * gtk_toggle_button_get_mode:
* @toggle_button: a #GtkToggleButton * @button: a #GtkToggleButton
* *
* Retrieves whether the button is displayed as a separate indicator * Retrieves whether the button is displayed as a separate indicator
* and label. See gtk_toggle_button_set_mode(). * and label. See gtk_toggle_button_set_mode().
* *
* Return value: %TRUE if the togglebutton is drawn as a separate indicator * Return value: %TRUE if the togglebutton is drawn as a separate indicator
* and label. * and label.
*
* Deprecated:3.0: Use gtk_button_get_indicator_style() instead
**/ **/
gboolean gboolean
gtk_toggle_button_get_mode (GtkToggleButton *toggle_button) gtk_toggle_button_get_mode (GtkToggleButton *button)
{ {
g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE); g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (button), FALSE);
return toggle_button->priv->draw_indicator; return gtk_button_get_indicator_style (GTK_BUTTON (button)) != GTK_INDICATOR_STYLE_PLAIN;
} }
void void
gtk_toggle_button_set_active (GtkToggleButton *toggle_button, gtk_toggle_button_set_active (GtkToggleButton *button,
gboolean is_active) gboolean is_active)
{ {
GtkToggleButtonPrivate *priv; g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); gtk_button_set_active (GTK_BUTTON (button), is_active);
priv = toggle_button->priv;
is_active = is_active != FALSE;
if (priv->active != is_active)
gtk_button_clicked (GTK_BUTTON (toggle_button));
}
void
_gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
gboolean is_active)
{
toggle_button->priv->active = is_active;
} }
gboolean gboolean
gtk_toggle_button_get_active (GtkToggleButton *toggle_button) gtk_toggle_button_get_active (GtkToggleButton *button)
{ {
g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE); g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (button), FALSE);
return toggle_button->priv->active; return gtk_button_get_active (GTK_BUTTON (button));
} }
void void
gtk_toggle_button_toggled (GtkToggleButton *toggle_button) gtk_toggle_button_toggled (GtkToggleButton *button)
{ {
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
g_signal_emit (toggle_button, toggle_button_signals[TOGGLED], 0); gtk_button_toggled (GTK_BUTTON (button));
} }
/** /**
* gtk_toggle_button_set_inconsistent: * gtk_toggle_button_set_inconsistent:
* @toggle_button: a #GtkToggleButton * @button: a #GtkToggleButton
* @setting: %TRUE if state is inconsistent * @is_inconsistent: %TRUE if state is inconsistent
* *
* If the user has selected a range of elements (such as some text or * If the user has selected a range of elements (such as some text or
* spreadsheet cells) that are affected by a toggle button, and the * spreadsheet cells) that are affected by a toggle button, and the
@@ -410,75 +349,328 @@ gtk_toggle_button_toggled (GtkToggleButton *toggle_button)
* state again if the user toggles the toggle button. This has to be * state again if the user toggles the toggle button. This has to be
* done manually, gtk_toggle_button_set_inconsistent() only affects * done manually, gtk_toggle_button_set_inconsistent() only affects
* visual appearance, it doesn't affect the semantics of the button. * visual appearance, it doesn't affect the semantics of the button.
*
**/ **/
void void
gtk_toggle_button_set_inconsistent (GtkToggleButton *toggle_button, gtk_toggle_button_set_inconsistent (GtkToggleButton *button,
gboolean setting) gboolean is_inconsistent)
{ {
GtkToggleButtonPrivate *priv; g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); gtk_button_set_inconsistent (GTK_BUTTON (button), is_inconsistent);
priv = toggle_button->priv;
setting = setting != FALSE;
if (setting != priv->inconsistent)
{
priv->inconsistent = setting;
gtk_toggle_button_update_state (GTK_BUTTON (toggle_button));
gtk_widget_queue_draw (GTK_WIDGET (toggle_button));
g_object_notify (G_OBJECT (toggle_button), "inconsistent");
}
} }
/** /**
* gtk_toggle_button_get_inconsistent: * gtk_toggle_button_get_inconsistent:
* @toggle_button: a #GtkToggleButton * @button: a #GtkToggleButton
* *
* Gets the value set by gtk_toggle_button_set_inconsistent(). * Gets the value set by gtk_toggle_button_set_inconsistent().
* *
* Return value: %TRUE if the button is displayed as inconsistent, %FALSE otherwise * Return value: %TRUE if the button is displayed as inconsistent,
* %FALSE otherwise
**/ **/
gboolean gboolean
gtk_toggle_button_get_inconsistent (GtkToggleButton *toggle_button) gtk_toggle_button_get_inconsistent (GtkToggleButton *button)
{ {
g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE); g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (button), FALSE);
return toggle_button->priv->inconsistent; return gtk_button_get_inconsistent (GTK_BUTTON (button));
}
static void
gtk_toggle_button_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
if (gtk_button_get_indicator_style (GTK_BUTTON (widget)) != GTK_INDICATOR_STYLE_PLAIN)
{
GtkWidget *child;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
guint border_width;
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_widget_style_get (GTK_WIDGET (widget),
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
"indicator-size", &indicator_size,
"indicator-spacing", &indicator_spacing,
NULL);
*minimum = 2 * border_width;
*natural = 2 * border_width;
child = gtk_bin_get_child (GTK_BIN (widget));
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
*minimum += child_min + indicator_spacing;
*natural += child_nat + indicator_spacing;
}
*minimum += (indicator_size + indicator_spacing * 2 + 2 * (focus_width + focus_pad));
*natural += (indicator_size + indicator_spacing * 2 + 2 * (focus_width + focus_pad));
}
else
GTK_WIDGET_CLASS (gtk_toggle_button_parent_class)->get_preferred_width (widget, minimum, natural);
}
static void
gtk_toggle_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
if (gtk_button_get_indicator_style (GTK_BUTTON (widget)) != GTK_INDICATOR_STYLE_PLAIN)
{
GtkWidget *child;
gint temp;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
guint border_width;
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_widget_style_get (GTK_WIDGET (widget),
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
"indicator-size", &indicator_size,
"indicator-spacing", &indicator_spacing,
NULL);
*minimum = border_width * 2;
*natural = border_width * 2;
child = gtk_bin_get_child (GTK_BIN (widget));
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_widget_get_preferred_height (child, &child_min, &child_nat);
*minimum += child_min;
*natural += child_nat;
}
temp = indicator_size + indicator_spacing * 2;
*minimum = MAX (*minimum, temp) + 2 * (focus_width + focus_pad);
*natural = MAX (*natural, temp) + 2 * (focus_width + focus_pad);
}
else
GTK_WIDGET_CLASS (gtk_toggle_button_parent_class)->get_preferred_height (widget, minimum, natural);
}
static void
gtk_toggle_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkAllocation child_allocation;
if (gtk_button_get_indicator_style (GTK_BUTTON (widget)) != GTK_INDICATOR_STYLE_PLAIN)
{
GtkWidget *child;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
gtk_widget_style_get (widget,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
"indicator-size", &indicator_size,
"indicator-spacing", &indicator_spacing,
NULL);
gtk_widget_set_allocation (widget, allocation);
if (gtk_widget_get_realized (widget))
gdk_window_move_resize (gtk_button_get_event_window (GTK_BUTTON (widget)),
allocation->x, allocation->y,
allocation->width, allocation->height);
child = gtk_bin_get_child (GTK_BIN (widget));
if (child && gtk_widget_get_visible (child))
{
GtkRequisition child_requisition;
guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_widget_get_preferred_size (child, &child_requisition, NULL);
child_allocation.width = MIN (child_requisition.width,
allocation->width -
((border_width + focus_width + focus_pad) * 2
+ indicator_size + indicator_spacing * 3));
child_allocation.width = MAX (child_allocation.width, 1);
child_allocation.height = MIN (child_requisition.height,
allocation->height - (border_width + focus_width + focus_pad) * 2);
child_allocation.height = MAX (child_allocation.height, 1);
child_allocation.x = (border_width + indicator_size + indicator_spacing * 3 +
allocation->x + focus_width + focus_pad);
child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
child_allocation.x = allocation->x + allocation->width
- (child_allocation.x - allocation->x + child_allocation.width);
gtk_widget_size_allocate (child, &child_allocation);
}
}
else
GTK_WIDGET_CLASS (gtk_toggle_button_parent_class)->size_allocate (widget, allocation);
}
static void
gtk_toggle_button_draw_indicator (GtkButton *button,
cairo_t *cr)
{
GtkWidget *widget = GTK_WIDGET (button);
GtkWidget *child;
GtkStateType state_type;
GtkShadowType shadow_type;
gint x, y;
gint indicator_size;
gint indicator_spacing;
gint focus_width;
gint focus_pad;
guint border_width;
gboolean interior_focus;
gtk_widget_style_get (widget,
"interior-focus", &interior_focus,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
"indicator-size", &indicator_size,
"indicator-spacing", &indicator_spacing,
NULL);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
x = indicator_spacing + border_width;
y = (gtk_widget_get_allocated_height (widget) - indicator_size) / 2;
child = gtk_bin_get_child (GTK_BIN (widget));
if (!interior_focus || !(child && gtk_widget_get_visible (child)))
x += focus_width + focus_pad;
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
x = gtk_widget_get_allocated_width (widget) - (indicator_size + x);
if (gtk_button_get_inconsistent (button))
shadow_type = GTK_SHADOW_ETCHED_IN;
else if (gtk_button_get_active (button))
shadow_type = GTK_SHADOW_IN;
else
shadow_type = GTK_SHADOW_OUT;
if (GTK_BUTTON (widget)->priv->activate_timeout ||
(GTK_BUTTON (widget)->priv->button_down && GTK_BUTTON (widget)->priv->in_button))
state_type = GTK_STATE_ACTIVE;
else if (GTK_BUTTON (widget)->priv->in_button)
state_type = GTK_STATE_PRELIGHT;
else if (!gtk_widget_is_sensitive (widget))
state_type = GTK_STATE_INSENSITIVE;
else
state_type = GTK_STATE_NORMAL;
if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
gtk_paint_flat_box (gtk_widget_get_style (widget), cr, GTK_STATE_PRELIGHT,
GTK_SHADOW_ETCHED_OUT,
widget, "checkbutton",
border_width, border_width,
gtk_widget_get_allocated_width (widget) - (2 * border_width),
gtk_widget_get_allocated_height (widget) - (2 * border_width));
if (gtk_button_get_indicator_style (GTK_BUTTON (widget)) == GTK_INDICATOR_STYLE_CHECK)
gtk_paint_check (gtk_widget_get_style (widget), cr,
state_type, shadow_type,
widget, "checkbutton",
x, y, indicator_size, indicator_size);
else
gtk_paint_option (gtk_widget_get_style (widget), cr,
state_type, shadow_type,
widget, "radiobutton",
x, y, indicator_size, indicator_size);
} }
static gint static gint
gtk_toggle_button_draw (GtkWidget *widget, gtk_toggle_button_draw (GtkWidget *widget,
cairo_t *cr) cairo_t *cr)
{ {
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (widget);
GtkToggleButtonPrivate *priv = toggle_button->priv;
GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
GtkButton *button = GTK_BUTTON (widget); GtkButton *button = GTK_BUTTON (widget);
GtkStateType state_type; GtkButtonPrivate *priv = button->priv;
GtkStateType state;
GtkShadowType shadow_type; GtkShadowType shadow_type;
GtkWidget *child;
gint interior_focus;
gint focus_width;
gint focus_pad;
gint border_width;
GtkAllocation allocation;
state_type = gtk_widget_get_state (widget); gtk_widget_get_allocation (widget, &allocation);
state = gtk_widget_get_state (widget);
if (priv->inconsistent) if (gtk_button_get_indicator_style (GTK_BUTTON (widget)) != GTK_INDICATOR_STYLE_PLAIN)
{ {
if (state_type == GTK_STATE_ACTIVE) gtk_toggle_button_draw_indicator (button, cr);
state_type = GTK_STATE_NORMAL;
shadow_type = GTK_SHADOW_ETCHED_IN; if (gtk_widget_has_focus (widget))
{
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_widget_style_get (widget,
"interior-focus", &interior_focus,
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
child = gtk_bin_get_child (GTK_BIN (widget));
if (interior_focus && child && gtk_widget_get_visible (child))
{
GtkAllocation child_allocation;
gtk_widget_get_allocation (child, &child_allocation);
gtk_paint_focus (gtk_widget_get_style (widget), cr, state,
widget, "checkbutton",
child_allocation.x - allocation.x - focus_width - focus_pad,
child_allocation.y - allocation.y - focus_width - focus_pad,
child_allocation.width + 2 * (focus_width + focus_pad),
child_allocation.height + 2 * (focus_width + focus_pad));
}
else
{
gtk_paint_focus (gtk_widget_get_style (widget), cr, state,
widget, "checkbutton",
border_width,
border_width,
allocation.width - 2 * border_width,
allocation.height - 2 * border_width);
}
}
} }
else else
shadow_type = button->priv->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; {
if (priv->inconsistent)
{
if (state == GTK_STATE_ACTIVE)
state = GTK_STATE_NORMAL;
shadow_type = GTK_SHADOW_ETCHED_IN;
}
else
shadow_type = GTK_BUTTON (widget)->priv->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
_gtk_button_paint (button, cr, _gtk_button_paint (GTK_BUTTON (widget), cr,
gtk_widget_get_allocated_width (widget), allocation.width, allocation.height,
gtk_widget_get_allocated_height (widget), state, shadow_type,
state_type, shadow_type, "togglebutton", "togglebuttondefault");
"togglebutton", "togglebuttondefault"); }
child = gtk_bin_get_child (GTK_BIN (widget));
if (child) if (child)
gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr); gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
@@ -502,73 +694,3 @@ gtk_toggle_button_mnemonic_activate (GtkWidget *widget,
return TRUE; return TRUE;
} }
static void
gtk_toggle_button_pressed (GtkButton *button)
{
button->priv->button_down = TRUE;
gtk_toggle_button_update_state (button);
gtk_widget_queue_draw (GTK_WIDGET (button));
}
static void
gtk_toggle_button_released (GtkButton *button)
{
if (button->priv->button_down)
{
button->priv->button_down = FALSE;
if (button->priv->in_button)
gtk_button_clicked (button);
gtk_toggle_button_update_state (button);
gtk_widget_queue_draw (GTK_WIDGET (button));
}
}
static void
gtk_toggle_button_clicked (GtkButton *button)
{
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
GtkToggleButtonPrivate *priv = toggle_button->priv;
priv->active = !priv->active;
gtk_toggle_button_toggled (toggle_button);
gtk_toggle_button_update_state (button);
g_object_notify (G_OBJECT (toggle_button), "active");
if (GTK_BUTTON_CLASS (gtk_toggle_button_parent_class)->clicked)
GTK_BUTTON_CLASS (gtk_toggle_button_parent_class)->clicked (button);
}
static void
gtk_toggle_button_update_state (GtkButton *button)
{
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
GtkToggleButtonPrivate *priv = toggle_button->priv;
gboolean depressed, touchscreen;
GtkStateType new_state;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (button)),
"gtk-touchscreen-mode", &touchscreen,
NULL);
if (priv->inconsistent)
depressed = FALSE;
else if (button->priv->in_button && button->priv->button_down)
depressed = TRUE;
else
depressed = priv->active;
if (!touchscreen && button->priv->in_button && (!button->priv->button_down || priv->draw_indicator))
new_state = GTK_STATE_PRELIGHT;
else
new_state = depressed ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL;
_gtk_button_set_depressed (button, depressed);
gtk_widget_set_state (GTK_WIDGET (toggle_button), new_state);
}

View File

@@ -45,23 +45,18 @@ G_BEGIN_DECLS
#define GTK_TOGGLE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TOGGLE_BUTTON, GtkToggleButtonClass)) #define GTK_TOGGLE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TOGGLE_BUTTON, GtkToggleButtonClass))
typedef struct _GtkToggleButton GtkToggleButton; typedef struct _GtkToggleButton GtkToggleButton;
typedef struct _GtkToggleButtonPrivate GtkToggleButtonPrivate;
typedef struct _GtkToggleButtonClass GtkToggleButtonClass; typedef struct _GtkToggleButtonClass GtkToggleButtonClass;
struct _GtkToggleButton struct _GtkToggleButton
{ {
/*< private >*/ /*< private >*/
GtkButton button; GtkButton button;
GtkToggleButtonPrivate *priv;
}; };
struct _GtkToggleButtonClass struct _GtkToggleButtonClass
{ {
GtkButtonClass parent_class; GtkButtonClass parent_class;
void (* toggled) (GtkToggleButton *toggle_button);
/* Padding for future expansion */ /* Padding for future expansion */
void (*_gtk_reserved1) (void); void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void); void (*_gtk_reserved2) (void);
@@ -70,24 +65,23 @@ struct _GtkToggleButtonClass
}; };
GType gtk_toggle_button_get_type (void) G_GNUC_CONST; GType gtk_toggle_button_get_type (void) G_GNUC_CONST;
GtkWidget* gtk_toggle_button_new (void); GtkWidget* gtk_toggle_button_new (void);
GtkWidget* gtk_toggle_button_new_with_label (const gchar *label); GtkWidget* gtk_toggle_button_new_with_label (const gchar *label);
GtkWidget* gtk_toggle_button_new_with_mnemonic (const gchar *label); GtkWidget* gtk_toggle_button_new_with_mnemonic (const gchar *label);
void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button, #ifndef GTK_DISABLE_DEPRECATED
gboolean draw_indicator); void gtk_toggle_button_set_mode (GtkToggleButton *button,
gboolean gtk_toggle_button_get_mode (GtkToggleButton *toggle_button); gboolean mode);
void gtk_toggle_button_set_active (GtkToggleButton *toggle_button, gboolean gtk_toggle_button_get_mode (GtkToggleButton *button);
gboolean is_active); #endif
gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button); void gtk_toggle_button_set_active (GtkToggleButton *button,
void gtk_toggle_button_toggled (GtkToggleButton *toggle_button); gboolean is_active);
void gtk_toggle_button_set_inconsistent (GtkToggleButton *toggle_button, gboolean gtk_toggle_button_get_active (GtkToggleButton *button);
gboolean setting); void gtk_toggle_button_set_inconsistent (GtkToggleButton *button,
gboolean gtk_toggle_button_get_inconsistent (GtkToggleButton *toggle_button); gboolean is_inconsistent);
gboolean gtk_toggle_button_get_inconsistent (GtkToggleButton *button);
void _gtk_toggle_button_set_active (GtkToggleButton *toggle_button, void gtk_toggle_button_toggled (GtkToggleButton *button);
gboolean is_active);
G_END_DECLS G_END_DECLS