[gnome-calendar] event-widget: use a stack to handle orientation



commit ea8b9e76e7fbd4ec197938052447178efb78c7fb
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Nov 25 11:42:47 2017 -0200

    event-widget: use a stack to handle orientation
    
    Instead of setting the position of the labels in a grid,
    use two different grids and switch between them using a
    stack.

 data/ui/event-widget.ui | 127 +++++++++++++++++++++++++----------------------
 src/gcal-event-widget.c | 128 ++++++++++++++++++++++++++----------------------
 2 files changed, 139 insertions(+), 116 deletions(-)
---
diff --git a/data/ui/event-widget.ui b/data/ui/event-widget.ui
index 58f0142..8eb78c9 100644
--- a/data/ui/event-widget.ui
+++ b/data/ui/event-widget.ui
@@ -2,85 +2,96 @@
 <interface>
   <template class="GcalEventWidget" parent="GtkBin">
     <child>
-      <object class="GtkGrid" id="main_grid">
+      <object class="GtkStack" id="stack">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="column_spacing">4</property>
+        <property name="hexpand">False</property>
         <property name="margin-top">1</property>
         <property name="margin-bottom">1</property>
         <property name="margin-start">6</property>
         <property name="margin-end">4</property>
-        <property name="hexpand">False</property>
+        <property name="homogeneous">false</property>
+
+        <!-- Horizontal page -->
         <child>
-          <object class="GtkLabel" id="hour_label">
+          <object class="GtkGrid" id="horizontal_grid">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="xalign">0.0</property>
-            <attributes>
-              <attribute name="weight" value="semibold"/>
-            </attributes>
+            <property name="column_spacing">4</property>
+            <child>
+              <object class="GtkLabel"  id="summary_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="xalign">0.0</property>
+                <property name="ellipsize">end</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="hour_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <style>
+                  <class name="dim-label" />
+                </style>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
           </object>
           <packing>
-            <property name="left_attach">0</property>
-            <property name="top_attach">0</property>
+            <property name="name">horizontal</property>
           </packing>
         </child>
+
+        <!-- Vertical page -->
         <child>
-          <object class="GtkLabel"  id="summary_label">
+          <object class="GtkGrid" id="vertical_grid">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="hexpand">True</property>
-            <property name="xalign">0</property>
-            <property name="ellipsize">end</property>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" bind-source="hour_label" bind-property="label" bind-flags="default" />
+                <property name="xalign">0.0</property>
+                <style>
+                  <class name="dim-label" />
+                </style>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" bind-source="summary_label" bind-property="label" 
bind-flags="default" />
+                <property name="wrap">True</property>
+                <property name="hexpand">True</property>
+                <property name="xalign">0.0</property>
+                <property name="ellipsize">end</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
           </object>
           <packing>
-            <property name="left_attach">1</property>
-            <property name="top_attach">0</property>
+            <property name="name">vertical</property>
           </packing>
         </child>
-      </object>
-    </child>
-  </template>
 
-  <!-- HACK!!!
-       We need this ghost GtkGrid because we can't change the position of the
-       labels in size-allocate. This grid will simulate the main grid with the
-       labels vertically positioned, so we don't need to chage the main grid's
-       label position in size-allocate -->
-  <object class="GtkGrid" id="ghost_grid">
-    <property name="visible">True</property>
-    <property name="column_spacing">4</property>
-    <property name="margin-top">1</property>
-    <property name="margin-bottom">1</property>
-    <property name="margin-start">6</property>
-    <property name="margin-end">4</property>
-    <child>
-      <object class="GtkLabel">
-        <property name="visible">True</property>
-        <property name="label" bind-source="hour_label" bind-property="label" bind-flags="default" />
-        <property name="can_focus">False</property>
-        <property name="xalign">0.0</property>
-        <attributes>
-          <attribute name="weight" value="semibold"/>
-        </attributes>
-      </object>
-      <packing>
-        <property name="left_attach">0</property>
-        <property name="top_attach">0</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkLabel">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="label" bind-source="summary_label" bind-property="label" bind-flags="default" />
-        <property name="hexpand">True</property>
-        <property name="xalign">0</property>
-        <property name="ellipsize">end</property>
       </object>
-      <packing>
-        <property name="top_attach">1</property>
-      </packing>
     </child>
-  </object>
+  </template>
 </interface>
diff --git a/src/gcal-event-widget.c b/src/gcal-event-widget.c
index 22c30b8..b4f2ffd 100644
--- a/src/gcal-event-widget.c
+++ b/src/gcal-event-widget.c
@@ -38,10 +38,11 @@ struct _GcalEventWidget
   GDateTime          *dt_end;
 
   /* widgets */
-  GtkWidget          *ghost_grid;
+  GtkWidget          *horizontal_grid;
   GtkWidget          *hour_label;
-  GtkWidget          *main_grid;
+  GtkWidget          *stack;
   GtkWidget          *summary_label;
+  GtkWidget          *vertical_grid;
 
   /* internal data */
   gboolean            clock_format_24h : 1;
@@ -54,7 +55,10 @@ struct _GcalEventWidget
 
   GtkOrientation      orientation;
 
-  guint               toggle_description_id;
+  guint               vertical_label_source_id;
+  gboolean            vertical_value_to_set;
+  gboolean            vertical_labels;
+
   gboolean            button_pressed;
 };
 
@@ -74,8 +78,6 @@ enum
   NUM_SIGNALS
 };
 
-
-
 typedef enum
 {
   CURSOR_NONE,
@@ -93,37 +95,53 @@ G_DEFINE_TYPE_WITH_CODE (GcalEventWidget, gcal_event_widget, GTK_TYPE_BIN,
  */
 
 static gboolean
-toggle_description_position_cb (GcalEventWidget *self)
+can_hold_vertical_labels_with_height (GcalEventWidget *self,
+                                      gint             height)
 {
-  gint current_top;
+  gint total_height;
 
-  gtk_container_child_get (GTK_CONTAINER (self->main_grid),
-                           self->summary_label,
-                           "top-attach", &current_top,
-                           NULL);
+  gtk_widget_get_preferred_height (self->vertical_grid, &total_height, NULL);
 
-  gtk_label_set_line_wrap (GTK_LABEL (self->summary_label),
-                           !gtk_label_get_line_wrap (GTK_LABEL (self->summary_label)));
+  return height >= total_height;
+}
 
-  gtk_container_child_set (GTK_CONTAINER (self->main_grid),
-                           self->summary_label,
-                           "left-attach", current_top == 1 ? 1 : 0,
-                           "top-attach", current_top == 1 ? 0 : 1,
-                           "width", current_top == 1 ? 1 : 2,
-                           NULL);
+static void
+set_vertical_labels (GcalEventWidget *self,
+                     gboolean         vertical)
+{
+  if (self->vertical_labels == vertical)
+    return;
 
-  self->toggle_description_id = 0;
+  gtk_stack_set_visible_child (GTK_STACK (self->stack), vertical ? self->vertical_grid : 
self->horizontal_grid);
+  self->vertical_labels = vertical;
+}
 
+static gboolean
+set_vertical_labels_in_idle_cb (gpointer data)
+{
+  GcalEventWidget *self = (GcalEventWidget*) data;
+
+  set_vertical_labels (self, self->vertical_value_to_set);
+
+  self->vertical_label_source_id = 0;
   return G_SOURCE_REMOVE;
 }
 
 static void
-queue_toggle_description_position (GcalEventWidget *self)
+queue_set_vertical_labels (GcalEventWidget *self,
+                           gboolean         vertical)
 {
-  if (self->toggle_description_id > 0)
-    g_source_remove (self->toggle_description_id);
+  if (self->vertical_label_source_id > 0)
+    {
+      g_source_remove (self->vertical_label_source_id);
+      self->vertical_label_source_id = 0;
+    }
 
-  self->toggle_description_id = g_idle_add ((GSourceFunc) toggle_description_position_cb, self);
+  if (self->vertical_labels == vertical)
+    return;
+
+  self->vertical_value_to_set = vertical;
+  self->vertical_label_source_id = g_idle_add (set_vertical_labels_in_idle_cb, self);
 }
 
 static void
@@ -153,7 +171,8 @@ static void
 gcal_event_widget_update_style (GcalEventWidget *self)
 {
   GtkStyleContext *context;
-  gboolean slanted_start, slanted_end;
+  gboolean slanted_start;
+  gboolean slanted_end;
 
   context = gtk_widget_get_style_context (GTK_WIDGET (self));
   slanted_start = FALSE;
@@ -183,8 +202,8 @@ gcal_event_widget_update_style (GcalEventWidget *self)
     gtk_style_context_add_class (context, "slanted-end");
 
   /* TODO: adjust margins based on the CSS gradients sizes, not hardcoded */
-  gtk_widget_set_margin_start (self->main_grid, slanted_start ? 20 : 4);
-  gtk_widget_set_margin_end (self->main_grid, slanted_end ? 20 : 4);
+  gtk_widget_set_margin_start (self->stack, slanted_start ? 20 : 4);
+  gtk_widget_set_margin_end (self->stack, slanted_end ? 20 : 4);
 
   /* Add style classes for orientation selectors */
   if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
@@ -212,7 +231,7 @@ gcal_event_widget_update_style (GcalEventWidget *self)
 
       /* XXX: hardcoding these values isn't really great... */
       if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
-        gtk_widget_set_margin_start (self->main_grid, 8);
+        gtk_widget_set_margin_start (self->stack, 8);
     }
 }
 
@@ -546,9 +565,12 @@ gcal_event_widget_size_allocate (GtkWidget     *widget,
                                  GtkAllocation *allocation)
 {
   GcalEventWidget *self;
+  GtkAllocation old_allocation;
 
   self = GCAL_EVENT_WIDGET (widget);
 
+  gtk_widget_get_allocation (widget, &old_allocation);
+
   if (gtk_widget_get_realized (widget))
     {
       gdk_window_move_resize (self->event_window,
@@ -558,31 +580,20 @@ gcal_event_widget_size_allocate (GtkWidget     *widget,
                               allocation->height);
     }
 
-  /* Try to put the summary label below if the orientation is vertical */
-  if (self->orientation == GTK_ORIENTATION_VERTICAL && !gcal_event_get_all_day (self->event))
+  GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->size_allocate (widget, allocation);
+
+  /*
+   * Only after the child widgets (main grid, labels, etc) are allocated with the parent
+   * class' allocation function, we can check if the current height is enough to hold the
+   * vertical labels.
+   */
+  if (old_allocation.width != allocation->width || old_allocation.height != allocation->height)
     {
-      gint minimum_grid_height;
-      gint current_top;
-
-      gtk_widget_get_preferred_height (self->ghost_grid, &minimum_grid_height, NULL);
-
-      gtk_container_child_get (GTK_CONTAINER (self->main_grid),
-                               self->summary_label,
-                               "top-attach", &current_top,
-                               NULL);
-
-      /*
-       * Since we can't change the position of the events inside size-allocate,
-       * queue it for future iterations of the mainloop.
-       */
-      if ((allocation->height < minimum_grid_height && current_top == 1) ||
-          (allocation->height >= minimum_grid_height && current_top == 0))
-        {
-          queue_toggle_description_position (self);
-        }
-    }
+      if (self->orientation == GTK_ORIENTATION_HORIZONTAL || gcal_event_get_all_day (self->event))
+        return;
 
-  GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->size_allocate (widget, allocation);
+      queue_set_vertical_labels (self, can_hold_vertical_labels_with_height (self, allocation->height));
+    }
 }
 
 static cairo_surface_t*
@@ -761,8 +772,8 @@ gcal_event_widget_set_property (GObject      *object,
 
     case PROP_ORIENTATION:
       self->orientation = g_value_get_enum (value);
+      gtk_widget_set_visible (self->vertical_grid, self->orientation == GTK_ORIENTATION_VERTICAL);
       gcal_event_widget_update_style (self);
-      gtk_widget_queue_allocate (GTK_WIDGET (object));
       g_object_notify (object, "orientation");
       break;
 
@@ -817,11 +828,11 @@ gcal_event_widget_finalize (GObject *object)
   g_clear_pointer (&self->css_class, g_free);
   g_clear_object (&self->event);
 
-  /* withdraw mainloop sources */
-  if (self->toggle_description_id > 0)
+  /* remove timeouts */
+  if (self->vertical_label_source_id > 0)
     {
-      g_source_remove (self->toggle_description_id);
-      self->toggle_description_id = 0;
+      g_source_remove (self->vertical_label_source_id);
+      self->vertical_label_source_id = 0;
     }
 
   G_OBJECT_CLASS (gcal_event_widget_parent_class)->finalize (object);
@@ -913,10 +924,11 @@ gcal_event_widget_class_init (GcalEventWidgetClass *klass)
 
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/event-widget.ui");
 
-  gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, ghost_grid);
+  gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, horizontal_grid);
   gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, hour_label);
-  gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, main_grid);
+  gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, stack);
   gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, summary_label);
+  gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, vertical_grid);
 
   gtk_widget_class_set_css_name (widget_class, "event");
 }


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