[california/wip/725786-edit-recurring] Use new Toolkit.RotatingButtonBox for create/update dialog



commit c3ad6d22dddf24a7b26706de994827ed31f15d17
Author: Jim Nelson <jim yorba org>
Date:   Fri Jul 11 15:03:29 2014 -0700

    Use new Toolkit.RotatingButtonBox for create/update dialog
    
    Gtk.Revealer trick too difficult to get right.  This does it right,
    using Gtk.Stack to slide Gtk.ButtonBoxes into place.  Can't use
    Glade because no Gtk.Stack support there.

 src/Makefile.am                              |    1 +
 src/host/host-create-update-event.vala       |   65 +++++++++++++++++--
 src/rc/create-update-event.ui                |   47 +------------
 src/toolkit/toolkit-rotating-button-box.vala |   89 ++++++++++++++++++++++++++
 4 files changed, 154 insertions(+), 48 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e304026..c404850 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -127,6 +127,7 @@ california_VALASOURCES = \
        toolkit/toolkit-motion-event.vala \
        toolkit/toolkit-mutable-widget.vala \
        toolkit/toolkit-popup.vala \
+       toolkit/toolkit-rotating-button-box.vala \
        toolkit/toolkit-stack-model.vala \
        \
        util/util.vala \
diff --git a/src/host/host-create-update-event.vala b/src/host/host-create-update-event.vala
index 5989d2b..095e693 100644
--- a/src/host/host-create-update-event.vala
+++ b/src/host/host-create-update-event.vala
@@ -20,6 +20,9 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
     private const int END_HOUR = 23;
     private const int MIN_DIVISIONS = 15;
     
+    private const string FAMILY_NORMAL = "normal";
+    private const string FAMILY_RECURRING = "recurring";
+    
     public string card_id { get { return ID; } }
     
     public string? title { get { return null; } }
@@ -56,7 +59,7 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
     private Gtk.ComboBoxText calendar_combo;
     
     [GtkChild]
-    private Gtk.Button accept_button;
+    private Gtk.Box rotating_button_box_container;
     
     public Calendar.DateSpan selected_date_span { get; set; }
     
@@ -69,6 +72,14 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
     private Gtk.Button? last_date_button_touched = null;
     private bool both_date_buttons_touched = false;
     
+    private Toolkit.RotatingButtonBox rotating_button_box = new Toolkit.RotatingButtonBox();
+    
+    private Gtk.Button accept_button = new Gtk.Button();
+    private Gtk.Button cancel_button = new Gtk.Button.with_mnemonic(_("_Cancel"));
+    private Gtk.Button update_all_button = new Gtk.Button.with_mnemonic(_("Update A_ll Events"));
+    private Gtk.Button update_this_button = new Gtk.Button.with_mnemonic(_("Update _This Event"));
+    private Gtk.Button cancel_recurring_button = new Gtk.Button.with_mnemonic(_("_Cancel"));
+    
     public CreateUpdateEvent() {
         // when selected_date_span updates, update date buttons as well
         notify[PROP_SELECTED_DATE_SPAN].connect(() => {
@@ -101,6 +112,31 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
             calendar_model.add(calendar_source);
         }
         
+        accept_button.get_style_context().add_class("suggested-action");
+        
+        accept_button.clicked.connect(on_accept_button_clicked);
+        cancel_button.clicked.connect(on_cancel_button_clicked);
+        update_all_button.clicked.connect(on_update_all_button_clicked);
+        update_this_button.clicked.connect(on_update_this_button_clicked);
+        cancel_recurring_button.clicked.connect(on_cancel_recurring_button_clicked);
+        
+        rotating_button_box.pack_end(FAMILY_NORMAL, cancel_button);
+        rotating_button_box.pack_end(FAMILY_NORMAL, accept_button);
+        
+        rotating_button_box.pack_end(FAMILY_RECURRING, cancel_recurring_button);
+        rotating_button_box.pack_end(FAMILY_RECURRING, update_all_button);
+        rotating_button_box.pack_end(FAMILY_RECURRING, update_this_button);
+        
+        // The cancel-recurring-update button looks big compared to other buttons, so allow for the
+        // ButtonBox to reduce it in size
+        
rotating_button_box.get_family_container(FAMILY_RECURRING).child_set_property(cancel_recurring_button,
+            "non-homogeneous", true);
+        
+        rotating_button_box.expand = true;
+        rotating_button_box.halign = Gtk.Align.FILL;
+        rotating_button_box.valign = Gtk.Align.END;
+        rotating_button_box_container.add(rotating_button_box);
+        
         update_controls();
     }
     
@@ -193,6 +229,10 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
         description_textview.buffer.text = event.description ?? "";
         
         accept_button.label = is_update ? _("_Update") : _("C_reate");
+        accept_button.use_underline = true;
+        
+        rotating_button_box.family = FAMILY_NORMAL;
+        
         original_calendar_source = event.calendar_source;
     }
     
@@ -238,11 +278,17 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
         jump_to_card_by_name(CreateUpdateRecurring.ID, event);
     }
     
-    [GtkCallback]
-    private void on_accept_clicked() {
+    private void on_accept_button_clicked() {
         if (calendar_model.active == null)
             return;
         
+        // if updating a recurring event, need to ask about update scope
+        if (event.is_recurring_instance && is_update) {
+            rotating_button_box.family = FAMILY_RECURRING;
+            
+            return;
+        }
+        
         event.calendar_source = calendar_model.active;
         event.summary = summary_entry.text;
         event.location = location_entry.text;
@@ -271,9 +317,18 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
             create_event_async.begin(null);
     }
     
-    [GtkCallback]
     private void on_cancel_button_clicked() {
-        jump_home_or_user_closed();
+        notify_user_closed();
+    }
+    
+    private void on_update_all_button_clicked() {
+    }
+    
+    private void on_update_this_button_clicked() {
+    }
+    
+    private void on_cancel_recurring_button_clicked() {
+        rotating_button_box.family = FAMILY_NORMAL;
     }
     
     private async void create_event_async(Cancellable? cancellable) {
diff --git a/src/rc/create-update-event.ui b/src/rc/create-update-event.ui
index 885be53..92b2637 100644
--- a/src/rc/create-update-event.ui
+++ b/src/rc/create-update-event.ui
@@ -268,53 +268,14 @@
       </packing>
     </child>
     <child>
-      <object class="GtkButtonBox" id="button_box">
+      <object class="GtkBox" id="rotating_button_box_container">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="valign">end</property>
         <property name="margin_top">8</property>
-        <property name="vexpand">True</property>
-        <property name="spacing">6</property>
-        <property name="homogeneous">True</property>
-        <property name="layout_style">end</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">False</property>
         <child>
-          <object class="GtkButton" id="cancel_button">
-            <property name="label" translatable="yes">_Cancel</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="can_default">True</property>
-            <property name="receives_default">True</property>
-            <property name="use_underline">True</property>
-            <property name="image_position">bottom</property>
-            <signal name="clicked" handler="on_cancel_button_clicked" 
object="CaliforniaHostCreateUpdateEvent" swapped="no"/>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkButton" id="accept_button">
-            <property name="label" translatable="yes">C_reate</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="can_default">True</property>
-            <property name="has_default">True</property>
-            <property name="receives_default">True</property>
-            <property name="use_underline">True</property>
-            <property name="image_position">bottom</property>
-            <signal name="clicked" handler="on_accept_clicked" object="CaliforniaHostCreateUpdateEvent" 
swapped="no"/>
-            <style>
-              <class name="suggested-action"/>
-            </style>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="pack_type">end</property>
-            <property name="position">1</property>
-          </packing>
+          <placeholder/>
         </child>
       </object>
       <packing>
diff --git a/src/toolkit/toolkit-rotating-button-box.vala b/src/toolkit/toolkit-rotating-button-box.vala
new file mode 100644
index 0000000..13778f7
--- /dev/null
+++ b/src/toolkit/toolkit-rotating-button-box.vala
@@ -0,0 +1,89 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+namespace California.Toolkit {
+
+/**
+ * RotatingButtonBox is a specialty widget for displaying groups ("families") of buttons, with each
+ * family silding (rotating) into view when required.
+ *
+ * Each family of Gtk.Buttons are held in Gtk.ButtonBoxes.  They are always laid out horizontally
+ * with an END layout style and fixed spacing.  This widget is designed specifically for buttons
+ * which populate the bottom edge of a dialog or popover.
+ *
+ * Families are created on-demand.  The direction of them sliding into view is determined by the
+ * order they are created, i.e. the first family created is to the "left" of subsequent families.
+ *
+ * Families are described by a string name.  Family names are case-sensitive.
+ */
+
+public class RotatingButtonBox : Gtk.Stack {
+    public const string PROP_FAMILY = "family";
+    
+    public Gtk.Orientation ORIENTATION = Gtk.Orientation.HORIZONTAL;
+    public Gtk.ButtonBoxStyle LAYOUT_STYLE = Gtk.ButtonBoxStyle.END;
+    public int SPACING = 8;
+    
+    /**
+     * The family name currently visible.
+     */
+    public string? family { get; set; }
+    
+    private Gee.HashMap<string, Gtk.ButtonBox> button_boxes = new Gee.HashMap<string, Gtk.ButtonBox>();
+    
+    public RotatingButtonBox() {
+        homogeneous = true;
+        transition_duration = SLOW_STACK_TRANSITION_DURATION_MSEC;
+        transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;
+        
+        bind_property("visible-child-name", this, PROP_FAMILY,
+            BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+    }
+    
+    /**
+     * Pack a Gtk.Button at the start of a particular family, creating the family if necessary.
+     *
+     * See Gtk.Box.pack_start().
+     */
+    public void pack_start(string family, Gtk.Button button) {
+        get_family_container(family).pack_start(button);
+    }
+    
+    /**
+     * Pack a Gtk.Button at the end of a particular family, creating the family if necessary.
+     *
+     * See Gtk.Box.pack_end().
+     */
+    public void pack_end(string family, Gtk.Button button) {
+        get_family_container(family).pack_end(button);
+    }
+    
+    /**
+     * Direct access to the Gtk.ButtonBox holding the named family.
+     *
+     * If the family doesn't exist, it will be created.
+     */
+    public Gtk.ButtonBox get_family_container(string family) {
+        if (button_boxes.has_key(family))
+            return button_boxes.get(family);
+        
+        // create new family of buttons
+        Gtk.ButtonBox button_box = new Gtk.ButtonBox(ORIENTATION);
+        button_box.layout_style = LAYOUT_STYLE;
+        button_box.spacing = SPACING;
+        
+        // add to internal lookup
+        button_boxes.set(family, button_box);
+        
+        // add to Gtk.Stack using the family name
+        add_named(button_box, family);
+        
+        return button_box;
+    }
+}
+
+}
+


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