From 31409b6e440ed19411aa9a004cb748e88e1a46ee Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Mon, 13 Nov 2017 14:23:35 -0200 Subject: [PATCH] month-view: improve layout algorithm Multiday event handling was a mess, and still it. But this commit makes it at least layout things correctly. It's not perfect, though; This commit brought back that terrible allocation cycle issue, since we're showing and hiding events in size-allocate. --- src/views/gcal-month-view.c | 121 +++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 58 deletions(-) diff --git a/src/views/gcal-month-view.c b/src/views/gcal-month-view.c index 4073faf6..0a64e5f7 100644 --- a/src/views/gcal-month-view.c +++ b/src/views/gcal-month-view.c @@ -88,11 +88,6 @@ struct _GcalMonthView */ GHashTable *overflow_cells; - /* - * Set containing the master widgets hidden for delete; - */ - GHashTable *hidden_as_overflow; - /* * the cell on which its drawn the first day of the month, in the first row, 0 for the first * cell, 1 for the second, and so on, this takes first_weekday into account already. @@ -305,14 +300,15 @@ get_month_cell_at_position (GcalMonthView *self, return NULL; } -static gboolean +static void get_widget_parts (gint first_cell, gint last_cell, gint natural_height, gdouble *vertical_cell_space, gdouble *size_left, GArray *cells, - GArray *lengths) + GArray *lengths, + GArray *length_visible) { gdouble old_y; gdouble y; @@ -331,17 +327,22 @@ get_widget_parts (gint first_cell, for (i = first_cell; i <= last_cell; i++) { - if (size_left[i] < natural_height) - return FALSE; + gboolean visible_at_range; + gboolean different_row; + + visible_at_range = size_left[i] >= natural_height; + different_row = i / 7 != (i - 1) / 7; y = vertical_cell_space[i] - size_left[i]; - if (old_y == -1.0 || y != old_y) + if (old_y == -1.0 || y != old_y || different_row) { current_part_length = 1; + old_y = y; + g_array_append_val (cells, i); g_array_append_val (lengths, current_part_length); - old_y = y; + g_array_append_val (length_visible, visible_at_range); } else { @@ -349,8 +350,6 @@ get_widget_parts (gint first_cell, g_array_index (lengths, gint, lengths->len - 1) = current_part_length; } } - - return TRUE; } static void @@ -1175,8 +1174,6 @@ gcal_month_view_remove (GtkContainer *container, g_hash_table_remove (self->children, uuid); else g_hash_table_replace (self->children, g_strdup (uuid), l); - - g_hash_table_remove (self->hidden_as_overflow, uuid); } out: @@ -1295,7 +1292,6 @@ gcal_month_view_finalize (GObject *object) g_clear_pointer (&self->children, g_hash_table_destroy); g_clear_pointer (&self->single_cell_children, g_hash_table_destroy); g_clear_pointer (&self->overflow_cells, g_hash_table_destroy); - g_clear_pointer (&self->hidden_as_overflow, g_hash_table_destroy); g_clear_pointer (&self->multi_cell_children, g_list_free); g_clear_object (&self->manager); @@ -1500,12 +1496,16 @@ gcal_month_view_size_allocate (GtkWidget *widget, */ for (l = self->multi_cell_children; l; l = g_list_next (l)) { + g_autoptr (GArray) visible_at_length = NULL; g_autoptr (GArray) lengths = NULL; g_autoptr (GArray) cells = NULL; GDateTime *date; GcalEvent *event; - gboolean visible, all_day; - gint first_cell, last_cell, first_row, last_row, start, end; + gboolean all_day; + gint first_cell, last_cell; + gint first_row, last_row; + gint start, end; + gint cell; child_widget = (GtkWidget*) l->data; event = gcal_event_widget_get_event (l->data); @@ -1513,9 +1513,6 @@ gcal_month_view_size_allocate (GtkWidget *widget, all_day = gcal_event_get_all_day (event); child_context = gtk_widget_get_style_context (l->data); - if (!gtk_widget_is_visible (child_widget) && !g_hash_table_contains (self->hidden_as_overflow, uuid)) - continue; - gtk_widget_show (child_widget); gtk_widget_get_preferred_height (child_widget, &minimum_height, NULL); @@ -1573,11 +1570,11 @@ gcal_month_view_size_allocate (GtkWidget *widget, */ 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); + visible_at_length = g_array_sized_new (TRUE, TRUE, sizeof (gboolean), 16); - for (row = first_row; row <= last_row && visible; row++) + for (row = first_row; row <= last_row; row++) { start = row * 7 + self->k * 6; end = row * 7 + (1 - self->k) * 6; @@ -1587,51 +1584,42 @@ gcal_month_view_size_allocate (GtkWidget *widget, if (row == last_row) end = last_cell; - visible = get_widget_parts (start, end, minimum_height, vertical_cell_space, size_left, cells, lengths); + get_widget_parts (start, end, + minimum_height, + vertical_cell_space, + size_left, + cells, + lengths, + visible_at_length); } - /* No space left, add to the overflow and continue */ - if (!visible) - { - gtk_widget_hide (child_widget); - g_hash_table_add (self->hidden_as_overflow, g_strdup (uuid)); - - for (row = first_cell; row <= last_cell; row++) - { - aux = g_hash_table_lookup (self->overflow_cells, GINT_TO_POINTER (row)); - aux = g_list_append (aux, child_widget); - - if (g_list_length (aux) == 1) - g_hash_table_insert (self->overflow_cells, GINT_TO_POINTER (row), aux); - else - g_hash_table_replace (self->overflow_cells, GINT_TO_POINTER (row), g_list_copy (aux)); - } - - continue; - } - - for (row = 0; row < cells->len; row++) + for (cell = 0; cell < cells->len; cell++) { g_autoptr (GDateTime) dt_start = NULL; g_autoptr (GDateTime) dt_end = NULL; + gboolean visible; gdouble width; gint cell_idx; gint length; - gint real_row; gint column; gint day; - cell_idx = g_array_index (cells, gint, row); - length = g_array_index (lengths, gint, row); - real_row = cell_idx / 7; + visible = g_array_index (visible_at_length, gboolean, cell); + cell_idx = g_array_index (cells, gint, cell); + length = g_array_index (lengths, gint, cell); + row = cell_idx / 7; column = cell_idx % 7; day = cell_idx - self->days_delay + 1; /* Day number is calculated differently on RTL languages */ if (self->k) - day = 7 * real_row + MIRROR (cell_idx % 7, 0, 7) - self->days_delay - length + 1; + day = 7 * row + MIRROR (cell_idx % 7, 0, 7) - self->days_delay - length + 1; - if (row != 0) + /* + * Setup a new event widget when the cell index changes. This happens when + * the event has a different y position, or when the row changed. + */ + if (cell != 0) { child_widget = gcal_event_widget_clone (GCAL_EVENT_WIDGET (child_widget)); @@ -1644,11 +1632,32 @@ gcal_month_view_size_allocate (GtkWidget *widget, aux = g_list_append (aux, child_widget); } + /* No space left, add to the overflow and continue */ + if (!visible) + { + gint idx; + + gtk_widget_hide (child_widget); + + for (idx = cell_idx; idx < cell_idx + length; idx++) + { + aux = g_hash_table_lookup (self->overflow_cells, GINT_TO_POINTER (idx)); + aux = g_list_append (aux, child_widget); + + if (g_list_length (aux) == 1) + g_hash_table_insert (self->overflow_cells, GINT_TO_POINTER (idx), aux); + else + g_hash_table_replace (self->overflow_cells, GINT_TO_POINTER (idx), g_list_copy (aux)); + } + + continue; + } + /* Retrieve the cell widget */ if (self->k) - month_cell = self->month_cell[real_row][6 - column]; + month_cell = self->month_cell[row][6 - column]; else - month_cell = self->month_cell[real_row][column]; + month_cell = self->month_cell[row][column]; gtk_widget_get_allocation (month_cell, &cell_alloc); @@ -1689,7 +1698,6 @@ gcal_month_view_size_allocate (GtkWidget *widget, child_allocation.height = minimum_height; gtk_widget_size_allocate (child_widget, &child_allocation); - g_hash_table_remove (self->hidden_as_overflow, uuid); /* update size_left */ for (j = 0; j < length; j++) @@ -1732,7 +1740,7 @@ gcal_month_view_size_allocate (GtkWidget *widget, event = gcal_event_widget_get_event (aux->data); uuid = gcal_event_get_uid (event); - if (!gtk_widget_is_visible (child_widget) && !g_hash_table_contains (self->hidden_as_overflow, uuid)) + if (!gtk_widget_is_visible (child_widget)) continue; gtk_widget_show (child_widget); @@ -1742,7 +1750,6 @@ gcal_month_view_size_allocate (GtkWidget *widget, if (size_left[cell] < minimum_height) { gtk_widget_hide (child_widget); - g_hash_table_add (self->hidden_as_overflow, g_strdup (uuid)); l = g_hash_table_lookup (self->overflow_cells, GINT_TO_POINTER (cell)); l = g_list_append (l, child_widget); @@ -1771,7 +1778,6 @@ gcal_month_view_size_allocate (GtkWidget *widget, child_allocation.height = minimum_height; gtk_widget_show (child_widget); gtk_widget_size_allocate (child_widget, &child_allocation); - g_hash_table_remove (self->hidden_as_overflow, uuid); size_left[cell] -= minimum_height + margin.top + margin.bottom; } @@ -2001,7 +2007,6 @@ gcal_month_view_init (GcalMonthView *self) self->children = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_list_free); self->single_cell_children = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_list_free); self->overflow_cells = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_list_free); - self->hidden_as_overflow = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); self->k = gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;