diff --git a/src/gui/views/gcal-month-view-row.c b/src/gui/views/gcal-month-view-row.c
index 87aea581..45461759 100644
--- a/src/gui/views/gcal-month-view-row.c
+++ b/src/gui/views/gcal-month-view-row.c
@@ -775,3 +775,44 @@ gcal_month_view_row_get_children_by_uuid (GcalMonthViewRow *self,
return filter_children_by_uid_and_modtype (GTK_WIDGET (self), mod, uuid);
}
+
+GtkWidget*
+gcal_month_view_row_get_cell_at_x (GcalMonthViewRow *self,
+ gdouble x)
+{
+ gint column;
+ gint width;
+
+ g_assert (GCAL_IS_MONTH_VIEW_ROW (self));
+
+ width = gtk_widget_get_width (GTK_WIDGET (self));
+ if (x < 0.0 || x > width)
+ return NULL;
+
+ column = floor (7.0 * x / (gdouble) width);
+
+ if (gtk_widget_get_direction (GTK_WIDGET (self)) != GTK_TEXT_DIR_RTL)
+ return self->day_cells[column];
+ else
+ return self->day_cells[7 - column - 1];
+}
+
+void
+gcal_month_view_row_update_selection (GcalMonthViewRow *self,
+ GcalRange *selection_range)
+{
+ g_assert (GCAL_IS_MONTH_VIEW_ROW (self));
+
+ for (guint i = 0; i < 7; i++)
+ {
+ GcalMonthCell *month_cell;
+ GDateTime *cell_date;
+ gboolean selected;
+
+ month_cell = GCAL_MONTH_CELL (self->day_cells[i]);
+ cell_date = gcal_month_cell_get_date (month_cell);
+ selected = selection_range && gcal_range_contains_datetime (selection_range, cell_date);
+
+ gcal_month_cell_set_selected (month_cell, selected);
+ }
+}
diff --git a/src/gui/views/gcal-month-view-row.h b/src/gui/views/gcal-month-view-row.h
index 2d4177ad..d3428409 100644
--- a/src/gui/views/gcal-month-view-row.h
+++ b/src/gui/views/gcal-month-view-row.h
@@ -57,4 +57,9 @@ GList* gcal_month_view_row_get_children_by_uuid (GcalMonthViewR
GcalRecurrenceModType mod,
const gchar *uuid);
+GtkWidget* gcal_month_view_row_get_cell_at_x (GcalMonthViewRow *self,
+ gdouble x);
+
+void gcal_month_view_row_update_selection (GcalMonthViewRow *self,
+ GcalRange *selection_range);
G_END_DECLS
diff --git a/src/gui/views/gcal-month-view.c b/src/gui/views/gcal-month-view.c
index e20eee8f..af0bcfc3 100644
--- a/src/gui/views/gcal-month-view.c
+++ b/src/gui/views/gcal-month-view.c
@@ -52,6 +52,8 @@ struct _GcalMonthView
GtkWidget *year_label;
GtkWidget *weekday_label[7];
+ GtkEventController *motion_controller;
+
GPtrArray *week_rows;
GHashTable *events;
@@ -61,6 +63,11 @@ struct _GcalMonthView
GtkWidget *relative_to;
} overflow;
+ struct {
+ GDateTime *start;
+ GDateTime *end;
+ } selection;
+
/* Ranges from [0.0, 1.0] */
gdouble row_offset;
AdwAnimation *row_offset_animation;
@@ -676,11 +683,161 @@ animate_row_scroll (GcalMonthView *self,
GCAL_EXIT;
}
+static void
+update_selection_range (GcalMonthView *self)
+{
+ g_autoptr (GcalRange) selection_range = NULL;
+ GDateTime *selection_start;
+ GDateTime *selection_end;
+
+ selection_start = self->selection.start;
+ selection_end = self->selection.end;
+
+ if (selection_start)
+ {
+ if (!selection_end)
+ selection_end = selection_start;
+
+ /* Swap dates if end is before start */
+ if (gcal_date_time_compare_date (selection_start, selection_end) > 0)
+ {
+ GDateTime *aux = selection_end;
+ selection_end = selection_start;
+ selection_start = aux;
+ }
+
+ selection_range = gcal_range_new (selection_start, selection_end, GCAL_RANGE_DATE_ONLY);
+ }
+ else
+ {
+ g_assert (selection_end == NULL);
+ selection_range = NULL;
+ }
+
+ for (gint i = 0; i < self->week_rows->len; i++)
+ {
+ GcalMonthViewRow *row = g_ptr_array_index (self->week_rows, i);
+ gcal_month_view_row_update_selection (row, selection_range);
+ }
+}
+
+
/*
* Callbacks
*/
+static void
+on_click_gesture_pressed_cb (GtkGestureClick *click_gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ GcalMonthView *self)
+{
+ GtkWidget *widget_at_position;
+ GtkWidget *day_cell;
+
+ GCAL_ENTRY;
+
+ widget_at_position = gtk_widget_pick (GTK_WIDGET (self), x, y, GTK_PICK_DEFAULT);
+ day_cell = gtk_widget_get_ancestor (widget_at_position, GCAL_TYPE_MONTH_CELL);
+
+ if (!day_cell)
+ GCAL_RETURN ();
+
+ g_assert (GCAL_IS_MONTH_CELL (day_cell));
+
+ gcal_clear_date_time (&self->selection.start);
+ self->selection.start = g_date_time_ref (gcal_month_cell_get_date (GCAL_MONTH_CELL (day_cell)));
+
+ gtk_event_controller_set_propagation_phase (self->motion_controller, GTK_PHASE_BUBBLE);
+
+ update_selection_range (self);
+
+ GCAL_EXIT;
+}
+
+static void
+on_click_gesture_released_cb (GtkGestureClick *click_gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ GcalMonthView *self)
+{
+ g_autoptr (GcalRange) selection_range = NULL;
+ g_autoptr (GDateTime) selection_start = NULL;
+ g_autoptr (GDateTime) selection_end = NULL;
+ GtkWidget *widget_at_position;
+
+ GCAL_ENTRY;
+
+ gtk_event_controller_set_propagation_phase (self->motion_controller, GTK_PHASE_NONE);
+
+ widget_at_position = gtk_widget_pick (GTK_WIDGET (self), x, y, GTK_PICK_DEFAULT);
+
+ if (!widget_at_position || !gtk_widget_get_ancestor (widget_at_position, GCAL_TYPE_MONTH_VIEW_ROW))
+ {
+ gcal_view_clear_marks (GCAL_VIEW (self));
+ GCAL_RETURN ();
+ }
+
+ g_assert (self->selection.start != NULL);
+
+ selection_start = self->selection.start;
+ selection_end = self->selection.end ?: selection_start;
+
+ /* Swap dates if end is before start */
+ if (gcal_date_time_compare_date (selection_start, selection_end) > 0)
+ {
+ GDateTime *aux = selection_end;
+ selection_end = selection_start;
+ selection_start = aux;
+ }
+
+ selection_start = g_date_time_ref (selection_start);
+ selection_end = g_date_time_add_days (selection_end, 1);
+
+ selection_range = gcal_range_new (selection_start, selection_end, GCAL_RANGE_DEFAULT);
+ gcal_view_create_event (GCAL_VIEW (self), selection_range, x, y);
+
+ GCAL_EXIT;
+}
+
+static void
+on_motion_controller_motion_cb (GtkEventControllerMotion *motion_controller,
+ gdouble x,
+ gdouble y,
+ GcalMonthView *self)
+{
+ GtkWidget *widget_at_position;
+ GtkWidget *day_cell;
+ GtkWidget *row;
+
+ GCAL_ENTRY;
+
+ widget_at_position = gtk_widget_pick (GTK_WIDGET (self), x, y, GTK_PICK_DEFAULT);
+
+ if (!widget_at_position)
+ GCAL_RETURN ();
+
+ row = gtk_widget_get_ancestor (widget_at_position, GCAL_TYPE_MONTH_VIEW_ROW);
+
+ if (!row)
+ GCAL_RETURN ();
+
+ day_cell = gcal_month_view_row_get_cell_at_x (GCAL_MONTH_VIEW_ROW (row), x);
+
+ g_assert (day_cell != NULL);
+ g_assert (GCAL_IS_MONTH_CELL (day_cell));
+
+ gcal_clear_date_time (&self->selection.end);
+ self->selection.end = g_date_time_ref (gcal_month_cell_get_date (GCAL_MONTH_CELL (day_cell)));
+
+ update_selection_range (self);
+
+ GCAL_EXIT;
+}
+
static void
on_event_widget_activated_cb (GcalMonthViewRow *row,
GcalEventWidget *event_widget,
@@ -1076,7 +1233,18 @@ gcal_month_view_set_date (GcalView *view,
static void
gcal_month_view_clear_marks (GcalView *view)
{
- GCAL_TODO ("gcal_month_view_clear_marks");
+ GcalMonthView *self;
+
+ GCAL_ENTRY;
+
+ self = GCAL_MONTH_VIEW (view);
+
+ gcal_clear_date_time (&self->selection.start);
+ gcal_clear_date_time (&self->selection.end);
+
+ update_selection_range (self);
+
+ GCAL_EXIT;
}
static GList*
@@ -1347,6 +1515,8 @@ gcal_month_view_finalize (GObject *object)
{
GcalMonthView *self = (GcalMonthView *)object;
+ gcal_clear_date_time (&self->selection.start);
+ gcal_clear_date_time (&self->selection.end);
gcal_clear_date_time (&self->date);
g_clear_object (&self->context);
@@ -1426,6 +1596,7 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/views/gcal-month-view.ui");
gtk_widget_class_bind_template_child (widget_class, GcalMonthView, month_label);
+ gtk_widget_class_bind_template_child (widget_class, GcalMonthView, motion_controller);
gtk_widget_class_bind_template_child (widget_class, GcalMonthView, year_label);
gtk_widget_class_bind_template_child_full (widget_class, "label_0", FALSE, G_STRUCT_OFFSET (GcalMonthView, weekday_label[0]));
@@ -1436,7 +1607,10 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
gtk_widget_class_bind_template_child_full (widget_class, "label_5", FALSE, G_STRUCT_OFFSET (GcalMonthView, weekday_label[5]));
gtk_widget_class_bind_template_child_full (widget_class, "label_6", FALSE, G_STRUCT_OFFSET (GcalMonthView, weekday_label[6]));
+ gtk_widget_class_bind_template_callback (widget_class, on_click_gesture_pressed_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_click_gesture_released_cb);
gtk_widget_class_bind_template_callback (widget_class, on_discrete_scroll_controller_scroll_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_motion_controller_motion_cb);
gtk_widget_class_bind_template_callback (widget_class, on_scroll_controller_scroll_begin_cb);
gtk_widget_class_bind_template_callback (widget_class, on_scroll_controller_scroll_cb);
gtk_widget_class_bind_template_callback (widget_class, on_scroll_controller_scroll_end_cb);
diff --git a/src/gui/views/gcal-month-view.ui b/src/gui/views/gcal-month-view.ui
index 4ee26af5..cac56cd1 100644
--- a/src/gui/views/gcal-month-view.ui
+++ b/src/gui/views/gcal-month-view.ui
@@ -20,6 +20,21 @@
+
+
+
+
+
+
+
+