month-view: use a custom structure to help multiday allocation

Instead of using 3 different, barely synchronized arrays. This
makes the code easier to read, and is more semantic too.
This commit is contained in:
Georges Basile Stavracas Neto
2017-11-18 21:57:25 -02:00
parent 89d5b4ae4b
commit 9fa9de2df7
+64 -45
View File
@@ -38,6 +38,15 @@
#define LINE_WIDTH 0.5
typedef struct
{
GtkWidget *event_widget;
gboolean visible;
guint8 length;
guint8 height;
guint8 cell;
} GcalEventBlock;
struct _GcalMonthView
{
GtkContainer parent;
@@ -289,19 +298,18 @@ get_month_cell_at_position (GcalMonthView *self,
return NULL;
}
static void
static GPtrArray*
calculate_multiday_event_blocks (GcalMonthView *self,
GtkWidget *event_widget,
gint first_cell,
gint last_cell,
gint natural_height,
gdouble *vertical_cell_space,
gdouble *size_left,
GArray *cells,
GArray *lengths,
GArray *length_visible,
gint *events_at_day,
gint *allocated_events_at_day)
{
GcalEventBlock *block;
GPtrArray *blocks;
gboolean was_visible;
gdouble old_y;
gdouble y;
@@ -321,27 +329,40 @@ calculate_multiday_event_blocks (GcalMonthView *self,
first_cell = swap;
}
blocks = g_ptr_array_new_full (last_cell - first_cell + 1, g_free);
GCAL_TRACE_MSG ("Calculating event blocks from cell %d to cell %d", first_cell, last_cell);
for (i = first_cell; i <= last_cell; i++)
{
GtkStyleContext *context;
GtkBorder margin;
gboolean visible_at_range;
gboolean different_row;
gboolean will_overflow;
gdouble real_height;
gint remaining_events;
gint minimum_height;
real_height = size_left[i];
/* Calculate the minimum event height */
context = gtk_widget_get_style_context (GTK_WIDGET (event_widget));
gtk_style_context_get_margin (context, gtk_style_context_get_state (context), &margin);
gtk_widget_get_preferred_height (GTK_WIDGET (event_widget), &minimum_height, NULL);
minimum_height += margin.top + margin.bottom;
/* Count this event at this cell */
different_row = i / 7 != (i - 1) / 7;
remaining_events = events_at_day[i] - allocated_events_at_day[i];
will_overflow = remaining_events * natural_height > real_height;
will_overflow = remaining_events * minimum_height > real_height;
if (will_overflow)
real_height -= gcal_month_cell_get_overflow_height (GCAL_MONTH_CELL (self->month_cell[i / 7][i % 7]));
visible_at_range = real_height >= natural_height;
visible_at_range = real_height >= minimum_height;
if (visible_at_range)
allocated_events_at_day[i]++;
@@ -359,20 +380,34 @@ calculate_multiday_event_blocks (GcalMonthView *self,
current_part_length = 1;
old_y = y;
g_array_append_val (cells, i);
g_array_append_val (lengths, current_part_length);
g_array_append_val (length_visible, visible_at_range);
/* Only create a new event widget after the first one is consumed */
if (old_y != -1.0)
{
event_widget = gcal_event_widget_clone (GCAL_EVENT_WIDGET (event_widget));
gtk_widget_show (event_widget);
setup_child_widget (self, event_widget);
}
/* Add a new block */
block = g_new (GcalEventBlock, 1);
block->event_widget = event_widget;
block->visible = visible_at_range;
block->height = minimum_height;
block->length = 1;
block->cell = i;
g_ptr_array_add (blocks, block);
}
else
{
current_part_length++;
g_array_index (lengths, gint, lengths->len - 1) = current_part_length;
block->length++;
}
was_visible = visible_at_range;
}
GCAL_EXIT;
GCAL_RETURN (blocks);
}
static void
@@ -1562,14 +1597,12 @@ gcal_month_view_size_allocate (GtkWidget *widget,
{
g_autoptr (GDateTime) start_date = NULL;
g_autoptr (GDateTime) end_date = NULL;
g_autoptr (GArray) visible_at_length = NULL;
g_autoptr (GArray) lengths = NULL;
g_autoptr (GArray) blocks = NULL;
g_autoptr (GPtrArray) blocks = NULL;
GcalEvent *event;
gboolean all_day;
gint event_block;
gint first_cell;
gint last_cell;
gint block_idx;
child_widget = (GtkWidget*) l->data;
event = gcal_event_widget_get_event (l->data);
@@ -1620,42 +1653,28 @@ gcal_month_view_size_allocate (GtkWidget *widget,
GCAL_TRACE_MSG ("Positioning '%s' (multiday) from %d to %d", gcal_event_get_summary (event), first_cell, last_cell);
blocks = 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);
blocks = calculate_multiday_event_blocks (self,
child_widget,
first_cell, last_cell,
vertical_cell_space,
size_left,
events_at_day,
allocated_events_at_day);
/* Position and allocate the child widget */
minimum_height = get_real_event_widget_height (child_widget);
gtk_style_context_get_margin (child_context,
gtk_style_context_get_state (child_context),
&margin);
calculate_multiday_event_blocks (self,
first_cell, last_cell,
minimum_height + margin.top + margin.bottom,
vertical_cell_space,
size_left,
blocks,
lengths,
visible_at_length,
events_at_day,
allocated_events_at_day);
for (event_block = 0; event_block < blocks->len; event_block++)
for (block_idx = 0; block_idx < blocks->len; block_idx++)
{
g_autoptr (GDateTime) dt_start = NULL;
g_autoptr (GDateTime) dt_end = NULL;
gboolean visible;
GcalEventBlock *block;
gdouble width;
gint last_block_cell;
gint length;
gint cell;
gint day;
visible = g_array_index (visible_at_length, gboolean, event_block);
length = g_array_index (lengths, gint, event_block);
cell = g_array_index (blocks, gint, event_block);
block = g_ptr_array_index (blocks, block_idx);
length = block->length;
cell = block->cell;
last_block_cell = cell + length - 1;
day = cell - self->days_delay + 1;
@@ -1663,7 +1682,7 @@ gcal_month_view_size_allocate (GtkWidget *widget,
* 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 (event_block != 0)
if (block_idx != 0)
{
child_widget = gcal_event_widget_clone (GCAL_EVENT_WIDGET (child_widget));
gtk_widget_show (child_widget);
@@ -1677,7 +1696,7 @@ gcal_month_view_size_allocate (GtkWidget *widget,
}
/* No space left, add to the overflow and continue */
if (!visible)
if (!block->visible)
{
gint idx;