[gnome-calendar] month-view: initial implementation of size alloc



commit fbeb6d35b243b9173532ff8bcec59dd8566b3f10
Author: Erick Pérez Castellanos <erick red gmail com>
Date:   Thu Dec 18 01:23:46 2014 -0500

    month-view: initial implementation of size alloc
    
    This implements breaking of events, and showing of its parts. It also
    provides the information need for the drawing of the overflow indicator.
    This implementation brings support to RTL locales as well as LTR.
    
    There's some things still missing here:
    1. Mark the widgets with CSS classes for styling its broken status
    2. Draw properly the overflow indicator

 src/gcal-month-view.c |  262 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 185 insertions(+), 77 deletions(-)
---
diff --git a/src/gcal-month-view.c b/src/gcal-month-view.c
index c992955..2cbec14 100644
--- a/src/gcal-month-view.c
+++ b/src/gcal-month-view.c
@@ -564,121 +564,229 @@ gcal_month_view_size_allocate (GtkWidget     *widget,
                                GtkAllocation *allocation)
 {
   GcalMonthViewPrivate *priv;
-  gint i;
-  GList *l;
+  gint i, j;
+  gint sw, k;
 
-  GtkBorder padding;
+  gint padding_bottom;
   PangoLayout *layout;
   PangoFontDescription *font_desc;
-
   gint font_height;
-  gdouble added_height;
 
-  gdouble start_grid_y;
-  gdouble horizontal_block;
-  gdouble vertical_block;
-  gdouble vertical_cell_margin;
+  gdouble start_grid_y, cell_width, cell_height, vertical_cell_space;
+  gdouble pos_x, pos_y;
+  gdouble size_left [42];
 
-  gdouble days;
   gint shown_rows;
-  gint february_gap;
 
-  gdouble lines_gap;
+  const gchar *uuid;
+  GtkWidget *child_widget;
+  GtkAllocation child_allocation;
+  gint natural_height;
 
-  gdouble lines_gap_for_5;
+  GList *widgets, *l, *aux, *l2 = NULL;
+  GHashTableIter iter;
+  gpointer key, value;
 
   priv = gcal_month_view_get_instance_private (GCAL_MONTH_VIEW (widget));
 
-  gtk_widget_set_allocation (widget, allocation);
-  if (gtk_widget_get_realized (widget))
+  /* remove every widget' parts, but the master widget */
+  widgets = g_hash_table_get_values (priv->children);
+  for (aux = widgets; aux != NULL; aux = g_list_next (aux))
     {
-      gdk_window_move_resize (priv->event_window,
-                              allocation->x,
-                              allocation->y,
-                              allocation->width,
-                              allocation->height);
+      l = g_list_next ((GList*) aux->data);
+      for (; l != NULL; l = g_list_next (l))
+        l2 = g_list_append (l2, l->data);
     }
+  g_list_free (widgets);
 
-  gtk_style_context_get_padding (gtk_widget_get_style_context (widget),
-                                 gtk_widget_get_state_flags (widget),
-                                 &padding);
-  layout = pango_layout_new (gtk_widget_get_pango_context (widget));
+  for (aux = l2; aux != NULL; aux = g_list_next (aux))
+    gtk_widget_destroy ((GtkWidget*) aux->data);
+  g_list_free (l2);
+
+  /* clean overflow information */
+  g_hash_table_remove_all (priv->overflown_days);
+
+  gtk_widget_set_allocation (widget, allocation);
+  if (gtk_widget_get_realized (widget))
+    gdk_window_move_resize (priv->event_window, allocation->x, allocation->y, allocation->width, 
allocation->height);
+
+  gtk_style_context_get (gtk_widget_get_style_context (widget), gtk_widget_get_state_flags (widget),
+                         "font", &font_desc, "padding-bottom", &padding_bottom, NULL);
 
-  gtk_style_context_get (gtk_widget_get_style_context (widget),
-                         gtk_widget_get_state_flags (widget),
-                         "font", &font_desc,
-                         NULL);
+  layout = pango_layout_new (gtk_widget_get_pango_context (widget));
+  layout = gtk_widget_create_pango_layout (widget, _("Other events"));
   pango_layout_set_font_description (layout, font_desc);
   pango_layout_get_pixel_size (layout, NULL, &font_height);
   pango_font_description_free (font_desc);
   g_object_unref (layout);
 
   start_grid_y = get_start_grid_y (widget);
-  horizontal_block = allocation->width / 7.0;
-  vertical_block = (allocation->height - start_grid_y) / 6.0;
+  cell_width = allocation->width / 7.0;
+  cell_height = (allocation->height - start_grid_y) / 6.0;
+  vertical_cell_space = cell_height - (padding_bottom + font_height);
 
-  days = priv->days_delay + icaltime_days_in_month (priv->date->month, priv->date->year);
-  shown_rows = ceil (days / 7.0);
-  february_gap = shown_rows == 4 ? 1 : 0;
-  lines_gap = ((shown_rows + 1) / 2.0) + 0.5 - ceil (shown_rows / 2.0);
-  lines_gap_for_5 = shown_rows == 5 ? lines_gap : 0;
+  for (i = 0; i < 42; i++)
+    size_left[i] = vertical_cell_space;
+
+  shown_rows = ceil ((priv->days_delay + icaltime_days_in_month (priv->date->month, priv->date->year)) / 
7.0);
 
-  vertical_cell_margin = padding.top + font_height;
-  for (i = 0; i < 31; i++)
+  /* orientation factors */ /* FIXME: replace with direction-changed signal handler */
+  if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR)
     {
-      added_height = 0;
-      for (l = priv->days[i]; l != NULL; l = l->next)
+      sw = 1;
+      k = 0;
+    }
+  else if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
+    {
+      sw = -1;
+      k = 1;
+    }
+
+  /* allocate multidays events */
+  for (l = priv->multiday_children; l != NULL; l = g_list_next (l))
+    {
+      gint first_cell, last_cell, first_row, last_row, start, end;
+      gboolean visible;
+
+      const icaltimetype *date;
+      GArray *cells, *lengths;
+
+      child_widget = (GtkWidget*) l->data;
+      uuid = gcal_event_widget_peek_uuid (GCAL_EVENT_WIDGET (child_widget));
+      if (g_hash_table_contains (priv->hidden_for_delete, uuid))
+        continue;
+
+      gtk_widget_show (child_widget);
+      gtk_widget_get_preferred_height (child_widget, NULL, &natural_height);
+
+      j = 1;
+      date = gcal_event_widget_peek_start_date (GCAL_EVENT_WIDGET (child_widget));
+      if (date->month == priv->date->month)
+        j = date->day;
+      j += priv->days_delay;
+      first_cell = 7 * ((j - 1) / 7)+ 6 * k + sw * ((j - 1) % 7);
+
+      j = icaltime_days_in_month (priv->date->month, priv->date->year);
+      date = gcal_event_widget_peek_end_date (GCAL_EVENT_WIDGET (child_widget));
+      if (date->month == priv->date->month)
+        j = date->day;
+      j += priv->days_delay;
+      last_cell = 7 * ((j - 1) / 7)+ 6 * k + sw * ((j - 1) % 7);
+
+      /* FIXME missing mark widgets with continuos tags */
+
+      first_row = first_cell / 7;
+      last_row = last_cell / 7;
+      visible = TRUE;
+      cells = g_array_sized_new (TRUE, TRUE, sizeof (gint), 16);
+      lengths = g_array_sized_new (TRUE, TRUE, sizeof (gint), 16);
+      for (i = first_row; i <= last_row && visible; i++)
         {
-          GcalViewChild *child;
-          gint pos_x;
-          gint pos_y;
-          gint min_height;
-          gint natural_height;
-          GtkAllocation child_allocation;
-
-          child = (GcalViewChild*) l->data;
-
-          pos_x = horizontal_block * ((i + priv->days_delay) % 7);
-          pos_y = vertical_block * (((i + priv->days_delay + 7 * february_gap) / 7) + lines_gap_for_5);
-
-          if ((! gtk_widget_get_visible (child->widget))
-              && (! child->hidden))
-            continue;
-
-          gtk_widget_get_preferred_height (child->widget,
-                                           &min_height,
-                                           &natural_height);
-          child_allocation.x = pos_x;
-          child_allocation.y = start_grid_y + vertical_cell_margin + pos_y;
-          child_allocation.width = horizontal_block;
-          child_allocation.height = MIN (natural_height, vertical_block);
-          if (added_height + vertical_cell_margin + child_allocation.height
-              > vertical_block)
+          start = i * 7 + k * 6;
+          end = i * 7 + (1 - k) * 6;
+
+          if (i == first_row)
             {
-              gtk_widget_hide (child->widget);
-              child->hidden = TRUE;
+              start = first_cell;
+            }
+          if (i == last_row)
+            {
+              end = last_cell;
+            }
 
-              l = l->next;
-              for (; l != NULL; l = l->next)
+          g_debug ("[calculate] event %s from: %d -> %d", gcal_event_widget_get_summary (GCAL_EVENT_WIDGET 
(child_widget)),
+                   start, end);
+
+          visible = get_widget_parts (start, end, natural_height, vertical_cell_space, size_left, cells, 
lengths);
+        }
+
+      if (visible)
+        {
+          for (i = 0; i < cells->len; i++)
+            {
+              gint cell_idx = g_array_index (cells, gint, i);
+              gint row = cell_idx / 7;
+              gint column = cell_idx % 7;
+              pos_x = cell_width * column;
+              pos_y = cell_height * (row + 0.5 * (2.0 - (shown_rows % 2))) + start_grid_y;
+
+              child_allocation.x = pos_x;
+              child_allocation.y = pos_y + vertical_cell_space - size_left[cell_idx];
+              child_allocation.width = cell_width * g_array_index (lengths, gint, i);
+              child_allocation.height = natural_height;
+
+              g_debug ("[allocate] event %s from: %d -- %d --> %d ", gcal_event_widget_get_summary 
(GCAL_EVENT_WIDGET (child_widget)),
+                       cell_idx, g_array_index (lengths, gint, i), cell_idx + g_array_index (lengths, gint, 
i));
+
+              if (i != 0)
                 {
-                  child = (GcalViewChild*) l->data;
+                  child_widget = gcal_event_widget_clone (GCAL_EVENT_WIDGET (child_widget));
+
+                  gtk_widget_set_parent (child_widget, widget);
+                  g_signal_connect (child_widget, "activate", G_CALLBACK (event_opened), widget);
+                  gtk_widget_show (child_widget);
 
-                  gtk_widget_hide (child->widget);
-                  child->hidden = TRUE;
+                  aux = g_hash_table_lookup (priv->children, uuid);
+                  aux = g_list_append (aux, child_widget);
                 }
+              gtk_widget_size_allocate (child_widget, &child_allocation);
 
-              break;
+              /* update size_left */
+              for (j = 0; j < g_array_index (lengths, gint, i); j++)
+                size_left[cell_idx + j] -= natural_height;
+            }
+        }
+      else
+        {
+          gtk_widget_hide (child_widget);
+
+          /* FIXME: improve overflow to handle the proper count of widgets */
+          g_hash_table_add (priv->overflown_days, GINT_TO_POINTER (first_cell));
+        }
+
+      g_array_free (cells, TRUE);
+      g_array_free (lengths, TRUE);
+    }
+
+  g_hash_table_iter_init (&iter, priv->single_day_children);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      j = GPOINTER_TO_INT (key);
+      j += priv->days_delay;
+      i = 7 * ((j - 1) / 7)+ 6 * k + sw * ((j - 1) % 7);
+
+      l = (GList*) value;
+      for (aux = l; aux != NULL; aux = g_list_next (aux))
+        {
+          child_widget = (GtkWidget*) aux->data;
+
+          gtk_widget_show (child_widget);
+          gtk_widget_get_preferred_height (child_widget, NULL, &natural_height);
+
+          if (size_left[i] > natural_height)
+            {
+              pos_x = cell_width * (i % 7);
+              pos_y = cell_height * ((i / 7) + 0.5 * (2.0 - (shown_rows % 2))) + start_grid_y;
+
+              child_allocation.x = pos_x;
+              child_allocation.y = pos_y + vertical_cell_space - size_left[i];
+              child_allocation.width = cell_width;
+              child_allocation.height = natural_height;
+              gtk_widget_show (child_widget);
+              gtk_widget_size_allocate (child_widget, &child_allocation);
+
+              size_left[i] -= natural_height;
             }
           else
             {
-              gtk_widget_show (child->widget);
-              child->hidden = FALSE;
-              child_allocation.y = child_allocation.y + added_height;
-              gtk_widget_size_allocate (child->widget, &child_allocation);
-              added_height += child_allocation.height;
+              gtk_widget_hide (child_widget);
+              g_hash_table_add (priv->overflown_days, GINT_TO_POINTER (i));
             }
         }
     }
+
+  if (g_hash_table_size (priv->overflown_days) != 0)
+    gtk_widget_queue_draw (widget);
 }
 
 static gboolean


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