[libadwaita/wip/exalm/browsing-view: 15/18] header-bar: Magic back buttons
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libadwaita/wip/exalm/browsing-view: 15/18] header-bar: Magic back buttons
- Date: Fri, 14 Oct 2022 20:14:35 +0000 (UTC)
commit 4d85619387f5be9c76ca61d0db6d8911f0cf60a4
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Sun Oct 9 02:15:31 2022 +0400
header-bar: Magic back buttons
src/adw-header-bar.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/adw-header-bar.h | 6 ++
2 files changed, 198 insertions(+), 3 deletions(-)
---
diff --git a/src/adw-header-bar.c b/src/adw-header-bar.c
index fb28d2ce..f2aeadae 100644
--- a/src/adw-header-bar.c
+++ b/src/adw-header-bar.c
@@ -23,6 +23,7 @@
#include "adw-header-bar.h"
+#include "adw-button-content.h"
#include "adw-browsing-view.h"
#include "adw-enums.h"
#include "adw-gizmo-private.h"
@@ -156,6 +157,7 @@ struct _AdwHeaderBar {
guint show_start_title_buttons : 1;
guint show_end_title_buttons : 1;
+ guint show_back_button : 1;
guint track_default_decoration : 1;
AdwCenteringPolicy centering_policy;
@@ -163,7 +165,11 @@ struct _AdwHeaderBar {
GtkSizeGroup *size_group;
+ GtkWidget *back_button;
+ GtkWidget *browsing_view;
GtkWidget *browsing_view_child;
+ AdwBrowsingViewChild *browsing_view_previous_child;
+ GBinding *back_button_binding;
};
enum {
@@ -171,6 +177,7 @@ enum {
PROP_TITLE_WIDGET,
PROP_SHOW_START_TITLE_BUTTONS,
PROP_SHOW_END_TITLE_BUTTONS,
+ PROP_SHOW_BACK_BUTTON,
PROP_DECORATION_LAYOUT,
PROP_CENTERING_POLICY,
LAST_PROP
@@ -213,6 +220,45 @@ create_end_window_controls (AdwHeaderBar *self)
self->end_window_controls = controls;
}
+static void
+update_back_button (AdwHeaderBar *self)
+{
+ AdwBrowsingViewChild *prev_child = NULL;
+
+ if (self->show_back_button && self->browsing_view && self->browsing_view_child)
+ prev_child = adw_browsing_view_get_previous_child (ADW_BROWSING_VIEW (self->browsing_view),
+ ADW_BROWSING_VIEW_CHILD (self->browsing_view_child));
+
+ if (prev_child == self->browsing_view_previous_child)
+ return;
+
+ self->browsing_view_previous_child = prev_child;
+
+ if (prev_child) {
+ if (!self->back_button) {
+ self->back_button = gtk_button_new_from_icon_name ("go-previous-symbolic");
+
+ gtk_widget_add_css_class (self->back_button, "back-button");
+ gtk_actionable_set_action_name (GTK_ACTIONABLE (self->back_button), "browsing.pop");
+
+ gtk_box_insert_child_after (GTK_BOX (self->start_box),
+ self->back_button,
+ self->start_window_controls);
+ }
+
+ g_clear_pointer (&self->back_button_binding, g_binding_unbind);
+ self->back_button_binding =
+ g_object_bind_property (prev_child, "title",
+ self->back_button, "tooltip-text",
+ G_BINDING_SYNC_CREATE);
+ } else if (self->back_button) {
+ gtk_box_remove (GTK_BOX (self->start_box), self->back_button);
+ self->back_button = NULL;
+ self->browsing_view_previous_child = NULL;
+ self->back_button_binding = NULL;
+ }
+}
+
static void
update_title (AdwHeaderBar *self)
{
@@ -262,21 +308,88 @@ construct_title_label (AdwHeaderBar *self)
update_title (self);
}
+static void
+browsing_view_pushed_cb (AdwHeaderBar *self)
+{
+ AdwBrowsingViewChild *visible_child;
+
+ g_assert (self->browsing_view);
+ g_assert (self->browsing_view_child);
+
+ visible_child = adw_browsing_view_get_visible_child (ADW_BROWSING_VIEW (self->browsing_view));
+
+ if (visible_child == ADW_BROWSING_VIEW_CHILD (self->browsing_view_child))
+ update_back_button (self);
+}
+
+static void
+browsing_view_notify_previous_view_cb (AdwHeaderBar *self)
+{
+ AdwBrowsingViewChild *prev_child;
+
+ g_assert (self->browsing_view);
+ g_assert (self->browsing_view_child);
+
+ prev_child = adw_browsing_view_get_previous_child (ADW_BROWSING_VIEW (self->browsing_view),
+ ADW_BROWSING_VIEW_CHILD (self->browsing_view_child));
+
+ if (!prev_child || gtk_widget_get_parent (GTK_WIDGET (prev_child)) != GTK_WIDGET (self->browsing_view))
+ update_back_button (self);
+}
+
+static void
+track_back_button (AdwHeaderBar *self)
+{
+ if (!self->browsing_view)
+ return;
+
+ g_signal_connect_swapped (self->browsing_view, "pushed",
+ G_CALLBACK (browsing_view_pushed_cb), self);
+ g_signal_connect_swapped (self->browsing_view, "notify::previous-view",
+ G_CALLBACK (browsing_view_notify_previous_view_cb), self);
+}
+
+static void
+untrack_back_button (AdwHeaderBar *self)
+{
+ if (!self->browsing_view)
+ return;
+
+ g_signal_handlers_disconnect_by_func (self->browsing_view,
+ browsing_view_pushed_cb, self);
+ g_signal_handlers_disconnect_by_func (self->browsing_view,
+ browsing_view_notify_previous_view_cb, self);
+}
+
static void
adw_header_bar_root (GtkWidget *widget)
{
AdwHeaderBar *self = ADW_HEADER_BAR (widget);
- GtkWidget *browsing_view_child;
+ GtkWidget *browsing_view = NULL, *browsing_view_child;
GTK_WIDGET_CLASS (adw_header_bar_parent_class)->root (widget);
browsing_view_child = gtk_widget_get_ancestor (widget, ADW_TYPE_BROWSING_VIEW_CHILD);
- if (browsing_view_child) {
+ if (browsing_view_child)
+ browsing_view = gtk_widget_get_parent (browsing_view_child);
+
+ if (!ADW_IS_BROWSING_VIEW (browsing_view))
+ browsing_view = NULL;
+
+ // TODO: if there's a way to edit hsitory at some point, this will need to
+ // be updated too
+ // TODO: need to check can-go-back once it's implemented
+
+ if (browsing_view && browsing_view_child) {
+ self->browsing_view = browsing_view;
self->browsing_view_child = browsing_view_child;
g_signal_connect_swapped (browsing_view_child, "notify::title",
G_CALLBACK (update_title), widget);
+
+ if (self->show_back_button)
+ track_back_button (self);
} else {
GtkRoot *root = gtk_widget_get_root (widget);
@@ -286,6 +399,7 @@ adw_header_bar_root (GtkWidget *widget)
}
update_title (ADW_HEADER_BAR (widget));
+ update_back_button (ADW_HEADER_BAR (widget));
}
static void
@@ -293,11 +407,16 @@ adw_header_bar_unroot (GtkWidget *widget)
{
AdwHeaderBar *self = ADW_HEADER_BAR (widget);
- if (self->browsing_view_child) {
+ if (self->browsing_view && self->browsing_view_child) {
g_signal_handlers_disconnect_by_func (self->browsing_view_child,
update_title, widget);
+ untrack_back_button (self);
+
+ self->browsing_view = NULL;
self->browsing_view_child = NULL;
+
+ update_back_button (self);
} else {
g_signal_handlers_disconnect_by_func (gtk_widget_get_root (widget),
update_title, widget);
@@ -352,6 +471,9 @@ adw_header_bar_get_property (GObject *object,
case PROP_SHOW_END_TITLE_BUTTONS:
g_value_set_boolean (value, adw_header_bar_get_show_end_title_buttons (self));
break;
+ case PROP_SHOW_BACK_BUTTON:
+ g_value_set_boolean (value, adw_header_bar_get_show_back_button (self));
+ break;
case PROP_DECORATION_LAYOUT:
g_value_set_string (value, adw_header_bar_get_decoration_layout (self));
break;
@@ -382,6 +504,9 @@ adw_header_bar_set_property (GObject *object,
case PROP_SHOW_END_TITLE_BUTTONS:
adw_header_bar_set_show_end_title_buttons (self, g_value_get_boolean (value));
break;
+ case PROP_SHOW_BACK_BUTTON:
+ adw_header_bar_set_show_back_button (self, g_value_get_boolean (value));
+ break;
case PROP_DECORATION_LAYOUT:
adw_header_bar_set_decoration_layout (self, g_value_get_string (value));
break;
@@ -474,6 +599,18 @@ adw_header_bar_class_init (AdwHeaderBarClass *class)
TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+ /**
+ * AdwHeaderBar:show-back-button: (attributes org.gtk.Property.get=adw_header_bar_get_show_back_button
org.gtk.Property.set=adw_header_bar_set_show_back_button)
+ *
+ * TODO
+ *
+ * Since: 1.3
+ */
+ props[PROP_SHOW_BACK_BUTTON] =
+ g_param_spec_boolean ("show-back-button", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
/**
* AdwHeaderBar:decoration-layout: (attributes org.gtk.Property.get=adw_header_bar_get_decoration_layout
org.gtk.Property.set=adw_header_bar_set_decoration_layout)
*
@@ -524,6 +661,7 @@ adw_header_bar_init (AdwHeaderBar *self)
self->decoration_layout = NULL;
self->show_start_title_buttons = TRUE;
self->show_end_title_buttons = TRUE;
+ self->show_back_button = TRUE;
self->handle = gtk_window_handle_new ();
gtk_widget_set_parent (self->handle, GTK_WIDGET (self));
@@ -852,6 +990,57 @@ adw_header_bar_set_show_end_title_buttons (AdwHeaderBar *self,
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SHOW_END_TITLE_BUTTONS]);
}
+/**
+ * adw_header_bar_get_show_back_button: (attributes org.gtk.Method.get_property=show-back-button)
+ * @self: a header bar
+ *
+ * TODO
+ *
+ * Returns: TODO
+ *
+ * Since: 1.3
+ */
+gboolean
+adw_header_bar_get_show_back_button (AdwHeaderBar *self)
+{
+ g_return_val_if_fail (ADW_IS_HEADER_BAR (self), FALSE);
+
+ return self->show_back_button;
+}
+
+/**
+ * adw_header_bar_set_show_back_button: (attributes org.gtk.Method.set_property=show-back-button)
+ * @self: a header bar
+ * @show_back_button: TODO
+ *
+ * TODO
+ *
+ * Since: 1.3
+ */
+void
+adw_header_bar_set_show_back_button (AdwHeaderBar *self,
+ gboolean show_back_button)
+{
+ g_return_if_fail (ADW_IS_HEADER_BAR (self));
+
+ show_back_button = !!show_back_button;
+
+ if (self->show_back_button == show_back_button)
+ return;
+
+ self->show_back_button = show_back_button;
+
+ if (self->show_back_button)
+ track_back_button (self);
+ else
+ untrack_back_button (self);
+
+ if (self->start_box)
+ update_back_button (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SHOW_BACK_BUTTON]);
+}
+
/**
* adw_header_bar_get_decoration_layout: (attributes org.gtk.Method.get_property=decoration-layout)
* @self: a header bar
diff --git a/src/adw-header-bar.h b/src/adw-header-bar.h
index cd18885e..acfa29c2 100644
--- a/src/adw-header-bar.h
+++ b/src/adw-header-bar.h
@@ -72,6 +72,12 @@ ADW_AVAILABLE_IN_ALL
void adw_header_bar_set_show_end_title_buttons (AdwHeaderBar *self,
gboolean setting);
+ADW_AVAILABLE_IN_ALL
+gboolean adw_header_bar_get_show_back_button (AdwHeaderBar *self);
+ADW_AVAILABLE_IN_ALL
+void adw_header_bar_set_show_back_button (AdwHeaderBar *self,
+ gboolean show_back_button);
+
ADW_AVAILABLE_IN_ALL
const char *adw_header_bar_get_decoration_layout (AdwHeaderBar *self);
ADW_AVAILABLE_IN_ALL
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]