[gnome-clocks/zbrown/header-controls: 6/7] headerbar: move headerbar logic to the headerbar itself



commit cea01d06aa92054dd92d8bead9a3014a1b43fa71
Author: Zander Brown <zbrown gnome org>
Date:   Fri Dec 6 12:23:53 2019 +0000

    headerbar: move headerbar logic to the headerbar itself
    
    each panel stores it's own state that is them bound to the headerbar at the active panel changes
    
    this helps ensure the state is consistent as an inactive panel cannot change the headerbar

 .gitignore                      |   2 +
 data/gnome-clocks.gresource.xml |   1 +
 data/ui/alarm.ui                |   2 +
 data/ui/headerbar.ui            | 281 ++++++++++++++++++++++++++++++++++++++++
 data/ui/window.ui               | 123 ++++++------------
 data/ui/world.ui                |   2 +
 src/alarm.vala                  |  56 ++++----
 src/clock.vala                  |  55 +++-----
 src/headerbar.vala              | 158 ++++++++++++++--------
 src/main.vala                   |   2 +
 src/stopwatch.vala              |  21 ++-
 src/timer.vala                  |  19 ++-
 src/widgets.vala                |  99 ++++----------
 src/window.vala                 | 215 ++++++++++++++++++------------
 src/world.vala                  |  73 +++++------
 15 files changed, 673 insertions(+), 436 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 56dddc8..f31cee2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 build
 _build
+*~
+.vscode
diff --git a/data/gnome-clocks.gresource.xml b/data/gnome-clocks.gresource.xml
index c4a345f..5a922b6 100644
--- a/data/gnome-clocks.gresource.xml
+++ b/data/gnome-clocks.gresource.xml
@@ -8,6 +8,7 @@
     <file preprocess="xml-stripblanks">gtk/menus.ui</file>
     <file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
     <file preprocess="xml-stripblanks">ui/window.ui</file>
+    <file preprocess="xml-stripblanks">ui/headerbar.ui</file>
     <file preprocess="xml-stripblanks">ui/worldlocationdialog.ui</file>
     <file preprocess="xml-stripblanks">ui/world.ui</file>
     <file preprocess="xml-stripblanks">ui/worldtile.ui</file>
diff --git a/data/ui/alarm.ui b/data/ui/alarm.ui
index 1d65ad8..6ead5a3 100644
--- a/data/ui/alarm.ui
+++ b/data/ui/alarm.ui
@@ -5,6 +5,7 @@
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="homogeneous">False</property>
+    <property name="n-selected" bind-source="content_view" bind-property="n-selected" 
bind-flags="sync-create" />
     <signal name="notify::visible-child" handler="visible_child_changed" swapped="no"/>
     <child>
       <object class="GtkGrid" id="empty_view">
@@ -46,6 +47,7 @@
     <child>
       <object class="ClocksContentView" id="content_view">
         <property name="visible">True</property>
+        <property name="mode" bind-source="ClocksAlarmFace" bind-property="view-mode" 
bind-flags="sync-create|bidirectional" />
         <signal name="item-activated" handler="item_activated" swapped="no"/>
       </object>
     </child>
diff --git a/data/ui/headerbar.ui b/data/ui/headerbar.ui
new file mode 100644
index 0000000..bd903c0
--- /dev/null
+++ b/data/ui/headerbar.ui
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <requires lib="libhandy" version="0.0"/>
+  <menu id="primary-menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
+        <attribute name="action">win.show-help-overlay</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Help</attribute>
+        <attribute name="action">win.help</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_About Clocks</attribute>
+        <attribute name="action">win.about</attribute>
+      </item>
+    </section>
+  </menu>
+  <template class="ClocksHeaderBar" parent="HdyHeaderBar">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="title">Clocks</property>
+    <property name="centering_policy">strict</property>
+    <property name="show_close_button">True</property>
+    <signal name="notify::subtitle" handler="subtitle_changed" swapped="no"/>
+    <child type="title">
+      <object class="GtkStack" id="title_stack">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="homogeneous">False</property>
+        <property name="transition_type">none</property>
+        <child>
+          <object class="HdySqueezer" id="squeezer">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="transition_type">crossfade</property>
+            <child>
+              <object class="HdyViewSwitcher" id="title_wide_switcher">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">center</property>
+                <property name="policy">wide</property>
+                <property name="stack" bind-source="ClocksHeaderBar" bind-property="stack" 
bind-flags="sync-create">ignore-me</property>
+              </object>
+            </child>
+            <child>
+              <object class="HdyViewSwitcher" id="title_narrow_switcher">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">center</property>
+                <property name="policy">narrow</property>
+                <property name="stack" bind-source="ClocksHeaderBar" bind-property="stack" 
bind-flags="sync-create">ignore-me</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkBox" id="title_text">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">center</property>
+                <property name="valign">center</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="title_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" bind-source="ClocksHeaderBar" bind-property="title" 
bind-flags="sync-create" />
+                    <style>
+                      <class name="title"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">switcher</property>
+          </packing>
+        </child>
+        <child>
+          <object class="ClocksSelectionMenuButton">
+            <property name="visible">True</property>
+            <property name="n-items" bind-source="ClocksHeaderBar" bind-property="n-selected" 
bind-flags="sync-create" />
+          </object>
+          <packing>
+            <property name="name">selection</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="valign">center</property>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="label" bind-source="ClocksHeaderBar" bind-property="title" 
bind-flags="sync-create" />
+                <property name="ellipsize">end</property>
+                <style>
+                  <class name="title"/>
+                </style>
+              </object>
+            </child>
+            <child>
+              <object class="GtkRevealer" id="reveal_subtitle">
+                <property name="visible">True</property>
+                <property name="reveal-child">False</property>
+                <child>
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="label" bind-source="ClocksHeaderBar" bind-property="subtitle" 
bind-flags="sync-create" />
+                    <property name="ellipsize">end</property>
+                    <style>
+                      <class name="subtitle"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">title</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkStack" id="start_button_stack">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="transition_type">crossfade</property>
+        <child>
+          <object class="GtkButton">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="action_name">win.new</property>
+            <property name="tooltip-text" translatable="yes">New</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">list-add-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">new</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="action_name">win.back</property>
+            <property name="tooltip-text" translatable="yes">Back</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">go-previous-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">back</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+          </object>
+          <packing>
+            <property name="name">empty</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkStack" id="end_button_stack">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hhomogeneous">False</property>
+        <property name="transition_type">crossfade</property>
+        <child>
+          <object class="GtkMenuButton">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="action_name">win.show-primary-menu</property>
+            <property name="tooltip-text" translatable="yes">Menu</property>
+            <property name="menu_model">primary-menu</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">open-menu-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">menu</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton">
+            <property name="label" translatable="yes">_Cancel</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="action_name">win.select-cancel</property>
+            <property name="use_underline">True</property>
+          </object>
+          <packing>
+            <property name="name">cancel</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+          </object>
+          <packing>
+            <property name="name">empty</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="pack_type">end</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkStack" id="select_stack">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="transition_type">crossfade</property>
+        <child>
+          <object class="GtkButton">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="action_name">win.select</property>
+            <property name="tooltip-text" translatable="yes">Select</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">object-select-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">select</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="name">empty</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="pack_type">end</property>
+      </packing>
+    </child>
+  </template>
+  <object class="GtkStack" id="ignore-me"></object>
+</interface>
diff --git a/data/ui/window.ui b/data/ui/window.ui
index 8b9ba6b..036e119 100644
--- a/data/ui/window.ui
+++ b/data/ui/window.ui
@@ -4,94 +4,17 @@
   <requires lib="gtk+" version="3.20"/>
   <requires lib="libhandy" version="0.0"/>
   <template class="ClocksWindow" parent="GtkApplicationWindow">
-    <property name="title" translatable="yes">Clocks</property>
-    <menu id="primary-menu">
-      <section>
-        <item>
-          <attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
-          <attribute name="action">win.show-help-overlay</attribute>
-        </item>
-        <item>
-          <attribute name="label" translatable="yes">_Help</attribute>
-          <attribute name="action">win.help</attribute>
-        </item>
-        <item>
-          <attribute name="label" translatable="yes">_About Clocks</attribute>
-          <attribute name="action">win.about</attribute>
-        </item>
-      </section>
-    </menu>
+    <property name="title" bind-source="header_bar" bind-property="title" bind-flags="sync-create" />
     <child type="titlebar">
       <object class="ClocksHeaderBar" id="header_bar">
         <property name="visible">True</property>
         <property name="hexpand">True</property>
         <property name="vexpand">False</property>
+        <property name="stack">stack</property>
+        <property name="switcher_bar">switcher_bar</property>
         <style>
           <class name="titlebar"/>
         </style>
-        <child type="title">
-          <object class="HdySqueezer" id="squeezer">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="transition_type">crossfade</property>
-            <child>
-              <object class="HdyViewSwitcher" id="title_wide_switcher">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">center</property>
-                <property name="policy">wide</property>
-                <property name="stack">stack</property>
-              </object>
-            </child>
-            <child>
-              <object class="HdyViewSwitcher" id="title_narrow_switcher">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">center</property>
-                <property name="policy">narrow</property>
-                <property name="stack">stack</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkBox" id="title_text">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">center</property>
-                <property name="valign">center</property>
-                <property name="orientation">vertical</property>
-                <child>
-                  <object class="GtkLabel" id="title_label">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Clock</property>
-                    <style>
-                      <class name="title"/>
-                    </style>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkMenuButton" id="menu_button">
-            <property name="valign">center</property>
-            <property name="menu_model">primary-menu</property>
-            <property name="action_name">win.show-primary-menu</property>
-            <property name="direction">none</property>
-            <style>
-              <class name="image-button"/>
-            </style>
-          </object>
-          <packing>
-            <property name="pack_type">end</property>
-          </packing>
-        </child>
       </object>
     </child>
     <child>
@@ -106,8 +29,46 @@
             <property name="hexpand">True</property>
             <property name="vexpand">True</property>
             <property name="homogeneous">False</property>
+            <signal name="notify::visible-child" handler="pane_changed" swapped="no"/>
             <child>
-              <placeholder/>
+              <object class="ClocksWorldFace" id="world">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="name">world</property>
+                <property name="title">World</property>
+                <property name="icon-name">globe-symbolic</property>
+              </packing>
+            </child>
+            <child>
+              <object class="ClocksAlarmFace" id="alarm">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="name">alarm</property>
+                <property name="title">Alarms</property>
+                <property name="icon-name">alarm-symbolic</property>
+              </packing>
+            </child>
+            <child>
+              <object class="ClocksStopwatchFace" id="stopwatch">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="name">stopwatch</property>
+                <property name="title">Stopwatch</property>
+                <property name="icon-name">stopwatch-symbolic</property>
+              </packing>
+            </child>
+            <child>
+              <object class="ClocksTimerFace" id="timer">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="name">timer</property>
+                <property name="title">Timer</property>
+                <property name="icon-name">timer-symbolic</property>
+              </packing>
             </child>
           </object>
           <packing>
diff --git a/data/ui/world.ui b/data/ui/world.ui
index 071fb72..9b8c9cc 100644
--- a/data/ui/world.ui
+++ b/data/ui/world.ui
@@ -5,6 +5,7 @@
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="homogeneous">False</property>
+    <property name="n-selected" bind-source="content_view" bind-property="n-selected" 
bind-flags="sync-create" />
     <signal name="notify::visible-child" handler="visible_child_changed" swapped="no"/>
     <child>
       <object class="GtkGrid" id="empty_view">
@@ -46,6 +47,7 @@
     <child>
       <object class="ClocksContentView" id="content_view">
         <property name="visible">True</property>
+        <property name="mode" bind-source="ClocksWorldFace" bind-property="view-mode" 
bind-flags="sync-create|bidirectional" />
         <signal name="item-activated" handler="item_activated" swapped="no"/>
       </object>
     </child>
diff --git a/src/alarm.vala b/src/alarm.vala
index f7e50ae..8f43019 100644
--- a/src/alarm.vala
+++ b/src/alarm.vala
@@ -582,12 +582,13 @@ private class RingingPanel : Gtk.Grid {
 
 [GtkTemplate (ui = "/org/gnome/clocks/ui/alarm.ui")]
 public class Face : Gtk.Stack, Clocks.Clock {
-    public string label { get; construct set; }
-    public string icon_name { get; construct set; }
-    public HeaderBar header_bar { get; construct set; }
+    public ViewMode view_mode { get; set; default = NORMAL; }
     public PanelId panel_id { get; construct set; }
-    public ButtonMode button_mode { get; private set; default = NEW; }
-
+    public ButtonMode button_mode { get; set; default = NEW; }
+    public bool can_select { get; set; default = true; }
+    public bool n_selected { get; set; }
+    public string title { get; set; default = _("Clocks"); }
+    public string subtitle { get; set; }
 
     private ContentStore alarms;
     private GLib.Settings settings;
@@ -598,11 +599,8 @@ public class Face : Gtk.Stack, Clocks.Clock {
     [GtkChild]
     private RingingPanel ringing_panel;
 
-    public Face (HeaderBar header_bar) {
-        Object (label: _("Alarm"),
-                icon_name: "alarm-symbolic",
-                header_bar: header_bar,
-                panel_id: PanelId.ALARM);
+    construct {
+        panel_id = ALARM;
 
         alarms = new ContentStore ();
         settings = new GLib.Settings ("org.gnome.clocks");
@@ -632,8 +630,6 @@ public class Face : Gtk.Stack, Clocks.Clock {
             return new Tile ((Item)item);
         });
 
-        content_view.set_header_bar (header_bar);
-
         load ();
         show_all ();
 
@@ -675,14 +671,16 @@ public class Face : Gtk.Stack, Clocks.Clock {
     [GtkCallback]
     private void dismiss_ringing_panel () {
        reset_view ();
+       button_mode = NEW;
+       title = _("Clocks");
     }
 
     [GtkCallback]
     private void visible_child_changed () {
         if (visible_child == empty_view || visible_child == content_view) {
-            header_bar.mode = HeaderBar.Mode.NORMAL;
+            view_mode = NORMAL;
         } else if (visible_child == ringing_panel) {
-            header_bar.mode = HeaderBar.Mode.STANDALONE;
+            view_mode = STANDALONE;
         }
     }
 
@@ -717,11 +715,13 @@ public class Face : Gtk.Stack, Clocks.Clock {
         ringing_panel.alarm = alarm;
         ringing_panel.update ();
         visible_child = ringing_panel;
+        title = ringing_panel.alarm.name;
+        view_mode = STANDALONE;
+        button_mode = NONE;
     }
 
     private void reset_view () {
         visible_child = alarms.get_n_items () == 0 ? empty_view : content_view;
-        request_header_bar_update ();
     }
 
     public void activate_new () {
@@ -738,6 +738,14 @@ public class Face : Gtk.Stack, Clocks.Clock {
         dialog.show_all ();
     }
 
+    public void activate_select () {
+        view_mode = SELECTION;
+    }
+
+    public void activate_select_cancel () {
+        view_mode = NORMAL;
+    }
+
     public void activate_select_all () {
         content_view.select_all ();
     }
@@ -749,24 +757,6 @@ public class Face : Gtk.Stack, Clocks.Clock {
     public bool escape_pressed () {
         return content_view.escape_pressed ();
     }
-
-    public void update_header_bar () {
-        switch (header_bar.mode) {
-            case HeaderBar.Mode.NORMAL:
-                button_mode = NEW;
-                content_view.update_header_bar ();
-                break;
-            case HeaderBar.Mode.SELECTION:
-                content_view.update_header_bar ();
-                break;
-            case HeaderBar.Mode.STANDALONE:
-                button_mode = NONE;
-                header_bar.title = ringing_panel.alarm.name;
-                break;
-            default:
-                assert_not_reached ();
-        }
-    }
 }
 
 } // namespace Alarm
diff --git a/src/clock.vala b/src/clock.vala
index fd55e4b..2a436ec 100644
--- a/src/clock.vala
+++ b/src/clock.vala
@@ -16,43 +16,22 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-namespace Clocks {
-
-public enum PanelId {
+public enum Clocks.PanelId {
     WORLD,
     ALARM,
     STOPWATCH,
-    TIMER;
-
-    public string to_string() {
-        switch (this) {
-            case WORLD:
-                return "world";
-            case ALARM:
-                return "alarm";
-            case STOPWATCH:
-                return "stopwatch";
-            case TIMER:
-                return "timer";
-            default:
-                assert_not_reached();
-        }
-    }
+    TIMER,
 }
 
-public const int N_PANELS = 4;
-
-public enum ButtonMode {
-    NEW,
-    BACK,
-    NONE
-}
 
-public interface Clock : GLib.Object {
-    public abstract string label { get; protected construct set; }
-    public abstract string icon_name { get; protected construct set; }
-    public abstract HeaderBar header_bar { get; protected construct set; }
+public interface Clocks.Clock : GLib.Object {
     public abstract PanelId panel_id { get; protected construct set; }
+    public abstract ButtonMode button_mode { get; set; }
+    public abstract ViewMode view_mode { get; set; }
+    public abstract bool can_select { get; set; }
+    public abstract bool n_selected { get; set; }
+    public abstract string title { get; protected set; }
+    public abstract string subtitle { get; protected set; }
 
     public virtual void activate_new () {
     }
@@ -60,23 +39,19 @@ public interface Clock : GLib.Object {
     public virtual void activate_back () {
     }
 
-    public virtual void activate_select_all () {
+    public virtual void activate_select () {
     }
 
-    public virtual void activate_select_none () {
+    public virtual void activate_select_cancel () {
     }
 
-    public virtual bool escape_pressed () {
-        return false;
+    public virtual void activate_select_all () {
     }
 
-    public virtual void back () {
+    public virtual void activate_select_none () {
     }
 
-    public signal void request_header_bar_update ();
-
-    public virtual void update_header_bar () {
+    public virtual bool escape_pressed () {
+        return false;
     }
 }
-
-} // namespace Clocks
diff --git a/src/headerbar.vala b/src/headerbar.vala
index d8e4690..03b05f5 100644
--- a/src/headerbar.vala
+++ b/src/headerbar.vala
@@ -18,33 +18,60 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-public class Clocks.HeaderBar : Gtk.HeaderBar {
-    public enum Mode {
-        NORMAL,
-        SELECTION,
-        STANDALONE
-    }
 
-    [CCode (notify = false)]
-    public Mode mode {
+public enum Clocks.ButtonMode {
+    NEW,
+    BACK,
+    NONE
+}
+
+
+public enum Clocks.ViewMode {
+    NORMAL,
+    SELECTION,
+    STANDALONE
+}
+
+
+[GtkTemplate (ui = "/org/gnome/clocks/ui/headerbar.ui")]
+public class Clocks.HeaderBar : Hdy.HeaderBar {
+    public ViewMode view_mode {
         get {
             return _mode;
         }
 
         set {
-            if (_mode != value) {
-                _mode = value;
+            _mode = value;
 
-                if (_mode == Mode.SELECTION) {
+            switch (_mode) {
+                case SELECTION:
+                    title_stack.visible_child_name = "selection";
                     get_style_context ().add_class ("selection-mode");
-                    button_stack.hide ();
-                } else {
+                    start_button_stack.hide ();
+                    end_button_stack.show ();
+                    select_stack.hide ();
+                    end_button_stack.visible_child_name = "cancel";
+                    centering_policy = LOOSE;
+                    break;
+                case NORMAL:
+                    title_stack.visible_child_name = "switcher";
                     get_style_context ().remove_class ("selection-mode");
-                    button_stack.show ();
-                }
-
-                notify_property ("mode");
+                    start_button_stack.show ();
+                    end_button_stack.show ();
+                    select_stack.show ();
+                    end_button_stack.visible_child_name = "menu";
+                    centering_policy = STRICT;
+                    break;
+                case STANDALONE:
+                    title_stack.visible_child_name = "title";
+                    start_button_stack.show ();
+                    end_button_stack.hide ();
+                    select_stack.hide ();
+                    centering_policy = STRICT;
+                    break;
             }
+            
+            show_close_button = _mode != SELECTION;
         }
     }
 
@@ -56,56 +83,75 @@ public class Clocks.HeaderBar : Gtk.HeaderBar {
         set {
             switch (value) {
                 case NEW:
-                    button_stack.visible_child_name = "new";
+                    start_button_stack.visible_child_name = "new";
                     break;
                 case BACK:
-                    button_stack.visible_child_name = "back";
+                    start_button_stack.visible_child_name = "back";
                     break;
                 case NONE:
-                    button_stack.visible_child_name = "none";
+                    start_button_stack.visible_child_name = "empty";
                     break;
             }
+            _button_mode = value;
         }
     }
 
-    private Mode _mode;
+    public bool can_select {
+        get {
+            return _can_select;
+        }
+        
+        set {
+            _can_select = value;
+            if (_can_select) {
+                select_stack.visible_child_name = "select";
+            } else {
+                select_stack.visible_child_name = "empty";
+            }
+        }
+    }
+
+    public Gtk.Stack stack { get; set; }
+    public Hdy.ViewSwitcherBar switcher_bar { get; set; }
+    public uint n_selected { get; set; }
+
+    private bool _can_select;
+    private ViewMode _mode;
     private ButtonMode _button_mode;
-    private Gtk.Stack button_stack;
-
-    construct {
-        button_stack = new Gtk.Stack ();
-        button_stack.homogeneous = true;
-        button_stack.transition_type = CROSSFADE;
-        button_stack.show ();
-
-        var new_button = new Gtk.Button.from_icon_name ("list-add-symbolic",
-                                                        BUTTON);
-        new_button.tooltip_text = _("New");
-        new_button.action_name = "win.new";
-        new_button.show ();
-        button_stack.add_named (new_button, "new");
-
-        var back_button = new Gtk.Button.from_icon_name ("go-previous-symbolic",
-                                                         BUTTON);
-        back_button.tooltip_text = _("Back");
-        back_button.action_name = "win.back";
-        back_button.show ();
-        button_stack.add_named (back_button, "back");
-
-        var empty = new Gtk.Box (VERTICAL, 0);
-        empty.show ();
-        button_stack.add_named (empty, "none");
-
-        pack_start (button_stack);
+
+    [GtkChild]
+    private Gtk.Stack start_button_stack;
+    [GtkChild]
+    private Gtk.Stack select_stack;
+    [GtkChild]
+    private Gtk.Stack end_button_stack;
+    [GtkChild]
+    private Hdy.Squeezer squeezer;
+    [GtkChild]
+    private Hdy.ViewSwitcher title_wide_switcher;
+    [GtkChild]
+    private Hdy.ViewSwitcher title_narrow_switcher;
+    [GtkChild]
+    private Gtk.Box title_text;
+    [GtkChild]
+    private Gtk.Stack title_stack;
+    [GtkChild]
+    private Gtk.Revealer reveal_subtitle;
+
+    class construct {
+        typeof (SelectionMenuButton).ensure ();
     }
 
-    public void clear () {
-        custom_title = null;
-        foreach (Gtk.Widget w in get_children ()) {
-            if (w == button_stack) {
-                continue;
-            }
-            w.hide ();
-        }
+    public override void size_allocate (Gtk.Allocation allocation) {
+        base.size_allocate (allocation);
+        squeezer.set_child_enabled (title_wide_switcher, allocation.width > 800);
+        squeezer.set_child_enabled (title_narrow_switcher, allocation.width > 500);
+        squeezer.set_child_enabled (title_text, allocation.width <= 500);
+        switcher_bar.set_reveal (allocation.width <= 500);
+    }
+
+    [GtkCallback]
+    private void subtitle_changed () {
+        reveal_subtitle.reveal_child = subtitle != null && subtitle.length > 0;
     }
 }
diff --git a/src/main.vala b/src/main.vala
index e966304..4e7e396 100644
--- a/src/main.vala
+++ b/src/main.vala
@@ -22,6 +22,8 @@ int main (string[] args) {
     Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
     Intl.textdomain (Config.GETTEXT_PACKAGE);
 
+    Environment.set_application_name (_("Clocks"));
+
     Hdy.init (ref args);
 
     var app = new Clocks.Application ();
diff --git a/src/stopwatch.vala b/src/stopwatch.vala
index d5b9c1c..0bc4744 100644
--- a/src/stopwatch.vala
+++ b/src/stopwatch.vala
@@ -112,15 +112,13 @@ public class Face : Gtk.Box, Clocks.Clock {
         TOTAL
     }
 
-    public string label { get; construct set; }
-    public string icon_name { get; construct set; }
-    public HeaderBar header_bar { get; construct set; }
     public PanelId panel_id { get; construct set; }
-    public ButtonMode button_mode {
-        get {
-            return NONE;
-        }
-    }
+    public ButtonMode button_mode { get; set; default = NONE; }
+    public ViewMode view_mode { get; set; default = NORMAL; }
+    public bool can_select { get; set; default = false; }
+    public bool n_selected { get; set; }
+    public string title { get; set; default = _("Clocks"); }
+    public string subtitle { get; set; }
 
     public State state { get; private set; default = State.RESET; }
 
@@ -141,11 +139,8 @@ public class Face : Gtk.Box, Clocks.Clock {
     [GtkChild]
     private Gtk.ListBox laps_list;
 
-    public Face (HeaderBar header_bar) {
-        Object (label: _("Stopwatch"),
-                icon_name: "stopwatch-symbolic",
-                header_bar: header_bar,
-                panel_id: PanelId.STOPWATCH);
+    construct {
+        panel_id = STOPWATCH;
 
         timer = new GLib.Timer ();
         tick_id = 0;
diff --git a/src/timer.vala b/src/timer.vala
index 7a0d7d4..a4702e3 100644
--- a/src/timer.vala
+++ b/src/timer.vala
@@ -71,11 +71,13 @@ public class Face : Gtk.Stack, Clocks.Clock {
         PAUSED
     }
 
-    public string label { get; construct set; }
-    public string icon_name { get; construct set; }
-    public HeaderBar header_bar { get; construct set; }
     public PanelId panel_id { get; construct set; }
-    public ButtonMode button_mode { get; private set; default = NONE; }
+    public ButtonMode button_mode { get; set; default = NONE; }
+    public ViewMode view_mode { get; set; default = NORMAL; }
+    public bool can_select { get; set; default = false; }
+    public bool n_selected { get; set; }
+    public string title { get; set; default = _("Clocks"); }
+    public string subtitle { get; set; }
 
     public State state { get; private set; default = State.STOPPED; }
 
@@ -113,12 +115,9 @@ public class Face : Gtk.Stack, Clocks.Clock {
     [GtkChild]
     private Gtk.Button left_button;
 
-    public Face (HeaderBar header_bar) {
-        Object (label: _("Timer"),
-                icon_name: "timer-symbolic",
-                header_bar: header_bar,
-                panel_id: PanelId.TIMER,
-                transition_type: Gtk.StackTransitionType.CROSSFADE);
+    construct {
+        panel_id = TIMER;
+        transition_type = CROSSFADE;
 
         settings = new GLib.Settings ("org.gnome.clocks");
 
diff --git a/src/widgets.vala b/src/widgets.vala
index a26ae91..206e348 100644
--- a/src/widgets.vala
+++ b/src/widgets.vala
@@ -203,7 +203,7 @@ private class SelectionMenuButton : Gtk.MenuButton {
     private uint _n_items;
     private Gtk.Label menubutton_label;
 
-    public SelectionMenuButton () {
+    construct {
         var app = (Gtk.Application) GLib.Application.get_default ();
         menu_model = app.get_menu_by_id ("selection-menu");
         menubutton_label = new Gtk.Label (_("Click on items to select them"));
@@ -220,48 +220,37 @@ private class SelectionMenuButton : Gtk.MenuButton {
 }
 
 public class ContentView : Gtk.Bin {
-    public enum Mode {
-        NORMAL,
-        SELECTION
-    }
-
-    public Mode mode {
+    public ViewMode mode {
         get {
             return _mode;
         }
 
-        private set {
+        set {
             if (_mode != value) {
                 _mode = value;
 
                 switch (_mode) {
-                case Mode.SELECTION:
-                    header_bar.mode = HeaderBar.Mode.SELECTION;
-                    action_bar.show ();
-                    break;
-                case Mode.NORMAL:
-                    header_bar.mode = HeaderBar.Mode.NORMAL;
-                    action_bar.hide ();
-                    // clear current selection
-                    model.unselect_all ();
-                    break;
-                default:
-                    assert_not_reached ();
+                    case SELECTION:
+                        action_bar.show ();
+                        break;
+                    case NORMAL:
+                    case STANDALONE:
+                        action_bar.hide ();
+                        // clear current selection
+                        model.unselect_all ();
+                        break;
                 }
             }
         }
     }
+    public uint n_selected { get; private set; }
 
-    private Mode _mode;
+    private ViewMode _mode;
     private ContentStore model;
     private Gtk.FlowBox flow_box;
-    private Gtk.Button select_button;
-    private Gtk.Button cancel_button;
-    private SelectionMenuButton selection_menubutton;
     private Gtk.Grid grid;
     private Gtk.ActionBar action_bar;
     private Gtk.Button delete_button;
-    private HeaderBar? header_bar;
 
     construct {
         get_style_context ().add_class ("content-view");
@@ -299,7 +288,7 @@ public class ContentView : Gtk.Bin {
         delete_button.hexpand = true;
         delete_button.clicked.connect (() => {
             model.delete_selected ();
-            mode = Mode.NORMAL;
+            mode = NORMAL;
         });
 
         action_bar.pack_end (delete_button);
@@ -317,7 +306,7 @@ public class ContentView : Gtk.Bin {
 
         model.selection_changed.connect (() => {
             var n_items = model.get_n_selected ();
-            selection_menubutton.n_items = n_items;
+            n_selected = n_items;
 
             if (n_items != 0) {
                 delete_button.sensitive = true;
@@ -334,12 +323,12 @@ public class ContentView : Gtk.Bin {
             var event_box = new Gtk.EventBox ();
             event_box.add (inner);
             event_box.button_press_event.connect ((event) => {
-                // On right click, swicth to selection mode automatically
+                // On right click, switch to selection mode automatically
                 if (item.selectable && event.button == Gdk.BUTTON_SECONDARY) {
-                    mode = Mode.SELECTION;
+                    mode = SELECTION;
                 }
 
-                if (item.selectable && mode == Mode.SELECTION) {
+                if (item.selectable && mode == SELECTION) {
                     item.selected = !item.selected;
                     return true;
                 } else if (event.button == Gdk.BUTTON_PRIMARY) {
@@ -366,13 +355,13 @@ public class ContentView : Gtk.Bin {
             item.bind_property ("selected", check, "active", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE 
| BindingFlags.BIDIRECTIONAL);
             item.bind_property ("selectable", check, "visible", BindingFlags.DEFAULT | 
BindingFlags.SYNC_CREATE,
                                  (binding, selectable, ref visible) => {
-                visible = this.mode == Mode.SELECTION && (item).selectable;
+                visible = this.mode == SELECTION && (item).selectable;
                 return true;
             });
 
             bind_property ("mode", check, "visible", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE,
                            (binding, mode, ref visible) => {
-                visible = mode == Mode.SELECTION && (item).selectable;
+                visible = mode == ViewMode.SELECTION && (item).selectable;
                 return true;
             });
 
@@ -407,7 +396,7 @@ public class ContentView : Gtk.Bin {
     }
 
     public void select_all () {
-        mode = Mode.SELECTION;
+        mode = SELECTION;
         model.select_all ();
     }
 
@@ -416,52 +405,12 @@ public class ContentView : Gtk.Bin {
     }
 
     public bool escape_pressed () {
-        if (mode == Mode.SELECTION) {
-            mode = Mode.NORMAL;
+        if (mode == SELECTION) {
+            mode = NORMAL;
             return true;
         }
         return false;
     }
-
-    public void set_header_bar (HeaderBar bar) {
-        header_bar = bar;
-
-        select_button = new Gtk.Button ();
-        var select_button_image = new Gtk.Image.from_icon_name ("object-select-symbolic", Gtk.IconSize.MENU);
-        select_button.set_image (select_button_image);
-        select_button.valign = Gtk.Align.CENTER;
-        select_button.no_show_all = true;
-        select_button.clicked.connect (() => {
-            mode = Mode.SELECTION;
-        });
-        header_bar.pack_end (select_button);
-
-        cancel_button = new Gtk.Button.with_label (_("Cancel"));
-        cancel_button.no_show_all = true;
-        cancel_button.valign = Gtk.Align.CENTER;
-        cancel_button.clicked.connect (() => {
-            mode = Mode.NORMAL;
-        });
-        header_bar.pack_end (cancel_button);
-
-        selection_menubutton = new SelectionMenuButton ();
-    }
-
-    public void update_header_bar () {
-        switch (header_bar.mode) {
-        case HeaderBar.Mode.SELECTION:
-            header_bar.custom_title = selection_menubutton;
-            cancel_button.show ();
-            break;
-        case HeaderBar.Mode.NORMAL:
-            var first_selectable = model.find ((i) => {
-                return i.selectable;
-            });
-
-            select_button.visible = first_selectable != null;
-            break;
-        }
-    }
 }
 
 public class AmPmToggleButton : Gtk.Button {
diff --git a/src/window.vala b/src/window.vala
index add06cd..1419927 100644
--- a/src/window.vala
+++ b/src/window.vala
@@ -27,6 +27,8 @@ public class Window : Gtk.ApplicationWindow {
         { "back", on_back_activate },
         { "help", on_help_activate },
         { "about", on_about_activate },
+        { "select", on_select_activate },
+        { "select-cancel", on_select_cancel_activate },
 
         // selection menu
         { "select-all", on_select_all_activate },
@@ -38,22 +40,25 @@ public class Window : Gtk.ApplicationWindow {
     [GtkChild]
     private Gtk.Stack stack;
     [GtkChild]
-    private Hdy.ViewSwitcherBar switcher_bar;
+    private World.Face world;
     [GtkChild]
-    private Hdy.Squeezer squeezer;
+    private Alarm.Face alarm;
     [GtkChild]
-    private Hdy.ViewSwitcher title_wide_switcher;
+    private Stopwatch.Face stopwatch;
     [GtkChild]
-    private Hdy.ViewSwitcher title_narrow_switcher;
-    [GtkChild]
-    private Gtk.Box title_text;
+    private Timer.Face timer;
 
-    [GtkChild]
-    private Gtk.MenuButton menu_button;
     private GLib.Settings settings;
-    private Gtk.Widget[] panels;
 
+    // DIY DzlBindingGroup
     private Binding bind_button_mode = null;
+    private Binding bind_view_mode = null;
+    private Binding bind_can_select = null;
+    private Binding bind_selected = null;
+    private Binding bind_title = null;
+    private Binding bind_subtitle = null;
+
+    private bool inited = false;
 
     public Window (Application app) {
         Object (application: app);
@@ -67,6 +72,15 @@ public class Window : Gtk.ApplicationWindow {
             settings.apply ();
         });
 
+        // GSettings gives us the nick, which matches the stack page name
+        stack.visible_child_name = settings.get_string ("panel-id");
+
+        inited = true;
+
+        header_bar.bind_property ("title", this, "title", SYNC_CREATE);
+
+        pane_changed ();
+
         // Setup window geometry saving
         Gdk.WindowState window_state = (Gdk.WindowState)settings.get_int ("state");
         if (Gdk.WindowState.MAXIMIZED in window_state) {
@@ -76,50 +90,6 @@ public class Window : Gtk.ApplicationWindow {
         int width, height;
         settings.get ("size", "(ii)", out width, out height);
         resize (width, height);
-        set_title (_("Clocks"));
-
-        panels = new Gtk.Widget[N_PANELS];
-
-        panels[PanelId.WORLD] = new World.Face (header_bar);
-        panels[PanelId.ALARM] =  new Alarm.Face (header_bar);
-        panels[PanelId.STOPWATCH] = new Stopwatch.Face (header_bar);
-        panels[PanelId.TIMER] = new Timer.Face (header_bar);
-
-        var world = (World.Face)panels[PanelId.WORLD];
-        var alarm = (Alarm.Face)panels[PanelId.ALARM];
-        var stopwatch = (Stopwatch.Face)panels[PanelId.STOPWATCH];
-        var timer = (Timer.Face)panels[PanelId.TIMER];
-
-       foreach (var panel in panels) {
-            stack.add_titled (panel, ((Clock)panel).label, ((Clock)panel).label);
-            stack.child_set_property(panel, "icon-name", ((Clock)panel).icon_name);
-        }
-
-        var stack_id = stack.notify["visible-child"].connect (() => {
-            var help_overlay = get_help_overlay ();
-            var page = stack.visible_child;
-            help_overlay.view_name = Type.from_instance (page).name();
-            update_header_bar ();
-
-            if (bind_button_mode != null) {
-                bind_button_mode.unbind ();
-            }
-            bind_button_mode = page.bind_property ("button-mode",
-                                                   header_bar,
-                                                   "button-mode",
-                                                   SYNC_CREATE);
-        });
-
-        var header_bar_id = header_bar.notify["mode"].connect (() => {
-            update_header_bar ();
-        });
-
-        stack.destroy.connect(() => {
-            header_bar.disconnect (header_bar_id);
-            header_bar_id = 0;
-            stack.disconnect (stack_id);
-            stack_id = 0;
-        });
 
         alarm.ring.connect ((w) => {
             world.reset_view ();
@@ -146,44 +116,61 @@ public class Window : Gtk.ApplicationWindow {
                                      Gdk.Key.Page_Up,
                                      Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK,
                                      "change-page", 1,
-                                     typeof(int), -1);
+                                     typeof(int), 0);
         Gtk.BindingEntry.add_signal (binding_set,
                                      Gdk.Key.Page_Down,
                                      Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK,
                                      "change-page", 1,
                                      typeof(int), 1);
 
-        stack.visible_child = panels[settings.get_enum ("panel-id")];
-
         Gtk.StyleContext style = get_style_context ();
         if (Config.PROFILE == "Devel") {
             style.add_class ("devel");
         }
 
-        update_header_bar ();
-
         show_all ();
     }
 
     [Signal(action = true)]
     public virtual signal void change_page (int offset) {
-        int page;
+        var dir = false;
 
-        stack.child_get (stack.visible_child, "position", out page);
-        page += offset;
-        if (page >= 0 && page < panels.length) {
-            stack.visible_child = panels[page];
+        if (get_direction () == RTL) {
+            dir = offset == 0 ? false : true;
         } else {
-            stack.error_bell ();
+            dir = offset == 1 ? false : true;
         }
-    }
 
-    public override void size_allocate (Gtk.Allocation allocation) {
-        base.size_allocate (allocation);
-        switcher_bar.set_reveal (allocation.width <= 500);
-        squeezer.set_child_enabled (title_wide_switcher, allocation.width > 800);
-        squeezer.set_child_enabled (title_narrow_switcher, allocation.width > 500);
-        squeezer.set_child_enabled (title_text, allocation.width <= 500);
+        switch (stack.visible_child_name) {
+            case "world":
+                if (dir) {
+                    stack.error_bell ();
+                } else {
+                    stack.visible_child = alarm;
+                }
+                break;
+            case "alarm":
+                if (dir) {
+                    stack.visible_child = world;
+                } else {
+                    stack.visible_child = stopwatch;
+                }
+                break;
+            case "stopwatch":
+                if (dir) {
+                    stack.visible_child = alarm;
+                } else {
+                    stack.visible_child = timer;
+                }
+                break;
+            case "timer":
+                if (dir) {
+                    stack.visible_child = stopwatch;
+                } else {
+                    stack.error_bell ();
+                }
+                break;
+        }
     }
 
     private void on_show_primary_menu_activate (SimpleAction action) {
@@ -199,6 +186,14 @@ public class Window : Gtk.ApplicationWindow {
         ((Clock) stack.visible_child).activate_back ();
     }
 
+    private void on_select_activate () {
+        ((Clock) stack.visible_child).activate_select ();
+    }
+
+    private void on_select_cancel_activate () {
+        ((Clock) stack.visible_child).activate_select_cancel ();
+    }
+
     private void on_select_all_activate () {
         ((Clock) stack.visible_child).activate_select_all ();
     }
@@ -208,12 +203,12 @@ public class Window : Gtk.ApplicationWindow {
     }
 
     public void show_world () {
-        ((World.Face) panels[PanelId.WORLD]).reset_view ();
-        stack.visible_child = panels[PanelId.WORLD];;
+        world.reset_view ();
+        stack.visible_child = world;
     }
 
     public void add_world_location (GWeather.Location location) {
-        ((World.Face) panels[PanelId.WORLD]).add_location (location);
+        world.add_location (location);
     }
 
     public override bool key_press_event (Gdk.EventKey event) {
@@ -236,7 +231,7 @@ public class Window : Gtk.ApplicationWindow {
         uint button;
 
         if (((Gdk.Event)(event)).get_button (out button) && button == BUTTON_BACK) {
-            ((Clock) stack.visible_child).back ();
+            ((Clock) stack.visible_child).activate_back ();
             return true;
         }
 
@@ -306,22 +301,70 @@ public class Window : Gtk.ApplicationWindow {
                                null);
     }
 
-    private void update_header_bar () {
-        header_bar.clear ();
+    [GtkCallback]
+    private void pane_changed () {
+        var help_overlay = get_help_overlay ();
+        var panel = (Clock) stack.visible_child;
+
+        if (stack.in_destruction ()) {
+            return;
+        }
+
+        help_overlay.view_name = Type.from_instance (panel).name();
+
+        if (inited) {
+            settings.set_enum ("panel-id", panel.panel_id);
+        }
+
+        if (bind_button_mode != null) {
+            bind_button_mode.unbind ();
+        }
+        bind_button_mode = panel.bind_property ("button-mode",
+                                                header_bar,
+                                                "button-mode",
+                                                SYNC_CREATE);
+
+        if (bind_view_mode != null) {
+            bind_view_mode.unbind ();
+        }
+        bind_view_mode = panel.bind_property ("view-mode",
+                                              header_bar,
+                                              "view-mode",
+                                              SYNC_CREATE);
+
+        if (bind_can_select != null) {
+            bind_can_select.unbind ();
+        }
+        bind_can_select = panel.bind_property ("can-select",
+                                               header_bar,
+                                               "can-select",
+                                               SYNC_CREATE);
+
+        if (bind_selected != null) {
+            bind_selected.unbind ();
+        }
+        bind_selected = panel.bind_property ("n-selected",
+                                             header_bar,
+                                             "n-selected",
+                                             SYNC_CREATE);
 
-        var clock = (Clock) stack.visible_child;
-        if (clock != null) {
-            settings.set_enum ("panel-id", clock.panel_id);
-            clock.update_header_bar ();
-            ((Gtk.Widget) clock).grab_focus ();
+        if (bind_title != null) {
+            bind_title.unbind ();
         }
+        bind_title = panel.bind_property ("title",
+                                          header_bar,
+                                          "title",
+                                          SYNC_CREATE);
 
-        if (header_bar.mode == HeaderBar.Mode.NORMAL) {
-            header_bar.custom_title = squeezer;
-            menu_button.show ();
+        if (bind_subtitle != null) {
+            bind_subtitle.unbind ();
         }
+        bind_subtitle = panel.bind_property ("subtitle",
+                                             header_bar,
+                                             "subtitle",
+                                             SYNC_CREATE);
 
-        header_bar.set_show_close_button (header_bar.mode != HeaderBar.Mode.SELECTION);
+        stack.visible_child.grab_focus ();
     }
 }
 
diff --git a/src/world.vala b/src/world.vala
index 81ebc64..c181441 100644
--- a/src/world.vala
+++ b/src/world.vala
@@ -338,12 +338,13 @@ private class LocationDialog : Gtk.Dialog {
 
 [GtkTemplate (ui = "/org/gnome/clocks/ui/world.ui")]
 public class Face : Gtk.Stack, Clocks.Clock {
-    public string label { get; construct set; }
-    public string icon_name { get; construct set; }
-    public HeaderBar header_bar { get; construct set; }
     public PanelId panel_id { get; construct set; }
-    public ButtonMode button_mode { get; private set; default = NEW; }
-
+    public ButtonMode button_mode { get; set; default = NEW; }
+    public ViewMode view_mode { get; set; default = NORMAL; }
+    public bool can_select { get; set; default = true; }
+    public bool n_selected { get; set; }
+    public string title { get; set; default = _("Clocks"); }
+    public string subtitle { get; set; }
 
     private ContentStore locations;
     private GLib.Settings settings;
@@ -363,12 +364,9 @@ public class Face : Gtk.Stack, Clocks.Clock {
     [GtkChild]
     private Gtk.Label standalone_sunset_label;
 
-    public Face (HeaderBar header_bar) {
-        Object (label: _("World"),
-                header_bar: header_bar,
-                icon_name: "globe-symbolic",
-                panel_id: PanelId.WORLD,
-                transition_type: Gtk.StackTransitionType.CROSSFADE);
+    construct {
+        panel_id = WORLD;
+        transition_type = CROSSFADE;
 
         locations = new ContentStore ();
         settings = new GLib.Settings ("org.gnome.clocks");
@@ -387,8 +385,6 @@ public class Face : Gtk.Stack, Clocks.Clock {
             return new Tile ((Item)item);
         });
 
-        content_view.set_header_bar (header_bar);
-
         load ();
         show_all ();
 
@@ -423,9 +419,15 @@ public class Face : Gtk.Stack, Clocks.Clock {
     [GtkCallback]
     private void visible_child_changed () {
         if (visible_child == empty_view || visible_child == content_view) {
-            header_bar.mode = HeaderBar.Mode.NORMAL;
+            view_mode = NORMAL;
+            button_mode = NEW;
+            can_select = true;
+            title = _("Clocks");
+            subtitle = null;
         } else if (visible_child == standalone) {
-            header_bar.mode = HeaderBar.Mode.STANDALONE;
+            view_mode = STANDALONE;
+            button_mode = BACK;
+            can_select = false;
         }
     }
 
@@ -442,6 +444,12 @@ public class Face : Gtk.Stack, Clocks.Clock {
         standalone_location = location;
         update_standalone ();
         visible_child = standalone;
+        if (standalone_location.state_name != null) {
+            title = "%s, %s".printf (standalone_location.city_name, standalone_location.state_name);
+        } else {
+            title = standalone_location.city_name;
+        }
+        subtitle = standalone_location.country_name;
     }
 
     private void load () {
@@ -513,7 +521,14 @@ public class Face : Gtk.Stack, Clocks.Clock {
 
     public void activate_back () {
         reset_view ();
-        button_mode = NEW;
+    }
+
+    public void activate_select () {
+        view_mode = SELECTION;
+    }
+
+    public void activate_select_cancel () {
+        view_mode = NORMAL;
     }
 
     public void activate_select_all () {
@@ -536,32 +551,6 @@ public class Face : Gtk.Stack, Clocks.Clock {
     public void reset_view () {
         standalone_location = null;
         visible_child = locations.get_n_items () == 0 ? empty_view : content_view;
-        request_header_bar_update ();
-    }
-
-    public void update_header_bar () {
-        switch (header_bar.mode) {
-        case HeaderBar.Mode.NORMAL:
-            header_bar.title = _("Clocks");
-            header_bar.subtitle = null;
-            content_view.update_header_bar ();
-            button_mode = NEW;
-            break;
-        case HeaderBar.Mode.SELECTION:
-            content_view.update_header_bar ();
-            break;
-        case HeaderBar.Mode.STANDALONE:
-            if (standalone_location.state_name != null) {
-                header_bar.title = "%s, %s".printf (standalone_location.city_name, 
standalone_location.state_name);
-            } else {
-                header_bar.title = standalone_location.city_name;
-            }
-            header_bar.subtitle = standalone_location.country_name;
-            button_mode = BACK;
-            break;
-        default:
-            assert_not_reached ();
-        }
     }
 }
 


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