diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c index 7193d8b7c5..a20c7fea10 100644 --- a/gtk/gtkswitch.c +++ b/gtk/gtkswitch.c @@ -47,13 +47,13 @@ * * ``` * switch - * ├── label - * ├── label + * ├── image + * ├── image * ╰── slider * ``` * * `GtkSwitch` has four css nodes, the main node with the name switch and - * subnodes for the slider and the on and off labels. Neither of them is + * subnodes for the slider and the on and off images. Neither of them is * using any style classes. * * # Accessibility @@ -140,6 +140,16 @@ G_DEFINE_TYPE_WITH_CODE (GtkSwitch, gtk_switch, GTK_TYPE_WIDGET, G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_switch_actionable_iface_init)) +static gboolean +is_right_side (GtkWidget *widget, + gboolean active) +{ + if (_gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + return active; + else + return !active; +} + static void gtk_switch_end_toggle_animation (GtkSwitch *self) { @@ -156,16 +166,18 @@ gtk_switch_on_frame_clock_update (GtkWidget *widget, gpointer user_data) { GtkSwitch *self = GTK_SWITCH (widget); + double progress; gtk_progress_tracker_advance_frame (&self->tracker, gdk_frame_clock_get_frame_time (clock)); if (gtk_progress_tracker_get_state (&self->tracker) != GTK_PROGRESS_STATE_AFTER) { - if (self->is_active) - self->handle_pos = 1.0 - gtk_progress_tracker_get_ease_out_cubic (&self->tracker, FALSE); + progress = gtk_progress_tracker_get_ease_out_cubic (&self->tracker, FALSE); + if (is_right_side (widget, self->is_active)) + self->handle_pos = 1.0 - progress; else - self->handle_pos = gtk_progress_tracker_get_ease_out_cubic (&self->tracker, FALSE); + self->handle_pos = progress; } else { @@ -251,7 +263,7 @@ gtk_switch_pan_gesture_pan (GtkGesturePan *gesture, gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED); - if (self->is_active) + if (is_right_side (widget, self->is_active)) offset += width / 2; offset /= width / 2; @@ -268,6 +280,7 @@ gtk_switch_pan_gesture_drag_end (GtkGestureDrag *gesture, double y, GtkSwitch *self) { + GtkWidget *widget = GTK_WIDGET (self); GdkEventSequence *sequence; gboolean active; @@ -278,16 +291,19 @@ gtk_switch_pan_gesture_drag_end (GtkGestureDrag *gesture, /* if half the handle passed the middle of the switch, then we * consider it to be on */ - active = self->handle_pos >= 0.5; + if (_gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + active = self->handle_pos >= 0.5; + else + active = self->handle_pos <= 0.5; } else if (!gtk_gesture_handles_sequence (self->click_gesture, sequence)) active = self->is_active; else return; - self->handle_pos = active ? 1.0 : 0.0; + self->handle_pos = is_right_side (widget, active) ? 1.0 : 0.0; gtk_switch_set_active (self, active); - gtk_widget_queue_allocate (GTK_WIDGET (self)); + gtk_widget_queue_allocate (widget); } static void @@ -354,6 +370,8 @@ gtk_switch_allocate (GtkWidget *widget, /* Center ON icon in left half */ gtk_widget_measure (self->on_image, GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL); child_alloc.x = ((width / 2) - min) / 2; + if (is_right_side (widget, FALSE)) + child_alloc.x += width / 2; child_alloc.width = min; gtk_widget_measure (self->on_image, GTK_ORIENTATION_VERTICAL, min, &min, NULL, NULL, NULL); child_alloc.y = (height - min) / 2; @@ -362,7 +380,9 @@ gtk_switch_allocate (GtkWidget *widget, /* Center OFF icon in right half */ gtk_widget_measure (self->off_image, GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL); - child_alloc.x = (width / 2) + ((width / 2) - min) / 2; + child_alloc.x = ((width / 2) - min) / 2; + if (is_right_side (widget, TRUE)) + child_alloc.x += width / 2; child_alloc.width = min; gtk_widget_measure (self->off_image, GTK_ORIENTATION_VERTICAL, min, &min, NULL, NULL, NULL); child_alloc.y = (height - min) / 2; @@ -370,6 +390,18 @@ gtk_switch_allocate (GtkWidget *widget, gtk_widget_size_allocate (self->off_image, &child_alloc, -1); } +static void +gtk_switch_direction_changed (GtkWidget *widget, + GtkTextDirection previous_dir) +{ + GtkSwitch *self = GTK_SWITCH (widget); + + self->handle_pos = 1.0 - self->handle_pos; + gtk_widget_queue_allocate (widget); + + GTK_WIDGET_CLASS (gtk_switch_parent_class)->direction_changed (widget, previous_dir); +} + static void gtk_switch_set_action_name (GtkActionable *actionable, const char *action_name) @@ -552,6 +584,8 @@ gtk_switch_class_init (GtkSwitchClass *klass) g_object_class_install_properties (gobject_class, LAST_PROP, switch_props); + widget_class->direction_changed = gtk_switch_direction_changed; + klass->activate = gtk_switch_activate; klass->state_set = state_set; @@ -676,6 +710,10 @@ gtk_switch_init (GtkSwitch *self) gtk_accessible_update_state (GTK_ACCESSIBLE (self), GTK_ACCESSIBLE_STATE_CHECKED, FALSE, -1); + if (is_right_side (GTK_WIDGET (self), FALSE)) + self->handle_pos = 1.0; + else + self->handle_pos = 0.0; } /** @@ -714,7 +752,7 @@ gtk_switch_set_active (GtkSwitch *self, self->is_active = is_active; - if (self->is_active) + if (is_right_side (GTK_WIDGET (self), self->is_active)) self->handle_pos = 1.0; else self->handle_pos = 0.0;