[gnome-games/wip/exalm/unified-window: 12/26] ui: Introduce TitlebarBox



commit 552c8f5d1d0d8131718ddff34af94e3e65f9c9d6
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Fri Apr 10 16:34:54 2020 +0500

    ui: Introduce TitlebarBox

 src/meson.build          |   1 +
 src/ui/titlebar-box.vala | 270 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 271 insertions(+)
---
diff --git a/src/meson.build b/src/meson.build
index c76cb575..cb717f60 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -151,6 +151,7 @@ vala_sources = [
   'ui/shortcuts-window.vala',
   'ui/snapshot-row.vala',
   'ui/snapshots-list.vala',
+  'ui/titlebar-box.vala',
   'ui/ui-view.vala',
 
   'utils/composite-cover.vala',
diff --git a/src/ui/titlebar-box.vala b/src/ui/titlebar-box.vala
new file mode 100644
index 00000000..26ba8621
--- /dev/null
+++ b/src/ui/titlebar-box.vala
@@ -0,0 +1,270 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+private class Games.TitlebarBox : Gtk.Container, Gtk.Buildable {
+       private Gtk.Widget _titlebar;
+       public Gtk.Widget titlebar {
+               get { return _titlebar; }
+               set {
+                       if (titlebar == value)
+                               return;
+
+                       if (titlebar != null)
+                               titlebar.unparent ();
+
+                       _titlebar = value;
+
+                       if (titlebar != null)
+                               titlebar.set_parent (this);
+               }
+       }
+
+       private Gtk.Widget _content;
+       public Gtk.Widget content {
+               get { return _content; }
+               set {
+                       if (content == value)
+                               return;
+
+                       if (content != null)
+                               content.unparent ();
+
+                       _content = value;
+
+                       if (content != null)
+                               content.set_parent (this);
+               }
+       }
+
+       private bool _overlay;
+       public bool overlay {
+               get { return _overlay; }
+               set {
+                       if (overlay == value)
+                               return;
+
+                       _overlay = value;
+
+                       animate_overlay ();
+               }
+       }
+
+       private bool _reveal_titlebar;
+       public bool reveal_titlebar {
+               get { return _reveal_titlebar; }
+               set {
+                       if (reveal_titlebar == value)
+                               return;
+
+                       _reveal_titlebar = value;
+
+                       animate_reveal ();
+               }
+       }
+
+       public int overlay_duration { get; set; default = 250; }
+       public int reveal_duration { get; set; default = 250; }
+
+       private int64 overlay_start_time;
+       private uint overlay_tick_cb_id;
+       private double overlay_progress;
+
+
+       private int64 reveal_start_time;
+       private uint reveal_tick_cb_id;
+       private double reveal_progress;
+
+       construct {
+               set_has_window (false);
+
+               reveal_titlebar = true;
+               reveal_progress = 1;
+       }
+
+       private void animate_overlay () {
+               if (!Hdy.get_enable_animations (this) || !get_mapped ()) {
+                       overlay_progress = overlay ? 1 : 0;
+                       queue_resize ();
+                       return;
+               }
+
+               if (overlay_tick_cb_id != 0) {
+                       remove_tick_callback (overlay_tick_cb_id);
+                       overlay_tick_cb_id = 0;
+               }
+
+               overlay_start_time = get_frame_clock ().get_frame_time () / 1000;
+               overlay_progress = overlay ? 0 : 1;
+               overlay_tick_cb_id = add_tick_callback (overlay_tick_cb);
+       }
+
+       private bool overlay_tick_cb (Gtk.Widget widget, Gdk.FrameClock frame_clock) {
+               var frame_time = frame_clock.get_frame_time () / 1000;
+               var t = (double) (frame_time - overlay_start_time) / overlay_duration;
+
+               if (t >= 1) {
+                       overlay_progress = overlay ? 1 : 0;
+                       overlay_tick_cb_id = 0;
+
+                       queue_resize ();
+
+                       return false;
+               }
+
+               overlay_progress = ease_out_cubic (t);
+
+               if (!overlay)
+                       overlay_progress = 1 - overlay_progress;
+
+               queue_resize ();
+
+               return true;
+       }
+
+       private void animate_reveal () {
+               if (!Hdy.get_enable_animations (this) || !get_mapped ()) {
+                       reveal_progress = reveal_titlebar ? 1 : 0;
+                       queue_resize ();
+                       return;
+               }
+
+               if (reveal_tick_cb_id != 0) {
+                       remove_tick_callback (reveal_tick_cb_id);
+                       reveal_tick_cb_id = 0;
+               }
+
+               reveal_start_time = get_frame_clock ().get_frame_time () / 1000;
+               reveal_progress = reveal_titlebar ? 0 : 1;
+               reveal_tick_cb_id = add_tick_callback (reveal_tick_cb);
+       }
+
+       private bool reveal_tick_cb (Gtk.Widget widget, Gdk.FrameClock frame_clock) {
+               var frame_time = frame_clock.get_frame_time () / 1000;
+               var t = (double) (frame_time - reveal_start_time) / reveal_duration;
+
+               if (t >= 1) {
+                       reveal_progress = reveal_titlebar ? 1 : 0;
+                       reveal_tick_cb_id = 0;
+
+                       queue_resize ();
+
+                       return false;
+               }
+
+               reveal_progress = ease_out_cubic (t);
+
+               if (!reveal_titlebar)
+                       reveal_progress = 1 - reveal_progress;
+
+               queue_resize ();
+
+               return true;
+       }
+
+       private double ease_out_cubic (double t) {
+               double p = t - 1;
+               return p * p * p + 1;
+       }
+
+       protected override void get_preferred_width (out int min, out int nat) {
+               int content_min, content_nat, titlebar_min, titlebar_nat;
+
+               if (titlebar != null)
+                       titlebar.get_preferred_width (out titlebar_min, out titlebar_nat);
+               else
+                       titlebar_min = titlebar_nat = 0;
+
+               if (content != null)
+                       content.get_preferred_width (out content_min, out content_nat);
+               else
+                       content_min = content_nat = 0;
+
+               min = int.max (content_min, titlebar_min);
+               nat = int.max (content_nat, titlebar_nat);
+       }
+
+       private int adjust_for_overlay (int height) {
+               var progress = double.min (1 - overlay_progress, reveal_progress);
+
+               return (int) Math.round (height * progress);
+       }
+
+       protected override void get_preferred_height (out int min, out int nat) {
+               int content_min, content_nat, titlebar_min, titlebar_nat;
+
+               if (titlebar != null)
+                       titlebar.get_preferred_height (out titlebar_min, out titlebar_nat);
+               else
+                       titlebar_min = titlebar_nat = 0;
+
+               if (content != null)
+                       content.get_preferred_height (out content_min, out content_nat);
+               else
+                       content_min = content_nat = 0;
+
+               min = int.max (content_min + adjust_for_overlay (titlebar_min), titlebar_min);
+               nat = int.max (content_nat + adjust_for_overlay (titlebar_nat), titlebar_nat);
+       }
+
+       protected override void size_allocate (Gtk.Allocation alloc) {
+               int titlebar_height = 0;
+
+               if (titlebar != null) {
+                       int min, nat;
+                       titlebar.get_preferred_height (out min, out nat);
+
+                       titlebar_height = int.max (min, nat);
+
+                       titlebar.size_allocate ({
+                               alloc.x,
+                               alloc.y - (int) Math.round (titlebar_height * (1 - reveal_progress)),
+                               alloc.width,
+                               titlebar_height
+                       });
+               }
+
+               titlebar_height = adjust_for_overlay (titlebar_height);
+
+               if (content != null)
+                       content.size_allocate ({
+                               alloc.x,
+                               alloc.y + titlebar_height,
+                               alloc.width,
+                               alloc.height - titlebar_height
+                       });
+
+               base.size_allocate (alloc);
+       }
+
+       protected override void add (Gtk.Widget widget) {
+               return_if_fail (content == null);
+
+               if (content == null)
+                       content = widget;
+       }
+
+       protected override void remove (Gtk.Widget widget) {
+               return_if_fail (widget == titlebar || widget == content);
+
+               if (widget == titlebar)
+                       titlebar = null;
+               else
+                       content = null;
+       }
+
+       protected override void forall_internal (bool include_internals, Gtk.Callback callback) {
+               if (content != null)
+                       callback (content);
+
+               if (titlebar != null)
+                       callback (titlebar);
+       }
+
+       public void add_child (Gtk.Builder builder, Object child, string? type) {
+               var widget = child as Gtk.Widget;
+
+               if (type == "titlebar")
+                       titlebar = widget;
+               else
+                       content = content;
+       }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]