From 176f8f28a8777dd0ba31687cc64452c61aef1617 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Thu, 10 Aug 2023 13:18:34 -0300 Subject: [PATCH] views/month: Show overflow popover when requested Basically, all that we used to do, but written in a different way for the new month view. --- src/gui/views/gcal-month-view.c | 142 ++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/src/gui/views/gcal-month-view.c b/src/gui/views/gcal-month-view.c index c163972d..f7bab11f 100644 --- a/src/gui/views/gcal-month-view.c +++ b/src/gui/views/gcal-month-view.c @@ -24,6 +24,8 @@ #include "config.h" #include "gcal-context.h" #include "gcal-debug.h" +#include "gcal-month-cell.h" +#include "gcal-month-popover.h" #include "gcal-month-view.h" #include "gcal-month-view-row.h" #include "gcal-range-tree.h" @@ -53,6 +55,12 @@ struct _GcalMonthView GPtrArray *week_rows; GHashTable *events; + struct { + GtkWidget *popover; + GcalMonthViewRow *row; + GtkWidget *relative_to; + } overflow; + /* Ranges from [0.0, 1.0] */ gdouble row_offset; AdwAnimation *row_offset_animation; @@ -89,6 +97,78 @@ enum * Auxiliary methods */ +static void +allocate_overflow_popover (GcalMonthView *self, + gint width, + gint height, + gint baseline) +{ + graphene_point_t origin, end; + GtkAllocation popover_allocation; + GtkAllocation allocation; + gint popover_min_width; + gint popover_nat_width; + gint popover_height; + gint popover_width; + gint header_height; + + g_assert (self->overflow.relative_to != NULL); + + header_height = gtk_widget_get_height (self->header); + + if (!gtk_widget_compute_point (self->overflow.relative_to, + GTK_WIDGET (self), + &GRAPHENE_POINT_INIT (0, 0), + &origin)) + g_assert_not_reached (); + + if (!gtk_widget_compute_point (self->overflow.relative_to, + GTK_WIDGET (self), + &GRAPHENE_POINT_INIT (gtk_widget_get_width (self->overflow.relative_to), + gtk_widget_get_height (self->overflow.relative_to)), + &end)) + g_assert_not_reached (); + + allocation = (GtkAllocation) { + .x = origin.x, + .y = origin.y, + .width = end.x - origin.x, + .height = end.y - origin.y, + }; + + gtk_widget_measure (GTK_WIDGET (self->overflow.popover), + GTK_ORIENTATION_HORIZONTAL, + -1, + &popover_min_width, + &popover_nat_width, + NULL, NULL); + + gtk_widget_measure (GTK_WIDGET (self->overflow.popover), + GTK_ORIENTATION_VERTICAL, + -1, + NULL, + &popover_height, + NULL, NULL); + + popover_width = CLAMP (popover_nat_width, popover_min_width, allocation.width * 1.5); + popover_height = CLAMP (popover_height, allocation.height * 1.5, height); + + popover_allocation = (GtkAllocation) { + .x = MAX (0, allocation.x - (popover_width - allocation.width) / 2.0), + .y = MAX (header_height, allocation.y - (popover_height - allocation.height) / 2.0), + .width = popover_width, + .height = popover_height, + }; + + if (popover_allocation.x + popover_allocation.width > width) + popover_allocation.x -= (popover_allocation.x + popover_allocation.width - width); + + if (popover_allocation.y + popover_allocation.height > height) + popover_allocation.y -= (popover_allocation.y + popover_allocation.height - height); + + gtk_widget_size_allocate (self->overflow.popover, &popover_allocation, baseline); +} + static void update_header_labels (GcalMonthView *self) { @@ -171,6 +251,22 @@ add_cached_events_to_row (GcalMonthView *self, } } +static inline void +maybe_popdown_overflow_popover (GcalMonthView *self) +{ + uint32_t row_index; + gboolean found; + + if (!self->overflow.row) + return; + + found = g_ptr_array_find (self->week_rows, self->overflow.row, &row_index); + g_assert (found); + + if (floor (row_index / (gdouble) N_ROWS_PER_PAGE) != floor (N_PAGES / 2.0)) + gcal_month_popover_popdown (GCAL_MONTH_POPOVER (self->overflow.popover)); +} + static void move_bottom_row_to_top (GcalMonthView *self) { @@ -320,6 +416,7 @@ update_week_ranges (GcalMonthView *self, } } + maybe_popdown_overflow_popover (self); dump_row_ranges (self); } @@ -397,6 +494,7 @@ offset_and_shuffle_rows (GcalMonthView *self, self->row_offset = fmod (self->row_offset, 0.5) + 0.5; } + maybe_popdown_overflow_popover (self); update_active_date (self); dump_row_ranges (self); } @@ -539,6 +637,7 @@ on_discrete_scroll_controller_scroll_cb (GtkEventControllerScroll *scroll_contro } gtk_widget_remove_css_class (GTK_WIDGET (self), "scrolling"); + maybe_popdown_overflow_popover (self); cancel_row_offset_animation (self); cancel_deceleration (self); update_active_date (self); @@ -642,6 +741,34 @@ on_scroll_controller_decelerate_cb (GtkEventControllerScroll *scroll_controller, GCAL_EXIT; } +static void +on_month_row_show_overflow_cb (GcalMonthViewRow *row, + GcalMonthCell *cell, + GcalMonthView *self) +{ + GcalMonthPopover *popover; + + GCAL_ENTRY; + + popover = GCAL_MONTH_POPOVER (self->overflow.popover); + + self->overflow.row = row; + self->overflow.relative_to = GTK_WIDGET (cell); + + gcal_month_popover_set_date (popover, gcal_month_cell_get_date (cell)); + gcal_month_popover_popup (popover); + + GCAL_EXIT; +} + +static void +on_month_popover_event_activated_cb (GcalMonthPopover *month_popover, + GcalEventWidget *event_widget, + GcalMonthViewRow *self) +{ + gcal_view_event_activated (GCAL_VIEW (self), event_widget); +} + /* * GcalTimelineSubscriber iface @@ -1007,6 +1134,10 @@ gcal_month_view_size_allocate (GtkWidget *widget, gtk_widget_size_allocate (row, &row_allocation, baseline); } + + /* Overflow popover */ + if (gtk_widget_should_layout (self->overflow.popover)) + allocate_overflow_popover (self, width, height, baseline); } static void @@ -1034,6 +1165,9 @@ gcal_month_view_snapshot (GtkWidget *widget, /* Snapshot header */ gtk_widget_snapshot_child (widget, self->header, snapshot); + + /* Overflow popover */ + gtk_widget_snapshot_child (widget, self->overflow.popover, snapshot); } @@ -1179,12 +1313,20 @@ gcal_month_view_init (GcalMonthView *self) { GtkWidget *row = gcal_month_view_row_new (); g_signal_connect (row, "event-activated", G_CALLBACK (on_event_widget_activated_cb), self); + g_signal_connect (row, "show-overflow", G_CALLBACK (on_month_row_show_overflow_cb), self); gtk_widget_set_parent (row, GTK_WIDGET (self)); g_ptr_array_add (self->week_rows, row); } gtk_widget_insert_after (self->header, GTK_WIDGET (self), NULL); + /* Overflow popover */ + self->overflow.popover = gcal_month_popover_new (); + g_object_bind_property (self, "context", self->overflow.popover, "context", G_BINDING_DEFAULT); + g_signal_connect (self->overflow.popover, "event-activated", G_CALLBACK (on_month_popover_event_activated_cb), self); + + gtk_widget_set_parent (self->overflow.popover, GTK_WIDGET (self)); + now = g_date_time_new_now_local (); gcal_view_set_date (GCAL_VIEW (self), now); }