[geary/mjog/info-bar-cleanup: 45/50] Components.InfoBarStack: New class for stacking Gtk InfoBars
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/mjog/info-bar-cleanup: 45/50] Components.InfoBarStack: New class for stacking Gtk InfoBars
- Date: Fri, 20 Mar 2020 06:10:45 +0000 (UTC)
commit 190c4464997a0ad2916f659efecec34774e445d5
Author: Michael Gratton <mike vee net>
Date: Mon Mar 16 11:33:27 2020 +1100
Components.InfoBarStack: New class for stacking Gtk InfoBars
po/POTFILES.in | 1 +
.../components/components-info-bar-stack.vala | 193 +++++++++++++++++++++
src/client/meson.build | 1 +
3 files changed, 195 insertions(+)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 78eca534..9ece7de1 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -36,6 +36,7 @@ src/client/components/client-web-view.vala
src/client/components/components-attachment-pane.vala
src/client/components/components-entry-undo.vala
src/client/components/components-in-app-notification.vala
+src/client/components/components-info-bar-stack.vala
src/client/components/components-inspector.vala
src/client/components/components-placeholder-pane.vala
src/client/components/components-preferences-window.vala
diff --git a/src/client/components/components-info-bar-stack.vala
b/src/client/components/components-info-bar-stack.vala
new file mode 100644
index 00000000..3328418d
--- /dev/null
+++ b/src/client/components/components-info-bar-stack.vala
@@ -0,0 +1,193 @@
+/*
+ * Copyright © 2020 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+/**
+ * A stack-like widget for displaying Gtk InfoBar widgets.
+ *
+ * The stack ensures only one info bar is shown at once, shows a frame
+ * around the info bar, and manages revealing and hiding itself and
+ * the info bars as needed.
+ */
+public class Components.InfoBarStack : Gtk.Frame, Geary.BaseInterface {
+
+
+ private class SingletonQueue : Gee.AbstractQueue<Gtk.InfoBar> {
+
+ public override bool read_only {
+ get { return false; }
+ }
+
+ public override int size {
+ get { return (this.element == null) ? 0 : 1; }
+ }
+
+ public override int capacity {
+ get { return 1; }
+ }
+
+ public override bool is_full {
+ get { return (this.element != null); }
+ }
+
+ public override int remaining_capacity {
+ get { return (this.element != null) ? 0 : 1; }
+ }
+
+ private Gtk.InfoBar? element = null;
+
+
+ public override bool add(Gtk.InfoBar to_add) {
+ var added = false;
+ if (this.element != to_add) {
+ this.element = to_add;
+ added = true;
+ }
+ return added;
+ }
+
+ public override void clear() {
+ this.element = null;
+ }
+
+ public override bool contains(Gtk.InfoBar other) {
+ return (this.element == other);
+ }
+
+ public override Gee.Iterator<Gtk.InfoBar> iterator() {
+ // This sucks but it won't ever be used so oh well
+ return (
+ this.element == null
+ ? Gee.Collection.empty<Gtk.InfoBar>().iterator()
+ : Geary.Collection.single(this.element).iterator()
+ );
+ }
+
+ public override bool remove(Gtk.InfoBar to_remove) {
+ var removed = false;
+ if (this.element == to_remove) {
+ this.element = null;
+ removed = true;
+ }
+ return removed;
+ }
+
+ public override Gtk.InfoBar peek() {
+ return this.element;
+ }
+
+ public override Gtk.InfoBar poll() {
+ var element = this.element;
+ this.element = null;
+ return element;
+ }
+
+ }
+
+
+ /** Determines if an info bar is currently being shown. */
+ public bool has_current {
+ get { return (this.current_info_bar != null); }
+ }
+
+ /** Returns the currently displayed info bar, if any. */
+ public Gtk.InfoBar? current_info_bar {
+ get { return get_child() as Gtk.InfoBar; }
+ }
+
+ private Gee.Queue<Gtk.InfoBar> available;
+
+
+ /**
+ * Constructs a stack that shows the most recently added info bar.
+ */
+ public InfoBarStack.exclusive() {
+ this.shadow_type = IN;
+ this.visible = false;
+ get_style_context().add_class("geary-info-bar-frame");
+
+ this.available = new SingletonQueue();
+ }
+
+ /**
+ * Adds an info bar to the stack.
+ *
+ * If this is the first info bar added, the stack will show itself
+ * and reveal the info bar. Otherwise, depending on the type of
+ * stack constructed, the info bar may or may not be revealed
+ * immediately.
+ */
+ public new void add(Gtk.InfoBar to_add) {
+ if (this.available.offer(to_add)) {
+ update();
+ }
+ }
+
+ /**
+ * Removes an info bar to the stack.
+ *
+ * If the info bar is currently visible, it will be hidden and
+ * replaced with the next info bar added. If the only info bar
+ * present is removed, the stack also hides itself.
+ */
+ public new void remove(Gtk.InfoBar to_remove) {
+ if (this.available.remove(to_remove)) {
+ update();
+ }
+ }
+
+ /**
+ * Removes all info bars from the stack, hiding the stack.
+ */
+ public new void remove_all() {
+ this.available.clear();
+ update();
+ }
+
+ private void update() {
+ var current = this.current_info_bar;
+ var next = this.available.peek();
+ if (current == null && next != null) {
+ // Not currently showing an info bar but have one to show,
+ // so show it
+ this.visible = true;
+ base.add(next);
+ this.size_allocate.connect(on_allocation_changed);
+ next.revealed = true;
+ next.notify["revealed"].connect(on_revealed);
+ } else if (current != null && next != current) {
+ // Currently showing an info bar but should be showing
+ // something else, so start hiding it
+ current.notify["revealed"].disconnect(on_revealed);
+ current.revealed = false;
+ } else if (current == null && next == null) {
+ // Not currently showing anything and there's nothing to
+ // show, so hide the frame
+ this.visible = false;
+ }
+ }
+
+ private void on_allocation_changed() {
+ var current = this.current_info_bar;
+ if (current != null) {
+ Gtk.Allocation alloc;
+ get_allocation(out alloc);
+ if (alloc.height < 2) {
+ this.size_allocate.disconnect(on_allocation_changed);
+ base.remove(current);
+ update();
+ }
+ }
+ }
+
+ private void on_revealed(GLib.Object target, GLib.ParamSpec param) {
+ var current = this.current_info_bar;
+ if (current == target && !current.revealed) {
+ remove(current);
+ }
+ }
+
+}
diff --git a/src/client/meson.build b/src/client/meson.build
index d6dd9a4a..556e06ae 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -33,6 +33,7 @@ geary_client_vala_sources = files(
'components/client-web-view.vala',
'components/components-attachment-pane.vala',
'components/components-entry-undo.vala',
+ 'components/components-info-bar-stack.vala',
'components/components-inspector.vala',
'components/components-in-app-notification.vala',
'components/components-inspector-error-view.vala',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]