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,
LEAVE,
ACTIVATE,
TOGGLED,
LAST_SIGNAL
};
@@ -90,6 +91,10 @@ enum {
PROP_XALIGN,
PROP_YALIGN,
PROP_IMAGE_POSITION,
PROP_ACTION,
PROP_INDICATOR_STYLE,
PROP_ACTIVE,
PROP_INCONSISTENT,
/* activatable properties */
PROP_ACTIVATABLE_RELATED_ACTION,
@@ -99,6 +104,7 @@ enum {
static void gtk_button_destroy (GtkWidget *widget);
static void gtk_button_dispose (GObject *object);
static void gtk_button_finalize (GObject *object);
static void gtk_button_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -188,6 +194,7 @@ gtk_button_class_init (GtkButtonClass *klass)
gobject_class->dispose = gtk_button_dispose;
gobject_class->set_property = gtk_button_set_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_height = gtk_button_get_preferred_height;
@@ -330,6 +337,46 @@ gtk_button_class_init (GtkButtonClass *klass)
GTK_POS_LEFT,
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_USE_ACTION_APPEARANCE, "use-action-appearance");
@@ -435,6 +482,15 @@ gtk_button_class_init (GtkButtonClass *klass)
G_TYPE_NONE, 0);
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:
*
@@ -526,6 +582,20 @@ gtk_button_class_init (GtkButtonClass *klass)
2,
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));
}
@@ -561,6 +631,7 @@ gtk_button_init (GtkButton *button)
priv->image_is_stock = TRUE;
priv->image_position = GTK_POS_LEFT;
priv->use_action_appearance = TRUE;
priv->indicator_style = GTK_INDICATOR_STYLE_PLAIN;
}
static void
@@ -578,6 +649,77 @@ gtk_button_destroy (GtkWidget *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*
gtk_button_constructor (GType type,
guint n_construct_properties,
@@ -596,9 +738,22 @@ gtk_button_constructor (GType type,
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)
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;
}
@@ -662,9 +817,21 @@ gtk_button_dispose (GObject *object)
gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL);
priv->action = NULL;
}
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
gtk_button_set_property (GObject *object,
guint prop_id,
@@ -703,6 +870,19 @@ gtk_button_set_property (GObject *object,
case PROP_IMAGE_POSITION:
gtk_button_set_image_position (button, g_value_get_enum (value));
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:
gtk_button_set_related_action (button, g_value_get_object (value));
break;
@@ -753,6 +933,18 @@ gtk_button_get_property (GObject *object,
case PROP_IMAGE_POSITION:
g_value_set_enum (value, priv->image_position);
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:
g_value_set_object (value, priv->action);
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
gtk_button_set_related_action (GtkButton *button,
GtkAction *action)
@@ -902,15 +1120,6 @@ gtk_button_set_related_action (GtkButton *button,
if (priv->action == action)
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);
priv->action = action;
@@ -1779,6 +1988,7 @@ gtk_real_button_pressed (GtkButton *button)
priv->button_down = TRUE;
gtk_button_update_state (button);
gtk_widget_queue_draw (GTK_WIDGET (button));
}
static void
@@ -1797,6 +2007,7 @@ gtk_real_button_released (GtkButton *button)
gtk_button_clicked (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)
gtk_action_activate (priv->action);
if (priv->g_action)
g_action_activate (priv->g_action, NULL);
}
static gboolean
@@ -2255,15 +2469,22 @@ static void
gtk_button_update_state (GtkButton *button)
{
GtkButtonPrivate *priv = button->priv;
gboolean depressed, touchscreen;
GtkStateType new_state;
gboolean depressed;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (button)),
"gtk-touchscreen-mode", &touchscreen,
NULL);
if (priv->activate_timeout)
depressed = priv->depress_on_activate;
else if (priv->in_button && priv->button_down)
depressed = TRUE;
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;
else
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;
}
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/gtkimage.h>
#include <gtk/gtkenums.h>
G_BEGIN_DECLS
@@ -67,6 +68,7 @@ struct _GtkButtonClass
void (* enter) (GtkButton *button);
void (* leave) (GtkButton *button);
void (* activate) (GtkButton *button);
void (* toggled) (GtkButton *button);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
@@ -120,7 +122,20 @@ void gtk_button_set_image_position (GtkButton *button,
GtkPositionType gtk_button_get_image_position (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,
gboolean depressed);
void _gtk_button_paint (GtkButton *button,
@@ -131,6 +146,8 @@ void _gtk_button_paint (GtkButton *button,
GtkShadowType shadow_type,
const gchar *main_detail,
const gchar *default_detail);
void _gtk_button_set_active (GtkButton *, gboolean);
void gtk_button_toggled (GtkButton *);
G_END_DECLS

View File

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

View File

@@ -34,68 +34,17 @@
#include "gtkprivate.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)
static void
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
gtk_check_button_init (GtkCheckButton *check_button)
gtk_check_button_init (GtkCheckButton *button)
{
gtk_widget_set_has_window (GTK_WIDGET (check_button), FALSE);
gtk_widget_set_receives_default (GTK_WIDGET (check_button), FALSE);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (check_button), TRUE);
gtk_button_set_indicator_style (GTK_BUTTON (button), GTK_INDICATOR_STYLE_CHECK);
}
GtkWidget*
@@ -108,7 +57,9 @@ gtk_check_button_new (void)
GtkWidget*
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
{
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_with_label (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
#endif /* __GTK_CHECK_BUTTON_H__ */

View File

@@ -558,6 +558,15 @@ typedef enum
} GtkScrollablePolicy;
typedef enum
{
GTK_INDICATOR_STYLE_PLAIN,
GTK_INDICATOR_STYLE_CHECK,
GTK_INDICATOR_STYLE_RADIO
} GtkIndicatorStyle;
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,
GtkDirectionType direction);
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,
guint prop_id,
const GValue *value,
@@ -169,8 +167,6 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class)
button_class->clicked = gtk_radio_button_clicked;
check_button_class->draw_indicator = gtk_radio_button_draw_indicator;
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_receives_default (GTK_WIDGET (radio_button), FALSE);
_gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), TRUE);
_gtk_button_set_active (GTK_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;
@@ -440,7 +437,9 @@ gtk_radio_button_new_with_label (GSList *group,
{
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)
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
* 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);
if (gtk_widget_is_focus (widget))
@@ -789,7 +788,7 @@ gtk_radio_button_clicked (GtkButton *button)
GtkRadioButton *radio_button = GTK_RADIO_BUTTON (button);
GtkRadioButtonPrivate *priv = radio_button->priv;
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
GtkToggleButton *tmp_button;
GtkButton *tmp_button;
GtkStateType new_state;
GSList *tmp_list;
gint toggled;
@@ -799,7 +798,7 @@ gtk_radio_button_clicked (GtkButton *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_list = priv->group;
@@ -809,8 +808,8 @@ gtk_radio_button_clicked (GtkButton *button)
tmp_button = tmp_list->data;
tmp_list = tmp_list->next;
if (tmp_button != toggle_button &&
gtk_toggle_button_get_active (tmp_button))
if (tmp_button != button &&
gtk_button_get_active (tmp_button))
break;
tmp_button = NULL;
@@ -823,16 +822,14 @@ gtk_radio_button_clicked (GtkButton *button)
else
{
toggled = TRUE;
_gtk_toggle_button_set_active (toggle_button,
!gtk_toggle_button_get_active (toggle_button));
_gtk_button_set_active (button, !gtk_button_get_active (button));
new_state = (button->priv->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
}
}
else
{
toggled = TRUE;
_gtk_toggle_button_set_active (toggle_button,
!gtk_toggle_button_get_active (toggle_button));
_gtk_button_set_active (button, !gtk_button_get_active (button));
tmp_list = priv->group;
while (tmp_list)
@@ -840,7 +837,7 @@ gtk_radio_button_clicked (GtkButton *button)
tmp_button = tmp_list->data;
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));
break;
@@ -873,85 +870,3 @@ gtk_radio_button_clicked (GtkButton *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)
{
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

View File

@@ -38,61 +38,44 @@
#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 {
PROP_0,
PROP_ACTIVE,
PROP_INCONSISTENT,
PROP_DRAW_INDICATOR
};
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_pressed (GtkButton *button);
static void gtk_toggle_button_released (GtkButton *button);
static void gtk_toggle_button_clicked (GtkButton *button);
static void gtk_toggle_button_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural);
static void gtk_toggle_button_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural);
static void gtk_toggle_button_size_allocate (GtkWidget *widget,
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,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_toggle_button_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gtk_toggle_button_update_state (GtkButton *button);
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface);
static void gtk_toggle_button_update (GtkActivatable *activatable,
GtkAction *action,
const gchar *property_name);
static void gtk_toggle_button_update (GtkActivatable *activatable,
GtkAction *action,
const gchar *property_name);
static void gtk_toggle_button_sync_action_properties (GtkActivatable *activatable,
GtkAction *action);
GtkAction *action);
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_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
gtk_toggle_button_activatable_interface_init))
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
gtk_toggle_button_activatable_interface_init))
static void
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->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->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,
PROP_DRAW_INDICATOR,
g_param_spec_boolean ("draw-indicator",
P_("Draw Indicator"),
P_("If the toggle part of the button is displayed"),
FALSE,
GTK_PARAM_READWRITE));
P_("Draw Indicator"),
P_("If the toggle part of the button is displayed"),
FALSE,
GTK_PARAM_READWRITE|G_PARAM_DEPRECATED));
toggle_button_signals[TOGGLED] =
g_signal_new (I_("toggled"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkToggleButtonClass, toggled),
NULL, NULL,
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
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));
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
gtk_toggle_button_init (GtkToggleButton *toggle_button)
{
GtkToggleButtonPrivate *priv;
GSimpleAction *action;
toggle_button->priv = G_TYPE_INSTANCE_GET_PRIVATE (toggle_button,
GTK_TYPE_TOGGLE_BUTTON,
GtkToggleButtonPrivate);
priv = toggle_button->priv;
action = g_simple_action_new_stateful ("anonymous", NULL,
g_variant_new_boolean (FALSE));
g_signal_connect (action, "activate", G_CALLBACK (invert), NULL);
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;
}
@@ -180,8 +151,8 @@ gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface)
static void
gtk_toggle_button_update (GtkActivatable *activatable,
GtkAction *action,
const gchar *property_name)
GtkAction *action,
const gchar *property_name)
{
GtkToggleButton *button;
@@ -200,7 +171,7 @@ gtk_toggle_button_update (GtkActivatable *activatable,
static void
gtk_toggle_button_sync_action_properties (GtkActivatable *activatable,
GtkAction *action)
GtkAction *action)
{
GtkToggleButton *button;
@@ -226,7 +197,9 @@ gtk_toggle_button_new (void)
GtkWidget*
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)
{
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:
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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -277,23 +247,14 @@ gtk_toggle_button_set_property (GObject *object,
static void
gtk_toggle_button_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkToggleButton *tb = GTK_TOGGLE_BUTTON (object);
GtkToggleButtonPrivate *priv = tb->priv;
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:
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;
default:
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:
* @toggle_button: a #GtkToggleButton
* @button: a #GtkToggleButton
* @draw_indicator: if %TRUE, draw the button as a separate indicator
* 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
* and #GtkRadioButton that derive from #GtkToggleButton,
* not instances of #GtkToggleButton itself.
*
* Deprecated:3.0: Use gtk_button_set_indicator_style() instead
*/
void
gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
gboolean draw_indicator)
gtk_toggle_button_set_mode (GtkToggleButton *button,
gboolean draw_indicator)
{
GtkToggleButtonPrivate *priv;
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
priv = toggle_button->priv;
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_button_set_indicator_style (GTK_BUTTON (button),
draw_indicator ? GTK_INDICATOR_STYLE_CHECK
: GTK_INDICATOR_STYLE_PLAIN);
g_object_notify (G_OBJECT (button), "draw-indicator");
}
/**
* gtk_toggle_button_get_mode:
* @toggle_button: a #GtkToggleButton
* @button: a #GtkToggleButton
*
* Retrieves whether the button is displayed as a separate indicator
* and label. See gtk_toggle_button_set_mode().
*
* Return value: %TRUE if the togglebutton is drawn as a separate indicator
* and label.
*
* Deprecated:3.0: Use gtk_button_get_indicator_style() instead
**/
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
gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
gtk_toggle_button_set_active (GtkToggleButton *button,
gboolean is_active)
{
GtkToggleButtonPrivate *priv;
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
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;
gtk_button_set_active (GTK_BUTTON (button), is_active);
}
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
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:
* @toggle_button: a #GtkToggleButton
* @setting: %TRUE if state is inconsistent
* @button: a #GtkToggleButton
* @is_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
@@ -410,75 +349,328 @@ gtk_toggle_button_toggled (GtkToggleButton *toggle_button)
* 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_toggle_button_set_inconsistent (GtkToggleButton *toggle_button,
gboolean setting)
gtk_toggle_button_set_inconsistent (GtkToggleButton *button,
gboolean is_inconsistent)
{
GtkToggleButtonPrivate *priv;
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
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_button_set_inconsistent (GTK_BUTTON (button), is_inconsistent);
}
/**
* gtk_toggle_button_get_inconsistent:
* @toggle_button: a #GtkToggleButton
* @button: a #GtkToggleButton
*
* 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
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
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);
GtkStateType state_type;
GtkButtonPrivate *priv = button->priv;
GtkStateType state;
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)
state_type = GTK_STATE_NORMAL;
shadow_type = GTK_SHADOW_ETCHED_IN;
gtk_toggle_button_draw_indicator (button, cr);
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
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_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget),
state_type, shadow_type,
"togglebutton", "togglebuttondefault");
_gtk_button_paint (GTK_BUTTON (widget), cr,
allocation.width, allocation.height,
state, shadow_type,
"togglebutton", "togglebuttondefault");
}
child = gtk_bin_get_child (GTK_BIN (widget));
if (child)
gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
@@ -502,73 +694,3 @@ gtk_toggle_button_mnemonic_activate (GtkWidget *widget,
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))
typedef struct _GtkToggleButton GtkToggleButton;
typedef struct _GtkToggleButtonPrivate GtkToggleButtonPrivate;
typedef struct _GtkToggleButtonClass GtkToggleButtonClass;
struct _GtkToggleButton
{
/*< private >*/
GtkButton button;
GtkToggleButtonPrivate *priv;
};
struct _GtkToggleButtonClass
{
GtkButtonClass parent_class;
void (* toggled) (GtkToggleButton *toggle_button);
/* Padding for future expansion */
void (*_gtk_reserved1) (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_with_label (const gchar *label);
GtkWidget* gtk_toggle_button_new_with_mnemonic (const gchar *label);
void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
gboolean draw_indicator);
gboolean gtk_toggle_button_get_mode (GtkToggleButton *toggle_button);
void gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
gboolean is_active);
gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button);
void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
void gtk_toggle_button_set_inconsistent (GtkToggleButton *toggle_button,
gboolean setting);
gboolean gtk_toggle_button_get_inconsistent (GtkToggleButton *toggle_button);
void _gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
gboolean is_active);
GtkWidget* gtk_toggle_button_new (void);
GtkWidget* gtk_toggle_button_new_with_label (const gchar *label);
GtkWidget* gtk_toggle_button_new_with_mnemonic (const gchar *label);
#ifndef GTK_DISABLE_DEPRECATED
void gtk_toggle_button_set_mode (GtkToggleButton *button,
gboolean mode);
gboolean gtk_toggle_button_get_mode (GtkToggleButton *button);
#endif
void gtk_toggle_button_set_active (GtkToggleButton *button,
gboolean is_active);
gboolean gtk_toggle_button_get_active (GtkToggleButton *button);
void gtk_toggle_button_set_inconsistent (GtkToggleButton *button,
gboolean is_inconsistent);
gboolean gtk_toggle_button_get_inconsistent (GtkToggleButton *button);
void gtk_toggle_button_toggled (GtkToggleButton *button);
G_END_DECLS