[california/wip/725767-week] Basics are in place for switching between views



commit 18f12e925e136743403df203b922fc6acc68941a
Author: Jim Nelson <jim yorba org>
Date:   Thu May 1 19:10:02 2014 -0700

    Basics are in place for switching between views

 po/POTFILES.in                       |    2 +
 src/Makefile.am                      |    1 +
 src/calendar/calendar-date.vala      |   22 ++++++--
 src/calendar/calendar.vala           |   60 +++++++++++++------
 src/host/host-main-window.vala       |  103 ++++++++++++++++++++++++++-------
 src/view/month/month-controller.vala |   20 ++++++-
 src/view/view-container.vala         |   24 ++++++++
 src/view/view-controllable.vala      |   12 +++-
 src/view/week/week-controller.vala   |   55 ++++++++++++++----
 src/view/week/week-grid.vala         |   30 ++++++++++-
 10 files changed, 267 insertions(+), 62 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 53a58b3..aaac90f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -13,6 +13,8 @@ src/host/host-create-update-event.vala
 src/host/host-import-calendar.vala
 src/host/host-main-window.vala
 src/host/host-show-event.vala
+src/view/month/month-controller.vala
+src/view/week/week-controller.vala
 [type: gettext/glade]src/rc/activator-list.ui
 [type: gettext/glade]src/rc/app-menu.interface
 [type: gettext/glade]src/rc/calendar-import.ui
diff --git a/src/Makefile.am b/src/Makefile.am
index 62dcd01..5442690 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -124,6 +124,7 @@ california_VALASOURCES = \
        unit-test/unit-test-harness.vala \
        \
        view/view.vala \
+       view/view-container.vala \
        view/view-controllable.vala \
        \
        view/month/month.vala \
diff --git a/src/calendar/calendar-date.vala b/src/calendar/calendar-date.vala
index 5ba97ba..a2f1f6c 100644
--- a/src/calendar/calendar-date.vala
+++ b/src/calendar/calendar-date.vala
@@ -39,7 +39,11 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
          * Indicates that the localized string for "Today" should not be used if the date matches
          * { link System.today}.
          */
-        NO_TODAY
+        NO_TODAY,
+        /**
+         * Indicates the day of week should not be included.
+         */
+        NO_DAY_OF_WEEK
     }
     
     public DayOfWeek day_of_week { get; private set; }
@@ -303,15 +307,23 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
         bool abbrev = (flags & PrettyFlag.ABBREV) != 0;
         bool with_year = (flags & PrettyFlag.INCLUDE_YEAR) != 0;
         bool no_today = (flags & PrettyFlag.NO_TODAY) != 0;
+        bool no_dow = (flags & PrettyFlag.NO_DAY_OF_WEEK) != 0;
         
         if (!no_today && !with_year && equal_to(System.today))
             return _("Today");
         
         unowned string fmt;
-        if (abbrev)
-            fmt = with_year ? FMT_PRETTY_DATE_ABBREV : FMT_PRETTY_DATE_ABBREV_NO_YEAR;
-        else
-            fmt = with_year ? FMT_PRETTY_DATE : FMT_PRETTY_DATE_NO_YEAR;
+        if (abbrev) {
+            if (no_dow)
+                fmt = with_year ? FMT_PRETTY_DATE_ABBREV_NO_DOW : FMT_PRETTY_DATE_ABBREV_NO_DOW_NO_YEAR;
+            else
+                fmt = with_year ? FMT_PRETTY_DATE_ABBREV : FMT_PRETTY_DATE_ABBREV_NO_YEAR;
+        } else {
+            if (no_dow)
+                fmt = with_year ? FMT_PRETTY_DATE_NO_DOW : FMT_PRETTY_DATE_NO_DOW_NO_YEAR;
+            else
+                fmt = with_year ? FMT_PRETTY_DATE : FMT_PRETTY_DATE_NO_YEAR;
+        }
         
         return String.reduce_whitespace(format(fmt));
     }
diff --git a/src/calendar/calendar.vala b/src/calendar/calendar.vala
index b4edb9d..db3cc06 100644
--- a/src/calendar/calendar.vala
+++ b/src/calendar/calendar.vala
@@ -19,25 +19,29 @@ namespace California.Calendar {
 
 private int init_count = 0;
 
-private static unowned string FMT_MONTH_YEAR_FULL;
-private static unowned string FMT_MONTH_YEAR_ABBREV;
-private static unowned string FMT_MONTH_FULL;
-private static unowned string FMT_MONTH_ABBREV;
-private static unowned string FMT_DAY_OF_WEEK_FULL;
-private static unowned string FMT_DAY_OF_WEEK_ABBREV;
-private static unowned string FMT_FULL_DATE;
-private static unowned string FMT_PRETTY_DATE;
-private static unowned string FMT_PRETTY_DATE_NO_YEAR;
-private static unowned string FMT_PRETTY_DATE_ABBREV;
-private static unowned string FMT_PRETTY_DATE_ABBREV_NO_YEAR;
-private static unowned string FMT_AM;
-private static unowned string FMT_BRIEF_AM;
-private static unowned string FMT_PM;
-private static unowned string FMT_BRIEF_PM;
-private static unowned string FMT_12HOUR_MIN_MERIDIEM;
-private static unowned string FMT_12HOUR_MIN_SEC_MERIDIEM;
-private static unowned string FMT_24HOUR_MIN;
-private static unowned string FMT_24HOUR_MIN_SEC;
+private unowned string FMT_MONTH_YEAR_FULL;
+private unowned string FMT_MONTH_YEAR_ABBREV;
+private unowned string FMT_MONTH_FULL;
+private unowned string FMT_MONTH_ABBREV;
+private unowned string FMT_DAY_OF_WEEK_FULL;
+private unowned string FMT_DAY_OF_WEEK_ABBREV;
+private unowned string FMT_FULL_DATE;
+private unowned string FMT_PRETTY_DATE;
+private unowned string FMT_PRETTY_DATE_NO_YEAR;
+private unowned string FMT_PRETTY_DATE_ABBREV;
+private unowned string FMT_PRETTY_DATE_ABBREV_NO_YEAR;
+private unowned string FMT_PRETTY_DATE_NO_DOW;
+private unowned string FMT_PRETTY_DATE_ABBREV_NO_DOW;
+private unowned string FMT_PRETTY_DATE_NO_DOW_NO_YEAR;
+private unowned string FMT_PRETTY_DATE_ABBREV_NO_DOW_NO_YEAR;
+private unowned string FMT_AM;
+private unowned string FMT_BRIEF_AM;
+private unowned string FMT_PM;
+private unowned string FMT_BRIEF_PM;
+private unowned string FMT_12HOUR_MIN_MERIDIEM;
+private unowned string FMT_12HOUR_MIN_SEC_MERIDIEM;
+private unowned string FMT_24HOUR_MIN;
+private unowned string FMT_24HOUR_MIN_SEC;
 
 private unowned string MIDNIGHT;
 private unowned string NOON;
@@ -103,6 +107,24 @@ public void init() throws Error {
     /// See http://www.cplusplus.com/reference/ctime/strftime/ for format reference
     FMT_PRETTY_DATE_ABBREV_NO_YEAR = _("%a, %b %e");
     
+    // A "pretty" date with no day of week according to locale preferences, i.e. "March 10, 2014"
+    // See http://www.cplusplus.com/reference/ctime/strftime/ for format reference
+    FMT_PRETTY_DATE_NO_DOW = _("%B %e, %Y");
+    
+    // A "pretty" date abbreviated with no day of week according to locale preferences,
+    // i.e. "Mar 10, 2014"
+    // See http://www.cplusplus.com/reference/ctime/strftime/ for format reference
+    FMT_PRETTY_DATE_ABBREV_NO_DOW = _("%b %e, %Y");
+    
+    // A "pretty" date with no day of week or year according to locale preferences, i.e. "March 10"
+    // See http://www.cplusplus.com/reference/ctime/strftime/ for format reference
+    FMT_PRETTY_DATE_NO_DOW_NO_YEAR = _("%B %e");
+    
+    // A "pretty" date abbreviated with no day of week or year according to locale preferences,
+    // i.e. "Mar 10"
+    // See http://www.cplusplus.com/reference/ctime/strftime/ for format reference
+    FMT_PRETTY_DATE_ABBREV_NO_DOW_NO_YEAR = _("%b %e");
+    
     /// Ante meridiem
     /// (Please translate even if 24-hour clock used in your locale; this allows for GNOME time
     /// format user settings to be honored)
diff --git a/src/host/host-main-window.vala b/src/host/host-main-window.vala
index aa8459c..f5ffa29 100644
--- a/src/host/host-main-window.vala
+++ b/src/host/host-main-window.vala
@@ -35,9 +35,14 @@ public class MainWindow : Gtk.ApplicationWindow {
     // Set as a property so it can be bound to the current View.Controllable
     public Calendar.FirstOfWeek first_of_week { get; set; }
     
-    private View.Controllable current_view;
-    private View.Month.Controller month_view = new View.Month.Controller();
     private Gtk.Button quick_add_button;
+    private View.Controllable month_view = new View.Month.Controller();
+    private View.Controllable week_view = new View.Week.Controller();
+    private View.Controllable? current_controller = null;
+    private Gee.HashSet<Binding> current_bindings = new Gee.HashSet<Binding>();
+    private Gtk.Stack view_stack = new Gtk.Stack();
+    private Gtk.HeaderBar headerbar = new Gtk.HeaderBar();
+    private Gtk.Button today = new Gtk.Button.with_label(_("_Today"));
     
     public MainWindow(Application app) {
         Object (application: app);
@@ -55,11 +60,23 @@ public class MainWindow : Gtk.ApplicationWindow {
         Application.instance.add_accelerator(rtl ? ACCEL_PREVIOUS : ACCEL_NEXT, ACTION_NEXT, null);
         Application.instance.add_accelerator(rtl ? ACCEL_NEXT : ACCEL_PREVIOUS, ACTION_PREVIOUS, null);
         
+        // view stack settings
+        view_stack.homogeneous = true;
+        view_stack.transition_duration = 300;
+        view_stack.transition_type = Gtk.StackTransitionType.SLIDE_UP_DOWN;
+        
+        // add views to view stack
+        add_controller(month_view);
+        add_controller(week_view);
+        
+        // subscribe after adding so next set_visible_child_name() is first initialization
+        view_stack.notify["visible-child"].connect(on_view_changed);
+        
         // start in Month view
-        current_view = month_view;
+        view_stack.set_visible_child_name(month_view.title);
         
-        // create GtkHeaderBar and pack it in
-        Gtk.HeaderBar headerbar = new Gtk.HeaderBar();
+        // if not on Unity, use headerbar as the titlebar (removes window chrome) and provide close
+        // button for users who might have trouble finding it otherwise
 #if !ENABLE_UNITY
         // Unity doesn't support GtkHeaderBar-as-title-bar very well yet; when set, the main
         // window can't be resized no matter what additional GtkWindow properties are set
@@ -67,7 +84,6 @@ public class MainWindow : Gtk.ApplicationWindow {
         set_titlebar(headerbar);
 #endif
         
-        Gtk.Button today = new Gtk.Button.with_label(_("_Today"));
         today.use_underline = true;
         today.tooltip_text = _("Jump to today's date (Ctrl+T)");
         today.set_action_name(ACTION_JUMP_TO_TODAY);
@@ -88,9 +104,15 @@ public class MainWindow : Gtk.ApplicationWindow {
         nav_buttons.pack_start(prev);
         nav_buttons.pack_end(next);
         
+        Gtk.StackSwitcher view_switcher = new Gtk.StackSwitcher();
+        view_switcher.stack = view_stack;
+        view_switcher.get_style_context().add_class(Gtk.STYLE_CLASS_LINKED);
+        view_switcher.get_style_context().add_class(Gtk.STYLE_CLASS_RAISED);
+        
         // pack left-side of window
         headerbar.pack_start(today);
         headerbar.pack_start(nav_buttons);
+        headerbar.pack_start(view_switcher);
         
         quick_add_button = new Gtk.Button.from_icon_name("list-add-symbolic", Gtk.IconSize.MENU);
         quick_add_button.tooltip_text = _("Quick add event (Ctrl+N)");
@@ -106,32 +128,69 @@ public class MainWindow : Gtk.ApplicationWindow {
         headerbar.pack_end(calendars);
         
         Gtk.Box layout = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
+        // if on Unity, since headerbar is not the titlebar, need to pack it like any other widget
 #if ENABLE_UNITY
         layout.pack_start(headerbar, false, true, 0);
 #endif
-        layout.pack_end(month_view.get_container(), true, true, 0);
-        
-        // current host bindings and signals
-        current_view.request_create_timed_event.connect(on_request_create_timed_event);
-        current_view.request_create_all_day_event.connect(on_request_create_all_day_event);
-        current_view.request_display_event.connect(on_request_display_event);
-        current_view.bind_property(View.Controllable.PROP_CURRENT_LABEL, headerbar, "title",
-            BindingFlags.SYNC_CREATE);
-        current_view.bind_property(View.Controllable.PROP_IS_VIEWING_TODAY, today, "sensitive",
-            BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
-        current_view.bind_property(View.Controllable.PROP_FIRST_OF_WEEK, this, PROP_FIRST_OF_WEEK,
-            BindingFlags.BIDIRECTIONAL);
+        layout.pack_end(view_stack, true, true, 0);
         
         add(layout);
     }
     
+    private void add_controller(View.Controllable controller) {
+        view_stack.add_titled(controller.get_container(), controller.title, controller.title);
+        controller.get_container().show_all();
+    }
+    
+    private unowned View.Container? current_view_container() {
+        return (View.Container?) view_stack.get_visible_child();
+    }
+    
+    private void on_view_changed() {
+        View.Container? view_container = current_view_container();
+        if (view_container != null && view_container.owner == current_controller)
+            return;
+        
+        if (current_controller != null) {
+            // signals
+            current_controller.request_create_timed_event.disconnect(on_request_create_timed_event);
+            current_controller.request_create_all_day_event.disconnect(on_request_create_all_day_event);
+            current_controller.request_display_event.disconnect(on_request_display_event);
+            
+            // clear bindings to unbind all of them
+            current_bindings.clear();
+        }
+        
+        if (view_container != null) {
+            current_controller = view_container.owner;
+            
+            // signals
+            current_controller.request_create_timed_event.disconnect(on_request_create_timed_event);
+            current_controller.request_create_all_day_event.disconnect(on_request_create_all_day_event);
+            current_controller.request_display_event.disconnect(on_request_display_event);
+            
+            // bindings
+            Binding binding = current_controller.bind_property(View.Controllable.PROP_CURRENT_LABEL,
+                headerbar, "title", BindingFlags.SYNC_CREATE);
+            current_bindings.add(binding);
+            
+            binding = current_controller.bind_property(View.Controllable.PROP_IS_VIEWING_TODAY, today,
+                "sensitive", BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN);
+            current_bindings.add(binding);
+            
+            binding = current_controller.bind_property(View.Controllable.PROP_FIRST_OF_WEEK, this,
+                PROP_FIRST_OF_WEEK, BindingFlags.BIDIRECTIONAL);
+            current_bindings.add(binding);
+        }
+    }
+    
     private void show_deck(Gtk.Widget relative_to, Gdk.Point? for_location, Toolkit.Deck deck) {
         Toolkit.DeckWindow deck_window = new Toolkit.DeckWindow(this, deck);
         
         // when the dialog closes, reset View.Controllable state (selection is maintained while
         // use is viewing/editing interaction) and destroy widgets
         deck_window.deck.dismiss.connect(() => {
-            current_view.unselect_all();
+            current_controller.unselect_all();
             deck_window.hide();
             // give the dialog a change to hide before allowing other signals to fire, which may
             // invoke another dialog (prevents multiple dialogs on screen at same time)
@@ -163,15 +222,15 @@ public class MainWindow : Gtk.ApplicationWindow {
     }
     
     private void on_jump_to_today() {
-        current_view.today();
+        current_controller.today();
     }
     
     private void on_next() {
-        current_view.next();
+        current_controller.next();
     }
     
     private void on_previous() {
-        current_view.prev();
+        current_controller.previous();
     }
     
     private void on_request_create_timed_event(Calendar.ExactTimeSpan initial, Gtk.Widget relative_to,
diff --git a/src/view/month/month-controller.vala b/src/view/month/month-controller.vala
index 7197655..918bfe0 100644
--- a/src/view/month/month-controller.vala
+++ b/src/view/month/month-controller.vala
@@ -24,6 +24,16 @@ public class Controller : BaseObject, View.Controllable {
     // even number, as it is halved to determine neighboring months depths
     private const int CACHE_NEIGHBORS_COUNT = 4;
     
+    // MasterGrid holds the day of week labels and Month.Cells
+    private class MasterGrid : Gtk.Grid, View.Container {
+        private Controller _owner;
+        public unowned View.Controllable owner { get { return _owner; } }
+        
+        public MasterGrid(Controller owner) {
+            _owner = owner;
+        }
+    }
+    
     /**
      * The month and year being displayed.
      *
@@ -44,6 +54,11 @@ public class Controller : BaseObject, View.Controllable {
     /**
      * @inheritDoc
      */
+    public string title { get { return _("Month"); } }
+    
+    /**
+     * @inheritDoc
+     */
     public string current_label { get; protected set; }
     
     /**
@@ -56,11 +71,12 @@ public class Controller : BaseObject, View.Controllable {
      */
     public Calendar.Date default_date { get; protected set; }
     
-    private Gtk.Grid master_grid = new Gtk.Grid();
+    private MasterGrid master_grid;
     private Gtk.Stack stack = new Gtk.Stack();
     private Gee.HashMap<Calendar.MonthOfYear, Grid> month_grids = new Gee.HashMap<Calendar.MonthOfYear, 
Grid>();
     
     public Controller() {
+        master_grid = new MasterGrid(this);
         master_grid.column_homogeneous = true;
         master_grid.column_spacing = 0;
         master_grid.row_homogeneous = false;
@@ -188,7 +204,7 @@ public class Controller : BaseObject, View.Controllable {
     /**
      * @inheritDoc
      */
-    public Gtk.Widget get_container() {
+    public View.Container get_container() {
         return master_grid;
     }
     
diff --git a/src/view/view-container.vala b/src/view/view-container.vala
new file mode 100644
index 0000000..137338a
--- /dev/null
+++ b/src/view/view-container.vala
@@ -0,0 +1,24 @@
+/* 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.View {
+
+/**
+ * A Gtk.Widget returned by { link Controllable} that acts as the container for the entire view.
+ *
+ * As tempting as it is to make this interface depend on Gtk.Container, we'll leave this fairly
+ * generic for now.
+ */
+
+public interface Container : Gtk.Widget {
+    /**
+     * The { link Controllable} that owns this { link Container}.
+     */
+    public abstract unowned Controllable owner { get; }
+}
+
+}
+
diff --git a/src/view/view-controllable.vala b/src/view/view-controllable.vala
index 4bae0b6..c95f9d8 100644
--- a/src/view/view-controllable.vala
+++ b/src/view/view-controllable.vala
@@ -21,6 +21,11 @@ public interface Controllable : Object {
     public const string PROP_FIRST_OF_WEEK = "first-of-week";
     
     /**
+     * A user-visible string (short) representing this view.
+     */
+    public abstract string title { get; }
+    
+    /**
      * A user-visible string representing the current calendar view.
      */
     public abstract string current_label { get; protected set; }
@@ -60,10 +65,13 @@ public interface Controllable : Object {
         Gdk.Point? for_location);
     
     /**
-     * Returns the Gtk.Widget container that should be used to display the { link Controllable}'s
+     * Returns the { link Container} that should be used to display the { link Controllable}'s
      * contents.
+     *
+     * This should not return a new Gtk.Widget each time, rather it returns the Widget the
+     * Controllable is maintaining the current view(s) in.
      */
-    public abstract Gtk.Widget get_container();
+    public abstract View.Container get_container();
     
     /**
      * Move forward one calendar unit.
diff --git a/src/view/week/week-controller.vala b/src/view/week/week-controller.vala
index 2a41e8a..e61d599 100644
--- a/src/view/week/week-controller.vala
+++ b/src/view/week/week-controller.vala
@@ -13,6 +13,15 @@ namespace California.View.Week {
 public class Controller : BaseObject, View.Controllable {
     public const string PROP_WEEK = "week";
     
+    private class MasterStack : Gtk.Stack, View.Container {
+        private Controller _owner;
+        public unowned View.Controllable owner { get { return _owner; } }
+        
+        public MasterStack(Controller owner) {
+            _owner = owner;
+        }
+    }
+    
     /**
      * The current week of the year being displayed.
      */
@@ -21,6 +30,11 @@ public class Controller : BaseObject, View.Controllable {
     /**
      * @inheritDoc
      */
+    public string title { get { return _("Week"); } }
+    
+    /**
+     * @inheritDoc
+     */
     public string current_label { get; protected set; }
     
     /**
@@ -33,22 +47,30 @@ public class Controller : BaseObject, View.Controllable {
      */
     public Calendar.FirstOfWeek first_of_week { get; set; }
     
-    private Gtk.Stack stack = new Gtk.Stack();
+    private MasterStack stack;
     
     public Controller() {
+        stack = new MasterStack(this);
+        stack.homogeneous = true;
+        stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;
+        stack.transition_duration = 300;
+        
+        // set this before signal handlers are in place (week and first_of_week are very closely
+        // tied in this view)
+        first_of_week = Calendar.FirstOfWeek.SUNDAY;
+        
         // changing these properties drives a lot of the what the view displays
         notify[View.Controllable.PROP_FIRST_OF_WEEK].connect(on_first_of_week_changed);
         notify[PROP_WEEK].connect(on_week_changed);
         
-        // set these now that signal handlers are in place
-        first_of_week = Calendar.FirstOfWeek.SUNDAY;
+        // set this now that signal handlers are in place
         week = Calendar.System.today.week_of(first_of_week);
     }
     
     /**
      * @inheritDoc
      */
-    public Gtk.Widget get_container() {
+    public View.Container get_container() {
         return stack;
     }
     
@@ -56,21 +78,23 @@ public class Controller : BaseObject, View.Controllable {
      * @inheritDoc
      */
     public void next() {
-        week = week.next();
+        week = week.adjust(1);
     }
     
     /**
      * @inheritDoc
      */
     public void previous() {
-        week = week.previous();
+        week = week.adjust(-1);
     }
     
     /**
      * @inheritDoc
      */
     public void today() {
-        week = Calendar.System.today.week_of(first_of_week);
+        Calendar.Week this_week = Calendar.System.today.week_of(first_of_week);
+        if (!week.equal_to(this_week))
+            week = this_week;
     }
     
     /**
@@ -80,24 +104,33 @@ public class Controller : BaseObject, View.Controllable {
     }
     
     private void on_first_of_week_changed() {
-        // update week to reflect this change
-        week = week.start_date.week_of(first_of_week);
+        // update week to reflect this change, but only if necessary
+        if (first_of_week != week.first_of_week)
+            week = week.start_date.week_of(first_of_week);
     }
     
     private void on_week_changed() {
         // current_label is Start Date - End Date, Year, unless bounding two years, in which case
         // Start Date, Year - End Date, Year
-        Calendar.Date.PrettyFlag start_flags = Calendar.Date.PrettyFlag.ABBREV;
+        Calendar.Date.PrettyFlag start_flags =
+            Calendar.Date.PrettyFlag.ABBREV | Calendar.Date.PrettyFlag.NO_DAY_OF_WEEK;
         if (!week.start_date.year.equal_to(week.end_date.year))
             start_flags |= Calendar.Date.PrettyFlag.INCLUDE_YEAR;
         Calendar.Date.PrettyFlag end_flags =
-            Calendar.Date.PrettyFlag.ABBREV | Calendar.Date.PrettyFlag.INCLUDE_YEAR;
+            Calendar.Date.PrettyFlag.ABBREV | Calendar.Date.PrettyFlag.INCLUDE_YEAR
+            | Calendar.Date.PrettyFlag.NO_DAY_OF_WEEK;
         
         // date formatting: "<Start Date> to <End Date>"
         current_label = _("%s to %s").printf(week.start_date.to_pretty_string(start_flags),
             week.end_date.to_pretty_string(end_flags));
         
         is_viewing_today = Calendar.System.today in week;
+        
+        Grid week_grid = new Grid(week);
+        week_grid.show_all();
+        
+        stack.add_named(week_grid, week_grid.id);
+        stack.set_visible_child(week_grid);
     }
     
     public override string to_string() {
diff --git a/src/view/week/week-grid.vala b/src/view/week/week-grid.vala
index 77c7eb4..dd82b8a 100644
--- a/src/view/week/week-grid.vala
+++ b/src/view/week/week-grid.vala
@@ -10,7 +10,7 @@ namespace California.View.Week {
  * A Gtk.Grid that holds the various { link Pane}s for each day of thw week.
  */
 
-public class Grid : Gtk.Grid {
+internal class Grid : Gtk.Grid {
     public const string PROP_WEEK = "week";
     
     /**
@@ -18,8 +18,36 @@ public class Grid : Gtk.Grid {
      */
     public Calendar.Week week { get; private set; }
     
+    /**
+     * Name (id) of { link Grid}.
+     *
+     * This is for use in a Gtk.Stack.
+     */
+    public string id { owned get { return week.to_string(); } }
+    
     public Grid(Calendar.Week week) {
         this.week = week;
+        
+        column_homogeneous = true;
+        column_spacing = 0;
+        row_homogeneous = false;
+        row_spacing = 0;
+        
+        // date labels across the top, week panes extending across the bottom
+        int col = 0;
+        foreach (Calendar.Date date in week) {
+            Gtk.Label date_label = new Gtk.Label("%s %d/%d".printf(date.day_of_week.abbrev_name,
+                date.month_of_year().month.value, date.day_of_month.value));
+            date_label.margin_top = 2;
+            date_label.margin_bottom = 2;
+            attach(date_label, col, 0, 1, 1);
+            
+            Gtk.DrawingArea pane = new Gtk.DrawingArea();
+            pane.expand = true;
+            attach(pane, col, 1, 1, 1);
+            
+            col++;
+        }
     }
 }
 


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