diff --git a/src/gui/views/gcal-year-view.c b/src/gui/views/gcal-year-view.c index ac32a8f9..b8ebc658 100644 --- a/src/gui/views/gcal-year-view.c +++ b/src/gui/views/gcal-year-view.c @@ -22,14 +22,13 @@ #include "gcal-clock.h" #include "gcal-context.h" #include "gcal-debug.h" +#include "gcal-range-tree.h" #include "gcal-timeline-subscriber.h" #include "gcal-year-view.h" #include "gcal-view.h" #include "gcal-utils.h" #include -#include -#include #define NAVIGATOR_MAX_GRID_SIZE 4 #define VISUAL_CLUES_SIDE 3.0 @@ -37,55 +36,17 @@ typedef struct { - /* month span from 0 to 11 */ - gint start_day, start_month; - gint end_day, end_month; - gint hovered_day, hovered_month; - gint dnd_day, dnd_month; -} ButtonData; - -typedef struct -{ - gdouble box_side; - GdkPoint coordinates [12]; -} GridData; + GtkWidget *week_number[6]; + GtkWidget *day[31]; + GtkWidget *grid; +} MonthData; struct _GcalYearView { GtkBox parent; - /* composite, GtkBuilder's widgets */ - GtkWidget *navigator; - GtkWidget *sidebar; - GtkWidget *events_sidebar; - GtkWidget *navigator_stack; - GtkWidget *no_events_title; - GtkWidget *navigator_sidebar; - GtkWidget *scrolled_window; - GtkLabel *temp_label; /* unowned */ - GtkImage *weather_icon; /* unowned */ - - GtkWidget *popover; /* Popover for popover_mode */ - - /* manager singleton */ - GcalContext *context; - - /* range shown on the sidebar */ - GDateTime *start_selected_date; - GDateTime *end_selected_date; - - /* geometry info */ - GridData *navigator_grid; - guint number_of_columns; - guint column_width; - guint row_height; - guint header_height; - guint sidebar_width; - - /* state flags */ - gboolean popover_mode; - gboolean button_pressed; - ButtonData *selected_data; + GtkFlowBox *flowbox; + GtkLabel *year_label; /** * first day of the week according to user locale, being @@ -93,1483 +54,409 @@ struct _GcalYearView */ gint first_weekday; - /* first and last weeks of the year */ - guint first_week_of_year; - guint last_week_of_year; - - /* Storage for the accumulated scrolling */ - gdouble scroll_value; - - /* show week numbers from GNOME Shell settings */ GSettings *calendar_settings; - gboolean show_week_numbers; - /* text direction factors */ - gint k; + MonthData months[12]; - /* date property */ GDateTime *date; + GcalContext *context; + gulong update_indicators_idle_id; - /* - * Array with the events at every month. Events - * that span multiple months are added multiple - * times to the array. - */ - GPtrArray *events[12]; + GcalRangeTree *events; }; enum { PROP_0, PROP_DATE, PROP_CONTEXT, - PROP_SHOW_WEEK_NUMBERS, LAST_PROP }; static void gcal_view_interface_init (GcalViewInterface *iface); -static void update_weather (GcalYearView *self); - static void gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface); +static gboolean update_event_indicators_in_idle_cb (gpointer data); G_DEFINE_TYPE_WITH_CODE (GcalYearView, gcal_year_view, GTK_TYPE_BOX, G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW, gcal_view_interface_init) G_IMPLEMENT_INTERFACE (GCAL_TYPE_TIMELINE_SUBSCRIBER, gcal_timeline_subscriber_interface_init)); -static gint -compare_events (GcalEventWidget *widget1, - GcalEventWidget *widget2) +static GtkWidget* +create_day_label (guint day) { - return gcal_event_compare (gcal_event_widget_get_event (widget1), gcal_event_widget_get_event (widget2)); -} + g_autofree gchar *day_str = NULL; + GtkWidget *overlay; + GtkWidget *label; + GtkWidget *dot; -static guint -get_last_week_of_year_dmy (gint first_weekday, - GDateDay day, - GDateMonth month, - GDateYear year) -{ - GDate day_of_year; - gint day_of_week; + day_str = g_strdup_printf ("%u", day); + label = gtk_label_new (day_str); + gtk_widget_set_halign (label, GTK_ALIGN_CENTER); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); + gtk_widget_add_css_class (label, "days"); + gtk_widget_add_css_class (label, "numeric"); - g_date_set_dmy (&day_of_year, day, month, year); - day_of_week = g_date_get_weekday (&day_of_year) % 7; + dot = g_object_new (ADW_TYPE_BIN, + "css-name", "dot", + "valign", GTK_ALIGN_END, + "halign", GTK_ALIGN_CENTER, + NULL); - if (day_of_week >= first_weekday) - g_date_add_days (&day_of_year, (6 - day_of_week) + first_weekday); - else - g_date_add_days (&day_of_year, first_weekday - day_of_week - 1); + overlay = gtk_overlay_new (); + gtk_overlay_set_child (GTK_OVERLAY (overlay), label); + gtk_overlay_add_overlay (GTK_OVERLAY (overlay), dot); + g_object_set_data (G_OBJECT (overlay), "dot", dot); - return g_date_get_iso8601_week_of_year (&day_of_year); + return overlay; } static void -event_activated (GcalEventWidget *widget, - gpointer user_data) +set_dot_visible (GtkWidget *day_widget, + gboolean visible) { - GcalYearView *view = GCAL_YEAR_VIEW (user_data); - - if (view->popover_mode) - gtk_widget_hide (view->popover); - g_signal_emit_by_name (view, "event-activated", widget); + GtkWidget *dot = g_object_get_data (G_OBJECT (day_widget), "dot"); + gtk_widget_set_visible (dot, visible); } static void -weather_changed (GcalWeatherService *weather_service, - GcalYearView *self) +init_month_data (GcalYearView *self, + guint month, + MonthData *month_data) { - g_return_if_fail (GCAL_IS_WEATHER_SERVICE (weather_service)); - g_return_if_fail (GCAL_IS_YEAR_VIEW (self)); - - update_weather (self); -} - -static void -order_selected_data (ButtonData *selected_data) -{ - gint swap; - if (selected_data->end_month < selected_data->start_month) - { - swap = selected_data->start_month; - selected_data->start_month = selected_data->end_month; - selected_data->end_month = swap; - - swap = selected_data->start_day; - selected_data->start_day = selected_data->end_day; - selected_data->end_day = swap; - } - else if (selected_data->start_month == selected_data->end_month && selected_data->end_day < selected_data->start_day) - { - swap = selected_data->start_day; - selected_data->start_day = selected_data->end_day; - selected_data->end_day = swap; - } -} - -static void -update_selected_dates_from_button_data (GcalYearView *year_view) -{ - if (year_view->selected_data->start_day != 0) - { - ButtonData selected_data = *(year_view->selected_data); - - order_selected_data (&selected_data); - - gcal_clear_date_time (&year_view->start_selected_date); - year_view->start_selected_date = g_date_time_new_local (g_date_time_get_year (year_view->date), - selected_data.start_month + 1, - selected_data.start_day, - 0, 0, 0); - - gcal_clear_date_time (&year_view->end_selected_date); - year_view->end_selected_date = g_date_time_new_local (g_date_time_get_year (year_view->date), - selected_data.end_month + 1, - selected_data.end_day, - 23, 59, 59); - } - else - { - g_autoptr (GDateTime) start_date = NULL; - - if (year_view->date) - start_date = g_date_time_ref (year_view->date); - else - start_date = g_date_time_new_now_local (); - - gcal_clear_date_time (&year_view->start_selected_date); - year_view->start_selected_date = g_date_time_new (gcal_context_get_timezone (year_view->context), - g_date_time_get_year (start_date), - g_date_time_get_month (start_date), - g_date_time_get_day_of_month (start_date), - 0, 0, 0); - - gcal_clear_date_time (&year_view->end_selected_date); - year_view->end_selected_date = g_date_time_add_days (year_view->start_selected_date, 1); - - year_view->selected_data->start_day = g_date_time_get_day_of_month (year_view->start_selected_date); - year_view->selected_data->start_month = g_date_time_get_month (year_view->start_selected_date) - 1; - year_view->selected_data->end_day = g_date_time_get_day_of_month (year_view->end_selected_date); - year_view->selected_data->end_month = g_date_time_get_month (year_view->end_selected_date)-1; - } - - if (g_date_time_get_year (year_view->end_selected_date) != g_date_time_get_year (year_view->start_selected_date)) - { - g_autoptr (GDateTime) end_of_year = NULL; - - end_of_year = g_date_time_new (gcal_context_get_timezone (year_view->context), - g_date_time_get_year (year_view->start_selected_date), - G_DATE_DECEMBER, - 31, - 0, 0, 0); - gcal_set_date_time (&year_view->end_selected_date, end_of_year); - } -} - -static void -update_no_events_page (GcalYearView *year_view) -{ - g_autoptr (GDateTime) now = NULL; - g_autofree gchar *title = NULL; - gboolean has_range; - - now = g_date_time_new_now_local (); - has_range = gcal_date_time_compare_date (year_view->start_selected_date, year_view->end_selected_date); - - if (gcal_date_time_compare_date (now, year_view->start_selected_date) == 0) - { - title = g_strdup_printf ("%s%s", _("Today"), has_range ? "…" : ""); - } - else - { - if (has_range) - { - /* Translators: This is a date format in the sidebar of the year - * view when the selection starts at the specified day and the - * end is unspecified. */ - title = g_date_time_format (year_view->start_selected_date, _("%B %d…")); - } - else - { - /* Translators: This is a date format in the sidebar of the year - * view when there is only one specified day selected. */ - title = g_date_time_format (year_view->start_selected_date, _("%B %d")); - } - } - - gtk_label_set_text (GTK_LABEL (year_view->no_events_title), title); - update_weather (year_view); -} - -static void -add_event_to_day_array (GcalYearView *year_view, - GcalEvent *event, - GList **days_widgets_array, - gint days_span) -{ - g_autoptr (GDateTime) second_date = NULL; - g_autoptr (GDateTime) date = NULL; - GcalCalendar *calendar; - GtkWidget *child_widget; - GDateTime *dt_start, *dt_end; - gboolean is_readonly; - gint i; - - calendar = gcal_event_get_calendar (event); - is_readonly = gcal_calendar_is_read_only (calendar); - - child_widget = gcal_event_widget_new (year_view->context, event); - gcal_event_widget_set_read_only (GCAL_EVENT_WIDGET (child_widget), is_readonly); - - dt_start = gcal_event_get_date_start (event); - dt_end = gcal_event_get_date_end (event); - - /* normalize date on each new event */ - date = g_date_time_ref (year_view->start_selected_date); - second_date = g_date_time_add_days (date, 1); - - /* marking and cloning */ - for (i = 0; i < days_span; i++) - { - GtkWidget *cloned_child; - GDateTime *aux; - gint start_comparison; - - cloned_child = child_widget; - start_comparison = gcal_date_time_compare_date (dt_start, date); - - if (start_comparison > 0) - { - /* - * The start date of the event is ahead of the current - * date being comparent, so we don't add it now. - */ - cloned_child = NULL; - } - else if (start_comparison == 0) - { - /* - * This is the first day the event happens, so we just use - * the previously created event widget. - */ - cloned_child = child_widget; - } - else - { - /* - * We're in the middle of the event and the dates are between - * the event start date > current date > event end date, so - * we keep cloning the event widget until we reach the end of - * the event. - */ - cloned_child = gcal_event_widget_clone (GCAL_EVENT_WIDGET (child_widget)); - } - - if (cloned_child != NULL) - { - gint end_comparison; - - /* - * Setup the event widget's custom dates, so the slanted edges are - * applied properly - */ - if (gcal_event_is_multiday (event)) - { - gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (cloned_child), date); - gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (cloned_child), second_date); - } - - days_widgets_array[i] = g_list_insert_sorted (days_widgets_array[i], - cloned_child, - (GCompareFunc) compare_events); - - end_comparison = gcal_date_time_compare_date (second_date, dt_end); - - /* - * If the end date surpassed the event's end date, we reached the - * end of the event's time span and shall stop adding the event to - * the list. - */ - if (end_comparison >= 0) - break; - } - - /* Move the compared dates to the next day */ - aux = date; - date = g_date_time_add_days (date, 1); - g_clear_pointer (&aux, g_date_time_unref); - - aux = second_date; - second_date = g_date_time_add_days (second_date, 1); - g_clear_pointer (&aux, g_date_time_unref); - } -} - -static GPtrArray* -get_events_for_range (GcalYearView *self, - GDateTime *start, - GDateTime *end) -{ - g_autoptr (GPtrArray) events = NULL; + GtkWidget *month_name; + GtkWidget *separator; guint i; - events = g_ptr_array_sized_new (50); + month_data->grid = g_object_new (GTK_TYPE_GRID, + "column-spacing", 6, + "row-spacing", 6, + "column-spacing", 6, + "hexpand", TRUE, + "vexpand", TRUE, + NULL); + gtk_widget_add_css_class (month_data->grid, "month"); + gtk_widget_add_css_class (month_data->grid, "card"); + gtk_widget_add_css_class (month_data->grid, "activatable"); + gtk_flow_box_append (self->flowbox, month_data->grid); - for (i = g_date_time_get_month (start) - 1; i <= g_date_time_get_month (end) - 1; i++) + month_name = gtk_label_new (gcal_get_month_name (month)); + gtk_widget_set_hexpand (month_name, TRUE); + gtk_widget_add_css_class (month_name, "accent"); + gtk_widget_add_css_class (month_name, "title-4"); + gtk_grid_attach (GTK_GRID (month_data->grid), month_name, 0, 0, 8, 1); + + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_grid_attach (GTK_GRID (month_data->grid), separator, 0, 1, 8, 1); + + for (i = 0; i < 6; i++) { - GPtrArray *month_events = self->events[i]; - guint j; + month_data->week_number[i] = gtk_label_new (NULL); + gtk_widget_set_halign (month_data->week_number[i], GTK_ALIGN_CENTER); + gtk_widget_set_valign (month_data->week_number[i], GTK_ALIGN_CENTER); + gtk_widget_add_css_class (month_data->week_number[i], "week-number"); + gtk_grid_attach (GTK_GRID (month_data->grid), month_data->week_number[i], 0, i + 2, 1, 1); + } - for (j = 0; j < month_events->len; j++) + for (i = 0; i < 31; i++) + { + month_data->day[i] = create_day_label (i + 1); + + gtk_grid_attach (GTK_GRID (month_data->grid), + month_data->day[i], + 1 + i % 7, + 2 + i / 7, + 1, + 1); + } +} + +static void +update_weekday_widgets (GcalYearView *self) +{ + gboolean show_weekdate; + guint month; + + GCAL_ENTRY; + + show_weekdate = g_settings_get_boolean (self->calendar_settings, "show-weekdate"); + + for (month = 0; month < 12; month++) + { + g_autoptr (GDateTime) week_date = NULL; + GDate date; + gint days_delay; + gint week; + + g_date_set_dmy (&date, 1, month + 1, g_date_time_get_year (self->date)); + days_delay = 7 - (7 - ((g_date_get_weekday (&date) % 7) - (self->first_weekday % 7))); + + /* Week numbers */ + week_date = g_date_time_new_local (g_date_time_get_year (self->date), + month + 1, + 1, 0, 0, 0); + + for (week = 0; week < 6; week++) { - GDateTime *event_start; - GDateTime *event_end; - GcalEvent *event; + g_autoptr (GDateTime) next_week_date = NULL; + GtkWidget *label; + gboolean valid_date; - event = g_ptr_array_index (month_events, j); - event_start = gcal_event_get_date_start (event); - event_end = gcal_event_get_date_end (event); + valid_date = g_date_valid_dmy (MAX (week * 7 + 1 - days_delay, 1), + month + 1, + g_date_time_get_year (self->date)); - if (gcal_date_time_compare_date (event_end, start) < 0 || - gcal_date_time_compare_date (event_start, end) > 0) + label = self->months[month].week_number[week]; + gtk_widget_set_visible (label, valid_date && show_weekdate); + + if (valid_date) { - continue; + g_autofree gchar *week_number = NULL; + + week_number = g_strdup_printf ("%d", g_date_time_get_week_of_year (week_date)); + gtk_label_set_label (GTK_LABEL (label), week_number); } - g_ptr_array_add (events, event); + next_week_date = g_date_time_add_days (week_date, 7); + gcal_set_date_time (&week_date, next_week_date); } } - return g_steal_pointer (&events); + GCAL_EXIT; } static void -update_sidebar (GcalYearView *year_view) +update_year_label (GcalYearView *self) { - g_autoptr (GPtrArray) events = NULL; - GtkWidget *child_widget; - GList **days_widgets_array; - gint i, days_span; + g_autofree gchar *year = NULL; - update_selected_dates_from_button_data (year_view); + year = g_date_time_format (self->date, "%Y"); + gtk_label_set_label (self->year_label, year); +} - gtk_container_foreach (GTK_CONTAINER (year_view->events_sidebar), (GtkCallback) gtk_widget_destroy, NULL); +static void +update_event_indicators (GcalYearView *self) +{ + guint month; - days_span = g_date_time_get_day_of_year (year_view->end_selected_date) - g_date_time_get_day_of_year (year_view->start_selected_date) + 1; - days_widgets_array = g_new0 (GList*, days_span); + GCAL_ENTRY; - events = get_events_for_range (year_view, - year_view->start_selected_date, - year_view->end_selected_date); - - - if (events->len == 0) + for (month = 0; month < 12; month++) { - days_span = 0; - update_no_events_page (year_view); - gtk_stack_set_visible_child_name (GTK_STACK (year_view->navigator_stack), "no-events"); - } - else - { - gtk_stack_set_visible_child_name (GTK_STACK (year_view->navigator_stack), "events-list"); - } + guint day; - for (i = 0; i < events->len; i++) - { - add_event_to_day_array (year_view, - g_ptr_array_index (events, i), - days_widgets_array, - days_span); - } - - gtk_widget_queue_draw (year_view->navigator); - - for (i = 0; i < days_span; i++) - { - GList *current_day = days_widgets_array[i]; - GList *l; - - for (l = current_day; l != NULL; l = g_list_next (l)) + for (day = 0; day < 31; day++) { - child_widget = l->data; - gtk_widget_show (child_widget); - g_signal_connect_object (child_widget, "activate", G_CALLBACK (event_activated), year_view, 0); - g_object_set_data (G_OBJECT (child_widget), "shift", GINT_TO_POINTER (i)); - gtk_container_add (GTK_CONTAINER (year_view->events_sidebar), child_widget); - } + g_autoptr (GcalRange) range = NULL; + g_autoptr (GDateTime) date = NULL; - g_list_free (current_day); - } + if (!g_date_valid_dmy (day + 1, month + 1, g_date_time_get_year (self->date))) + continue; - g_free (days_widgets_array); -} + date = g_date_time_new_local (g_date_time_get_year (self->date), + month + 1, + day + 1, + 0, 0, 0); + range = gcal_range_new_take (g_date_time_ref (date), + g_date_time_add_days (date, 1), + GCAL_RANGE_DEFAULT); -static void -reset_sidebar (GcalYearView *year_view) -{ - memset (year_view->selected_data, 0, sizeof (ButtonData)); - gtk_widget_queue_draw (GTK_WIDGET (year_view)); - - update_sidebar (year_view); -} - -static void -update_sidebar_headers (GtkListBoxRow *row, - GtkListBoxRow *before, - gpointer user_data) -{ - GcalYearView *year_view; - GtkWidget *row_child, *before_child = NULL, *row_header = NULL; - GcalEvent *row_event, *before_event; - GDateTime *row_date, *before_date = NULL; - gint row_shift, before_shift =-1; - - year_view = GCAL_YEAR_VIEW (user_data); - row_child = gtk_bin_get_child (GTK_BIN (row)); - - if (!row_child) - return; - - row_event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (row_child)); - row_date = gcal_event_get_date_start (row_event); - row_date = g_date_time_to_local (row_date); - row_shift = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row_child), "shift")); - - if (before) - { - before_child = gtk_bin_get_child (GTK_BIN (before)); - before_event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (before_child)); - before_date = gcal_event_get_date_start (before_event); - before_date = g_date_time_to_local (before_date); - before_shift = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (before_child), "shift")); - } - - if (before_shift == -1 || before_shift != row_shift) - { - g_autoptr (GDateTime) row_day = NULL; - g_autoptr (GDateTime) now = NULL; - GtkWidget *label; - gchar *label_str; - - row_header = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - now = g_date_time_new_now_local (); - row_day = g_date_time_add_days (year_view->start_selected_date, row_shift); - - if (gcal_date_time_compare_date (row_day, now) == 0) - label_str = g_strdup (_("Today")); - else - /* Translators: This is a date format in the sidebar of the year view. */ - label_str = g_date_time_format (row_day, _("%B %d")); - - label = gtk_label_new (label_str); - gtk_style_context_add_class (gtk_widget_get_style_context (label), "sidebar-header"); - g_object_set (label, "margin", 6, "halign", GTK_ALIGN_START, NULL); - g_free (label_str); - - gtk_container_add (GTK_CONTAINER (row_header), label); - } - - if (row_header != NULL) - gtk_widget_show_all (row_header); - gtk_list_box_row_set_header (row, row_header); - - g_clear_pointer (&before_date, g_date_time_unref); - g_clear_pointer (&row_date, g_date_time_unref); -} - -static void -calculate_coord_for_date (GcalYearView *year_view, - gint day, - gint month, - gboolean is_title, - GdkRectangle *rect) -{ - gint cell_x, cell_y, clicked_cell, sw; - - if (is_title || - year_view->selected_data->start_day != year_view->selected_data->end_day || - year_view->selected_data->start_month != year_view->selected_data->end_month) - { - rect->x = year_view->navigator_grid->coordinates[month].x; - rect->y = year_view->navigator_grid->coordinates[month].y; - rect->width = year_view->column_width; - rect->height = year_view->row_height; - - return; - } - - /* else */ - sw = 1 - 2 * year_view->k; - clicked_cell = day + ((time_day_of_week (1, month, g_date_time_get_year (year_view->date)) - year_view->first_weekday + 7) % 7) - 1; - - cell_x = (clicked_cell % 7 + year_view->k + year_view->show_week_numbers) * year_view->navigator_grid->box_side * sw; - cell_x += (year_view->k * year_view->navigator_grid->box_side * (7 + year_view->show_week_numbers)); - cell_y = ((clicked_cell / 7 + 1) * year_view->navigator_grid->box_side); - - rect->x = cell_x + year_view->navigator_grid->coordinates[month].x; - rect->y = cell_y + year_view->navigator_grid->coordinates[month].y; - rect->width = rect->height = year_view->navigator_grid->box_side; -} - -static gint -sidebar_sort_func (GtkListBoxRow *row1, - GtkListBoxRow *row2, - gpointer user_data) -{ - GtkWidget *row1_child, *row2_child; - gint result, row1_shift, row2_shift; - - row1_child = gtk_bin_get_child (GTK_BIN (row1)); - row2_child = gtk_bin_get_child (GTK_BIN (row2)); - row1_shift = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row1_child), "shift")); - row2_shift = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row2_child), "shift")); - - result = row1_shift - row2_shift; - if (result == 0) - return compare_events (GCAL_EVENT_WIDGET (row1_child), GCAL_EVENT_WIDGET (row2_child)); - - return result; -} - - -static gboolean -calculate_day_month_for_coord (GcalYearView *year_view, - gdouble x, - gdouble y, - gint *out_day, - gint *out_month, - gboolean *is_title) -{ - GdkPoint *coordinates; - gint row, column, i, sw, clicked_cell, day, month, columns_or_rows; - gint number_of_rows; - gdouble box_side; - - row = -1; - column = -1; - box_side = year_view->navigator_grid->box_side; - number_of_rows = ceil (12.0 / year_view->number_of_columns); - sw = 1 - 2 * year_view->k; - coordinates = year_view->navigator_grid->coordinates; - - *is_title = FALSE; - columns_or_rows = year_view->number_of_columns > number_of_rows ? year_view->number_of_columns : number_of_rows; - - for (i = 0; i < columns_or_rows && ((row == -1) || (column == -1)); i++) - { - if (row == -1 && - y > coordinates[i * year_view->number_of_columns].y && - y < coordinates[i * year_view->number_of_columns].y + year_view->row_height) - { - if (y < coordinates[i * year_view->number_of_columns].y + box_side) - *is_title = TRUE; - row = i; - } - if (column == -1 && - x > coordinates[i].x + box_side * year_view->show_week_numbers * (1 - year_view->k) && - x < coordinates[i].x + year_view->column_width - box_side * year_view->show_week_numbers * year_view->k) - { - column = i; + set_dot_visible (self->months[month].day[day], + gcal_range_tree_count_entries_at_range (self->events, range) > 0); } } - if (row == -1 || column == -1) - return FALSE; - - month = row * year_view->number_of_columns + column; - - if (month < 0 || month > 11) - return FALSE; - - *out_month = month; - - if (*is_title) - return TRUE; - - row = (y - (year_view->navigator_grid->coordinates[month].y + box_side)) / box_side; - column = (x - (year_view->navigator_grid->coordinates[month].x + box_side * year_view->show_week_numbers * (1 - year_view->k))) / box_side; - clicked_cell = row * 7 + column; - day = 7 * ((clicked_cell + 7 * year_view->k) / 7) + sw * (clicked_cell % 7) + (1 - year_view->k); - day -= ((time_day_of_week (1, month, g_date_time_get_year (year_view->date)) - year_view->first_weekday + 7) % 7); - - if (day < 1 || day > time_days_in_month (g_date_time_get_year (year_view->date), month)) - return FALSE; - - *out_day = day; - return TRUE; -} -static guint -count_events_at_day (GcalYearView *self, - GDateTime *today) -{ - g_autoptr (GDateTime) today_end = NULL; - GPtrArray *events; - guint i, n_events; - - events = self->events[g_date_time_get_month (today) - 1]; - n_events = 0; - today_end = g_date_time_add_days (today, 1); - - for (i = 0; i < events->len; i++) - { - g_autoptr (GDateTime) event_start = NULL; - g_autoptr (GDateTime) event_end = NULL; - GcalEvent *event; - - event = g_ptr_array_index (events, i); - - event_start = g_date_time_ref (gcal_event_get_date_start (event)); - - if (gcal_event_get_all_day (event)) - event_end = g_date_time_add_days (gcal_event_get_date_end (event), -1); - else - event_end = g_date_time_ref (gcal_event_get_date_end (event)); - - - if (gcal_date_time_compare_date (event_start, today_end) >= 0 || - gcal_date_time_compare_date (event_end, today) < 0) - { - continue; - } - - n_events++; - } - - return n_events; + GCAL_EXIT; } static void -draw_month_grid (GcalYearView *year_view, - GtkWidget *widget, - cairo_t *cr, - gint month_nr, - gint *weeks_counter) +update_month_grid (GcalYearView *self) { - GtkStyleContext *context; - GtkStateFlags state_flags; - - PangoLayout *layout, *slayout; - PangoFontDescription *font_desc, *sfont_desc; - - g_autoptr (GDateTime) day = NULL; g_autoptr (GDateTime) now = NULL; + gboolean show_weekdate; + guint month; - GdkRGBA color; - gint layout_width, layout_height, i, j, sw; - gint column, row; - gboolean column_is_workday; - gdouble x, y, box_side, box_padding_top, box_padding_start; - gint days_delay, days, shown_rows; - gchar *str, *nr_day, *nr_week; - gboolean selected_day; + GCAL_ENTRY; now = g_date_time_new_now_local (); + show_weekdate = g_settings_get_boolean (self->calendar_settings, "show-weekdate"); - cairo_save (cr); - context = gtk_widget_get_style_context (widget); - state_flags = gtk_style_context_get_state (context); - sw = 1 - 2 * year_view->k; - box_side = year_view->navigator_grid->box_side; - x = year_view->navigator_grid->coordinates[month_nr].x; - y = year_view->navigator_grid->coordinates[month_nr].y; - - /* Get the font description */ - gtk_style_context_save (context); - gtk_style_context_set_state (context, state_flags | GTK_STATE_FLAG_SELECTED); - gtk_style_context_get (context, state_flags | GTK_STATE_FLAG_SELECTED, "font", &sfont_desc, NULL); - gtk_style_context_restore (context); - - slayout = gtk_widget_create_pango_layout (widget, NULL); - pango_layout_set_font_description (slayout, sfont_desc); - - /* header */ - gtk_style_context_save (context); - gtk_style_context_add_class (context, "header"); - - str = g_strdup (gcal_get_month_name (month_nr)); - gtk_style_context_get (context, state_flags, "font", &font_desc, NULL); - - layout = gtk_widget_create_pango_layout (widget, str); - pango_layout_set_font_description (layout, font_desc); - pango_layout_get_pixel_size (layout, &layout_width, &layout_height); - gtk_render_layout (context, cr, x + (year_view->column_width - layout_width) / 2.0, y + (box_side - layout_height) / 2.0, - layout); - - gtk_render_background (context, cr, - x + (year_view->column_width - layout_width) / 2.0, y + (box_side - layout_height) / 2.0, - layout_width, layout_width); - - pango_font_description_free (font_desc); - g_free (str); - gtk_style_context_restore (context); - - /* separator line */ - gtk_style_context_save (context); - gtk_style_context_add_class (context, "lines"); - - gtk_style_context_get_color (context, state_flags, &color); - cairo_set_line_width (cr, 0.2); - gdk_cairo_set_source_rgba (cr, &color); - - cairo_move_to (cr, x + box_side * year_view->show_week_numbers * (1 - year_view->k), y + box_side + 0.4); - cairo_rel_line_to (cr, 7.0 * box_side, 0); - cairo_stroke (cr); - - gtk_style_context_restore (context); - - /* days */ - gtk_style_context_save (context); - gtk_style_context_add_class (context, "days"); - - gtk_style_context_get (context, state_flags, "font", &font_desc, NULL); - pango_layout_set_font_description (layout, font_desc); - - days_delay = (time_day_of_week (1, month_nr, g_date_time_get_year (year_view->date)) - year_view->first_weekday + 7) % 7; - days = days_delay + g_date_get_days_in_month (month_nr + 1, g_date_time_get_year (year_view->date)); - shown_rows = ceil (days / 7.0); - - day = g_date_time_new (gcal_context_get_timezone (year_view->context), - g_date_time_get_year (year_view->date), - month_nr + 1, - 1, 0, 0, 0); - - for (i = 0; i < 7 * shown_rows; i++) + for (month = 0; month < 12; month++) { - g_autoptr (GDateTime) next_day = NULL; + g_autoptr (GDateTime) week_date = NULL; + GDate date; + guint day; + gint days_delay; + gint column; + gint week; + gint row; - column = (i % 7) + (year_view->k || year_view->show_week_numbers); - column_is_workday = is_workday ((7 * year_view->k + sw * (column - (year_view->show_week_numbers * !year_view->k) + (sw * year_view->first_weekday))) % 7); - row = i / 7; + g_date_set_dmy (&date, 1, month + 1, g_date_time_get_year (self->date)); + days_delay = 7 - (7 - ((g_date_get_weekday (&date) % 7) - (self->first_weekday % 7))); - j = 7 * ((i + 7 * year_view->k) / 7) + sw * (i % 7) + (1 - year_view->k); - if (j <= days_delay) - continue; - else if (j > days) - continue; - j -= days_delay; + column = days_delay; + row = 2; - nr_day = g_strdup_printf ("%d", j); - pango_layout_set_text (layout, nr_day, -1); - pango_layout_get_pixel_size (layout, &layout_width, &layout_height); - box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0; - box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0; + /* Week numbers */ + week_date = g_date_time_new_local (g_date_time_get_year (self->date), + month + 1, + 1, 0, 0, 0); - /* Draw the hover background */ - if (year_view->selected_data->hovered_day == j && - year_view->selected_data->hovered_month == month_nr) + for (week = 0; week < 6; week++) { - gint hover_x, hover_y; + g_autoptr (GDateTime) next_week_date = NULL; + GtkWidget *label; + gboolean valid_date; - hover_x = box_side * column + x + box_padding_start / 2.0 - year_view->k * box_side - 2.0; - hover_y = box_side * (row + 1) + y + box_padding_top - 1.0; + valid_date = g_date_valid_dmy (MAX (week * 7 + 1 - days_delay, 1), + month + 1, + g_date_time_get_year (self->date)); - gtk_style_context_set_state (context, state_flags | GTK_STATE_FLAG_PRELIGHT); + label = self->months[month].week_number[week]; + gtk_widget_set_visible (label, valid_date && show_weekdate); - gtk_render_background (context, - cr, - hover_x, - hover_y, - box_side - box_padding_start / 2.0, - box_side); - - gtk_style_context_set_state (context, state_flags); - } - - /* Draw the Drag n' Drop indicator */ - if (year_view->selected_data->dnd_day == j && - year_view->selected_data->dnd_month == month_nr) - { - gint dnd_x, dnd_y; - - dnd_x = box_side * column + x + box_padding_start / 2.0 - year_view->k * box_side - 2.0; - dnd_y = box_side * (row + 1) + y + box_padding_top - 1.0; - - gtk_style_context_save (context); - gtk_style_context_add_class (context, "dnd"); - - gtk_render_background (context, - cr, - dnd_x, - dnd_y, - box_side - box_padding_start / 2.0, - box_side); - - gtk_style_context_restore (context); - } - - selected_day = FALSE; - if (year_view->selected_data->start_day != 0) - { - ButtonData selected_data = *(year_view->selected_data); - order_selected_data (&selected_data); - if (month_nr > selected_data.start_month && month_nr < selected_data.end_month) + if (valid_date) { - selected_day = TRUE; - } - else if (month_nr == selected_data.start_month && month_nr == selected_data.end_month) - { - selected_day = j >= selected_data.start_day && j <= selected_data.end_day; - } - else if (month_nr == selected_data.start_month && j >= selected_data.start_day) - { - selected_day = TRUE; - } - else if (month_nr == selected_data.end_month && j <= selected_data.end_day) - { - selected_day = TRUE; + g_autofree gchar *week_number = NULL; + + week_number = g_strdup_printf ("%d", g_date_time_get_week_of_year (week_date)); + gtk_label_set_label (GTK_LABEL (label), week_number); } + + next_week_date = g_date_time_add_days (week_date, 7); + gcal_set_date_time (&week_date, next_week_date); } - if (g_date_time_get_year (year_view->date) == g_date_time_get_year (now) && - month_nr + 1 == g_date_time_get_month (now) && - j == g_date_time_get_day_of_month (now)) + /* Month days */ + for (day = 0; day < 31; day++) { - PangoLayout *clayout; - PangoFontDescription *cfont_desc; + g_autoptr (GDateTime) day_datetime = NULL; + GtkLayoutManager *layout_manager; + GtkLayoutChild *layout_child; + GtkWidget *label; + gboolean valid_date; + gint weekday; - gtk_style_context_save (context); - gtk_style_context_add_class (context, "current"); + label = self->months[month].day[day]; + valid_date = g_date_valid_dmy (day + 1, month + 1, g_date_time_get_year (self->date)); - clayout = gtk_widget_create_pango_layout (widget, nr_day); - gtk_style_context_get (context, state_flags, "font", &cfont_desc, NULL); - pango_layout_set_font_description (clayout, cfont_desc); - pango_layout_get_pixel_size (clayout, &layout_width, &layout_height); - box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0; - box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0; + gtk_widget_set_visible (label, valid_date); - /* FIXME: hardcoded padding of the number background */ - gtk_render_background (context, cr, - box_side * column + x + sw * box_padding_start - year_view->k * layout_width - 2.0, - box_side * (row + 1) + y + box_padding_top - 1.0, - layout_width + 4.0, layout_height + 2.0); - gtk_render_layout (context, cr, - box_side * column + x + sw * box_padding_start - year_view->k * layout_width, - box_side * (row + 1) + y + box_padding_top, - clayout); + if (!valid_date) + continue; - gtk_style_context_restore (context); - pango_font_description_free (cfont_desc); - g_object_unref (clayout); - } - else if (selected_day) - { - gtk_style_context_set_state (context, state_flags | GTK_STATE_FLAG_SELECTED); + day_datetime = g_date_time_new_local (g_date_time_get_year (self->date), + month + 1, + day + 1, + 0, 0, 0); - pango_layout_set_text (slayout, nr_day, -1); - pango_layout_get_pixel_size (slayout, &layout_width, &layout_height); - box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0; - box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0; + g_date_set_dmy (&date, day + 1, month + 1, g_date_time_get_year (self->date)); + weekday = g_date_get_weekday (&date) % 7; - gtk_render_layout (context, cr, - box_side * column + x + sw * box_padding_start - year_view->k * layout_width, - box_side * (row + 1) + y + box_padding_top, - slayout); + if (!is_workday (weekday)) + gtk_widget_add_css_class (label, "non-workday"); + else + gtk_widget_remove_css_class (label, "non-workday"); - gtk_style_context_set_state (context, state_flags); - } - else if (!column_is_workday) - { - gtk_style_context_save (context); - gtk_style_context_add_class (context, "non-workday"); - gtk_render_layout (context, cr, - box_side * column + x + sw * box_padding_start - year_view->k * layout_width, - box_side * (row + 1) + y + box_padding_top, - layout); - gtk_style_context_restore (context); - } - else - { - gtk_render_layout (context, cr, - box_side * column + x + sw * box_padding_start - year_view->k * layout_width, - box_side * (row + 1) + y + box_padding_top, - layout); - } + if (g_date_time_get_month (now) == month + 1 && + g_date_time_get_day_of_month (now) == day + 1 && + g_date_time_get_year (now) == g_date_time_get_year (self->date)) + gtk_widget_add_css_class (label, "current"); + else + gtk_widget_remove_css_class (label, "current"); - if (count_events_at_day (year_view, day) > 0) - { - gtk_style_context_save (context); - gtk_style_context_add_class (context, "with-events"); + layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self->months[month].grid)); + layout_child = gtk_layout_manager_get_layout_child (layout_manager, label); - if (selected_day) - gtk_style_context_add_class (context, "with-events-selected"); - else if (!column_is_workday) - gtk_style_context_add_class (context, "with-events-non-workday"); + gtk_grid_layout_child_set_column (GTK_GRID_LAYOUT_CHILD (layout_child), column + 1); + gtk_grid_layout_child_set_row (GTK_GRID_LAYOUT_CHILD (layout_child), row); - box_padding_start = MAX (0, (box_side - VISUAL_CLUES_SIDE) / 2); - gtk_render_background (context, cr, - box_side * column + x + sw * box_padding_start - year_view->k * VISUAL_CLUES_SIDE, - box_side * (row + 1) + y + box_padding_top + layout_height + 2.0, - VISUAL_CLUES_SIDE, VISUAL_CLUES_SIDE); - gtk_style_context_restore (context); - } - - /* Update the current day, so we can count the events at this day */ - next_day = g_date_time_add_days (day, 1); - gcal_set_date_time (&day, next_day); - - g_free (nr_day); - } - pango_font_description_free (font_desc); - gtk_style_context_restore (context); - - /* week numbers */ - gtk_style_context_save (context); - gtk_style_context_add_class (context, "week-numbers"); - - gtk_style_context_get (context, state_flags, "font", &font_desc, NULL); - pango_layout_set_font_description (layout, font_desc); - - for (i = 0; i < shown_rows; i++) - { - /* special condition for first and last weeks of the year */ - if (month_nr == 0 && year_view->first_week_of_year > 1 && i == 1) - *weeks_counter = 1; - else if (month_nr == 11 && (i + 1) == shown_rows) - *weeks_counter = year_view->last_week_of_year; - /* other weeks */ - else if (i == 0) - { - if (days_delay == 0 && month_nr != 0) - *weeks_counter = *weeks_counter + 1; - } - else - *weeks_counter = *weeks_counter + 1; - - if (year_view->show_week_numbers) - { - nr_week = g_strdup_printf ("%d", *weeks_counter); - - pango_layout_set_text (layout, nr_week, -1); - pango_layout_get_pixel_size (layout, &layout_width, &layout_height); - box_padding_top = (box_side - layout_height) / 2.0 > 0 ? (box_side - layout_height) / 2.0 : 0; - box_padding_start = (box_side - layout_width) / 2.0 > 0 ? (box_side - layout_width) / 2.0 : 0; - - gtk_render_background (context, cr, - x + sw * box_padding_top + year_view->k * (8 * box_side - layout_height) - WEEK_NUMBER_MARGIN, - box_side * (i + 1) + y + box_padding_top - WEEK_NUMBER_MARGIN, - layout_height + WEEK_NUMBER_MARGIN * 2, layout_height + WEEK_NUMBER_MARGIN * 2); - - gtk_render_layout (context, cr, - x + sw * box_padding_start + year_view->k * (8 * box_side - layout_width), - box_side * (i + 1) + y + box_padding_top, - layout); - - g_free (nr_week); - } - } - gtk_style_context_restore (context); - - pango_font_description_free (sfont_desc); - g_object_unref (slayout); - - pango_font_description_free (font_desc); - g_object_unref (layout); - cairo_restore (cr); -} - -static gboolean -draw_navigator (GcalYearView *year_view, - cairo_t *cr, - GtkWidget *widget) -{ - GtkStyleContext *context; - GtkStateFlags state_flags; - GtkBorder padding; - - gint header_height, layout_width, layout_height; - gint real_padding_left, real_padding_top, i, sw, weeks_counter, number_of_rows; - gdouble width, height; - - gchar *header_str; - - PangoLayout *header_layout; - PangoFontDescription *font_desc; - - context = gtk_widget_get_style_context (widget); - state_flags = gtk_style_context_get_state (context); - sw = 1 - 2 * year_view->k; - width = gtk_widget_get_allocated_width (widget); - number_of_rows = ceil (12.0 / year_view->number_of_columns); - - /* read header from CSS code related to the view */ - gtk_style_context_save (context); - gtk_style_context_add_class (context, "primary-label"); - - header_str = g_strdup_printf ("%d", g_date_time_get_year (year_view->date)); - gtk_style_context_get (context, state_flags, "font", &font_desc, NULL); - gtk_style_context_get_padding (context, state_flags, &padding); - - gtk_style_context_restore (context); - - header_layout = gtk_widget_create_pango_layout (widget, header_str); - pango_layout_set_font_description (header_layout, font_desc); - pango_layout_get_pixel_size (header_layout, &layout_width, &layout_height); - /* XXX: here the color of the text isn't read from year-view but from navigator widget, - * which has the same color on the CSS file */ - gtk_render_layout (context, cr, - year_view->k * (width - layout_width) + sw * padding.left, - padding.top, - header_layout); - - pango_font_description_free (font_desc); - g_object_unref (header_layout); - g_free (header_str); - - header_height = padding.top * 2 + layout_height; - height = gtk_widget_get_allocated_height (widget) - header_height; - - real_padding_left = (width - year_view->column_width * year_view->number_of_columns) / (year_view->number_of_columns + 1); - real_padding_top = (height - year_view->row_height * number_of_rows) / number_of_rows; - - if (real_padding_top < 0) - real_padding_top = 0; - - weeks_counter = year_view->first_week_of_year; - for (i = 0; i < 12; i++) - { - gint row = i / year_view->number_of_columns; - gint column = year_view->k * (year_view->number_of_columns - 1) + sw * (i % year_view->number_of_columns); - - year_view->navigator_grid->coordinates[i].x = (column + 1) * real_padding_left + column * year_view->column_width; - year_view->navigator_grid->coordinates[i].y = row * real_padding_top + row * year_view->row_height + header_height; - draw_month_grid (year_view, widget, cr, i, &weeks_counter); - } - - return FALSE; -} - -static gboolean -navigator_button_press_cb (GcalYearView *year_view, - GdkEventButton *event, - GtkWidget *widget) -{ - gint day, month; - gboolean is_title = FALSE; - - if (!calculate_day_month_for_coord (year_view, event->x, event->y, &day, &month, &is_title)) - return GDK_EVENT_PROPAGATE; - - if (is_title) - day = 1; - - year_view->button_pressed = TRUE; - year_view->selected_data->start_day = day; - year_view->selected_data->start_month = month; - - return GDK_EVENT_PROPAGATE; -} - -static gboolean -navigator_button_release_cb (GcalYearView *year_view, - GdkEventButton *event, - GtkWidget *widget) -{ - g_autoptr (GDateTime) new_date = NULL; - gboolean is_title = FALSE; - gint day, month; - - if (!year_view->button_pressed) - return FALSE; - - if (!calculate_day_month_for_coord (year_view, event->x, event->y, &day, &month, &is_title)) - goto fail; - - if (is_title) - day = g_date_get_days_in_month (month + 1, g_date_time_get_year (year_view->date)); - - year_view->button_pressed = FALSE; - year_view->selected_data->end_day = day; - year_view->selected_data->end_month = month; - - /* update date and notify */ - new_date = g_date_time_new_local (g_date_time_get_year (year_view->date), - month + 1, - day, - 0, 0, 0); - gcal_set_date_time (&year_view->date, new_date); - g_object_notify (G_OBJECT (year_view), "active-date"); - - gtk_widget_queue_draw (widget); - - if (year_view->popover_mode) - { - GdkRectangle rect; - GtkWidget *box; - - /* sizing */ - box = gtk_bin_get_child (GTK_BIN (year_view->popover)); - gtk_widget_set_size_request (box, 200, year_view->navigator_grid->box_side * 2 * 7); - - calculate_coord_for_date (year_view, day, month, is_title, &rect); - gtk_popover_set_pointing_to (GTK_POPOVER (year_view->popover), &rect); - - /* FIXME: do no show over selected days */ - gtk_popover_set_position (GTK_POPOVER (year_view->popover), GTK_POS_RIGHT); - gtk_widget_show (year_view->popover); - } - - update_sidebar (year_view); - return TRUE; - -fail: - year_view->button_pressed = FALSE; - reset_sidebar (year_view); - return TRUE; -} - -static gboolean -navigator_motion_notify_cb (GcalYearView *year_view, - GdkEventMotion *event, - GtkWidget *widget) -{ - gint day = 0, month = 0; - gboolean is_title = FALSE; - - /* Cancel the hover when selecting a date range */ - year_view->selected_data->hovered_day = -1; - year_view->selected_data->hovered_month = -1; - - if (calculate_day_month_for_coord (year_view, event->x, event->y, &day, &month, &is_title)) - { - if (year_view->button_pressed) - { - if (is_title) - day = g_date_get_days_in_month (month + 1, g_date_time_get_year (year_view->date)); - - year_view->selected_data->end_day = day; - year_view->selected_data->end_month = month; - gtk_widget_queue_draw (widget); - - return GDK_EVENT_STOP; - } - else - { - /* We only deal with the hover effect when the button is not pressed */ - year_view->selected_data->hovered_day = day; - year_view->selected_data->hovered_month = month; - gtk_widget_queue_draw (widget); - - return GDK_EVENT_PROPAGATE; + column++; + if (column >= 7) + row++; + column %= 7; } } - gtk_widget_queue_draw (widget); - - return GDK_EVENT_STOP; + GCAL_EXIT; } static void -navigator_edge_overshot_cb (GcalYearView *self, - GtkPositionType position_type) +queue_update_event_indicators (GcalYearView *self) { - g_autoptr (GDateTime) new_date = NULL; - GtkAdjustment *adjustment; - - /* Ignore horizontal scrolling (and the year view never scrolls horizontally anyway) */ - if (position_type == GTK_POS_LEFT || position_type == GTK_POS_RIGHT) + if (self->update_indicators_idle_id > 0) return; - adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (self->scrolled_window)); - - new_date = g_date_time_add_years (self->date, position_type == GTK_POS_BOTTOM ? 1 : -1); - gcal_set_date_time (&self->date, new_date); - - gtk_adjustment_set_value (adjustment, 0.0); - gtk_widget_queue_draw (self->navigator); - - g_object_notify (G_OBJECT (self), "active-date"); + self->update_indicators_idle_id = g_idle_add_full (G_PRIORITY_LOW, + update_event_indicators_in_idle_cb, + self, + NULL); } -static gboolean -navigator_scroll_event_cb (GcalYearView *self, - GdkEventScroll *scroll_event) -{ - GtkWidget *vscrollbar; - - vscrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (self->scrolled_window)); - - /* - * If the vertical scrollbar is visible, delegate the year changing check - * to GtkScrolledWindow:edge-overshot callback. - */ - if (gtk_widget_get_child_visible (vscrollbar)) - return GDK_EVENT_PROPAGATE; - - /* - * If we accumulated enough scrolling, change the month. Otherwise, we'd scroll - * waaay too fast. - */ - if (should_change_date_for_scroll (&self->scroll_value, scroll_event)) - { - g_autoptr (GDateTime) new_date = NULL; - - new_date = g_date_time_add_years (self->date, self->scroll_value > 0 ? 1 : -1); - gcal_set_date_time (&self->date, new_date); - self->scroll_value = 0; - - gtk_widget_queue_draw (self->navigator); - - g_object_notify (G_OBJECT (self), "active-date"); - } - - return GDK_EVENT_STOP; -} - -static void -add_event_clicked_cb (GcalYearView *year_view, - GtkButton *button) -{ - g_autoptr (GDateTime) start_date = NULL; - g_autoptr (GDateTime) end_date = NULL; - - if (year_view->start_selected_date) - { - start_date = g_date_time_new_now_local (); - } - else - { - start_date = g_date_time_ref (year_view->start_selected_date); - end_date = g_date_time_add_days (year_view->end_selected_date, 1); - } - - if (year_view->popover_mode) - gtk_widget_hide (year_view->popover); - - g_signal_emit_by_name (GCAL_VIEW (year_view), "create-event-detailed", start_date, end_date); -} - -static void -popover_closed_cb (GcalYearView *year_view, - GtkPopover *popover) -{ - reset_sidebar (year_view); -} - -static void -calculate_grid_sizes (GcalYearView *self) -{ - /* 1 column for week number and 7 for days */ - if (self->show_week_numbers) - self->column_width = self->navigator_grid->box_side * 8; - else - self->column_width = self->navigator_grid->box_side * 7; - - /* 1 line for month header and 6 lines for weeks */ - self->row_height = self->navigator_grid->box_side * 7; -} - -static void -calculate_sizes (GcalYearView *self) -{ - GtkStyleContext *context; - PangoLayout *layout; - PangoFontDescription *font; - - gint padding_left, padding_right, padding_top, padding_bottom; - gint width, height, box_width, box_height, natural; - gchar *test_str; - - /* get header info from CSS */ - context = gtk_widget_get_style_context (GTK_WIDGET (self)); - gtk_style_context_save (context); - gtk_style_context_add_class (context, "primary-label"); - gtk_style_context_get (context, gtk_style_context_get_state (context), - "padding-top", &padding_top, - "padding-bottom", &padding_bottom, - "font", &font, NULL); - gtk_style_context_restore (context); - - /* measure header height */ - test_str = g_strdup_printf ("8888"); - layout = gtk_widget_create_pango_layout (self->navigator, test_str); - pango_layout_set_font_description (layout, font); - pango_layout_get_pixel_size (layout, &width, &height); - - pango_font_description_free (font); - g_object_unref (layout); - g_free (test_str); - - self->header_height = padding_top + height + padding_bottom; - - /* get day info from CSS */ - context = gtk_widget_get_style_context (GTK_WIDGET (self->navigator)); - gtk_style_context_save (context); - gtk_style_context_add_class (context, "days"); - gtk_style_context_get (context, gtk_style_context_get_state (context), - "padding-left", &padding_left, - "padding-right", &padding_right, - "padding-top", &padding_top, - "padding-bottom", &padding_bottom, - "font", &font, NULL); - gtk_style_context_restore (context); - - /* measure box size */ - test_str = g_strdup_printf ("88"); - layout = gtk_widget_create_pango_layout (self->navigator, test_str); - pango_layout_set_font_description (layout, font); - pango_layout_get_pixel_size (layout, &width, &height); - - pango_font_description_free (font); - g_object_unref (layout); - g_free (test_str); - - box_width = padding_left + width + padding_right; - box_height = padding_top + height + padding_bottom; - - self->navigator_grid->box_side = (box_width > box_height) ? box_width : box_height; - - /* get sidebar width */ - gtk_widget_get_preferred_width (self->sidebar, &width, &natural); - self->sidebar_width = width; - - calculate_grid_sizes (self); -} /* - * Drag and Drop functions + * Callbacks */ -static gboolean -navigator_drag_motion_cb (GcalYearView *self, - GdkDragContext *context, - gint x, - gint y, - guint time, - GtkWidget *navigator) -{ - gint day, month; - gboolean is_title, retval; - - retval = FALSE; - - self->selected_data->dnd_day = -1; - self->selected_data->dnd_month = -1; - - if (calculate_day_month_for_coord (self, x, y, &day, &month, &is_title)) - { - /* For now, don't allow dropping events on the month title */ - if (!is_title) - { - self->selected_data->dnd_day = day; - self->selected_data->dnd_month = month; - - gdk_drag_status (context, GDK_ACTION_MOVE, time); - - retval = TRUE; - } - } - else - { - gdk_drag_status (context, 0, time); - } - - gtk_widget_queue_draw (self->navigator); - - return retval; -} static gboolean -navigator_drag_drop_cb (GcalYearView *self, - GdkDragContext *context, - gint x, - gint y, - guint time, - GtkWidget *navigator) +update_event_indicators_in_idle_cb (gpointer data) { - gint day, month; - gboolean is_title; + GcalYearView *self = GCAL_YEAR_VIEW (data); - if (calculate_day_month_for_coord (self, x, y, &day, &month, &is_title)) - { - if (!GCAL_IS_EVENT_WIDGET (gtk_drag_get_source_widget (context))) - return FALSE; + update_event_indicators (self); - if (!is_title) - { - g_autoptr (GcalEvent) changed_event = NULL; - GcalRecurrenceModType mod; - GcalEventWidget *event_widget; - GcalCalendar *calendar; - GcalEvent *event; - GDateTime *start_dt, *end_dt; - GDateTime *drop_date; - - event_widget = GCAL_EVENT_WIDGET (gtk_drag_get_source_widget (context)); - event = gcal_event_widget_get_event (event_widget); - changed_event = gcal_event_new_from_event (event); - calendar = gcal_event_get_calendar (changed_event); - mod = GCAL_RECURRENCE_MOD_THIS_ONLY; - - if (gcal_event_has_recurrence (changed_event) && - !ask_recurrence_modification_type (GTK_WIDGET (self), &mod, calendar)) - { - goto out; - } - - start_dt = gcal_event_get_date_start (changed_event); - end_dt = gcal_event_get_date_end (changed_event); - - drop_date = g_date_time_add_full (start_dt, - g_date_time_get_year (self->date) - g_date_time_get_year (start_dt), - (month + 1) - g_date_time_get_month (start_dt), - day - g_date_time_get_day_of_month (start_dt), - 0, 0, 0); - - if (!g_date_time_equal (start_dt, drop_date)) - { - GTimeSpan diff = g_date_time_difference (drop_date, start_dt); - GDateTime *new_start; - - new_start = g_date_time_add (start_dt, diff); - gcal_event_set_date_start (changed_event, new_start); - - /* The event may have a NULL end date, so we have to check it here */ - if (end_dt) - { - GDateTime *new_end; - - new_end = g_date_time_add (end_dt, diff); - gcal_event_set_date_end (changed_event, new_end); - - g_clear_pointer (&new_end, g_date_time_unref); - } - - gcal_manager_update_event (gcal_context_get_manager (self->context), - changed_event, - mod); - - g_clear_pointer (&new_start, g_date_time_unref); - } - - g_clear_pointer (&drop_date, g_date_time_unref); - } - } - -out: - /* Cancel the DnD after the event is dropped */ - self->selected_data->dnd_day = -1; - self->selected_data->dnd_month = -1; - - gtk_drag_finish (context, TRUE, FALSE, time); - - gtk_widget_queue_draw (navigator); - - return TRUE; + self->update_indicators_idle_id = 0; + return G_SOURCE_REMOVE; } static void -navigator_drag_leave_cb (GcalYearView *self, - GdkDragContext *context, - guint time, - GtkWidget *navigator) +on_clock_day_changed_cb (GcalClock *clock, + GcalYearView *self) { - /* Cancel the DnD after the event is dropped */ - self->selected_data->dnd_day = -1; - self->selected_data->dnd_month = -1; + GCAL_ENTRY; - gtk_widget_queue_draw (navigator); + update_month_grid (self); + + GCAL_EXIT; } +static void +on_flowbox_child_activated_cb (GtkFlowBox *flowbox, + GtkFlowBoxChild *child, + GcalYearView *self) +{ + g_autoptr (GDateTime) date = NULL; + gint child_index; + + GCAL_ENTRY; + + child_index = gtk_flow_box_child_get_index (child); + date = g_date_time_new_local (g_date_time_get_year (self->date), + child_index + 1, + 1, 0, 0, 0); + + gcal_set_date_time (&self->date, date); + g_object_notify (G_OBJECT (self), "active-date"); + + gtk_widget_activate_action (GTK_WIDGET (self), "win.change-view", "i", 1); + + GCAL_EXIT; +} + +static void +on_show_weekdate_changed_cb (GSettings *settings, + gchar *key, + GcalYearView *self) +{ + GCAL_ENTRY; + + update_weekday_widgets (self); + + GCAL_EXIT; +} + + /* * GcalTimelineSubscriber implementation */ @@ -1593,38 +480,15 @@ gcal_year_view_add_event (GcalTimelineSubscriber *subscriber, GcalEvent *event) { GcalYearView *self; - GDateTime *event_start; - GDateTime *event_end; - guint start_month; - guint end_month; - guint i; GCAL_ENTRY; self = GCAL_YEAR_VIEW (subscriber); g_debug ("Caching event '%s' in Year view", gcal_event_get_uid (event)); + gcal_range_tree_add_range (self->events, gcal_event_get_range (event), g_object_ref (event)); - event_start = gcal_event_get_date_start (event); - event_end = gcal_event_get_date_end (event); - - /* Calculate the start & end months */ - start_month = g_date_time_get_month (event_start) - 1; - end_month = g_date_time_get_month (event_end) - 1; - - if (g_date_time_get_year (event_start) < g_date_time_get_year (self->date)) - start_month = 0; - - if (g_date_time_get_year (event_end) > g_date_time_get_year (self->date)) - end_month = 11; - - /* Add the event to the cache */ - for (i = start_month; i <= end_month; i++) - g_ptr_array_add (self->events[i], g_object_ref (event)); - - update_sidebar (self); - - gtk_widget_queue_draw (GTK_WIDGET (self->navigator)); + queue_update_event_indicators (self); GCAL_EXIT; } @@ -1633,68 +497,16 @@ static void gcal_year_view_remove_event (GcalTimelineSubscriber *subscriber, GcalEvent *event) { - g_autoptr (GList) children = NULL; GcalYearView *self; - GList *l; - const gchar *event_id; - guint n_children; - guint i; GCAL_ENTRY; self = GCAL_YEAR_VIEW (subscriber); - event_id = gcal_event_get_uid (event); - n_children = 0; - children = gtk_container_get_children (GTK_CONTAINER (self->events_sidebar)); + g_debug ("Removing event '%s' from Year view's cache", gcal_event_get_uid (event)); + gcal_range_tree_remove_range (self->events, gcal_event_get_range (event), event); - for (l = children; l != NULL; l = g_list_next (l)) - { - GcalEventWidget *child_widget; - GcalEvent *list_event; - - child_widget = GCAL_EVENT_WIDGET (gtk_bin_get_child (GTK_BIN (l->data))); - list_event = gcal_event_widget_get_event (child_widget); - - if (g_strcmp0 (event_id, gcal_event_get_uid (list_event)) == 0) - gtk_widget_destroy (GTK_WIDGET (l->data)); - else - n_children++; - } - - /* - * No children left visible, all the events were removed and now we have to show the - * 'No Events' placeholder. - */ - if (n_children == 0) - { - update_no_events_page (self); - gtk_stack_set_visible_child_name (GTK_STACK (self->navigator_stack), "no-events"); - } - - /* Also remove from the cached list of events */ - for (i = 0; i < 12; i++) - { - GPtrArray *events; - guint j; - - events = self->events[i]; - - for (j = 0; j < events->len; j++) - { - GcalEvent *cached_event; - - cached_event = g_ptr_array_index (events, j); - - if (!g_str_equal (gcal_event_get_uid (cached_event), event_id)) - continue; - - g_debug ("Removing event '%s' from Year view's cache", event_id); - g_ptr_array_remove (events, event); - } - } - - gtk_widget_queue_draw (GTK_WIDGET (self->navigator)); + queue_update_event_indicators (self); GCAL_EXIT; } @@ -1708,7 +520,6 @@ gcal_year_view_update_event (GcalTimelineSubscriber *subscriber, gcal_year_view_remove_event (subscriber, event); gcal_year_view_add_event (subscriber, event); - GCAL_EXIT; } @@ -1722,7 +533,10 @@ gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface) } -/* GcalView implementation */ +/* + * GcalView interface + */ + static GDateTime* gcal_year_view_get_date (GcalView *view) { @@ -1737,35 +551,22 @@ gcal_year_view_set_date (GcalView *view, { GcalYearView *self; gboolean year_changed; - gboolean needs_reset; GCAL_ENTRY; self = GCAL_YEAR_VIEW (view); - needs_reset = self->date && - self->start_selected_date && - !g_date_time_equal (self->date, date); - year_changed = !self->date || g_date_time_get_year (self->date) != g_date_time_get_year (date); gcal_set_date_time (&self->date, date); - self->first_week_of_year = get_last_week_of_year_dmy (self->first_weekday, - 1, - G_DATE_JANUARY, - g_date_time_get_year (self->date)); - self->last_week_of_year = get_last_week_of_year_dmy (self->first_weekday, - 31, - G_DATE_DECEMBER, - g_date_time_get_year (self->date)); - - if (needs_reset) - reset_sidebar (self); - if (year_changed) gcal_timeline_subscriber_range_changed (GCAL_TIMELINE_SUBSCRIBER (view)); + update_weekday_widgets (self); + update_month_grid (self); + update_year_label (self); + GCAL_EXIT; } @@ -1774,17 +575,7 @@ gcal_year_view_get_children_by_uuid (GcalView *view, GcalRecurrenceModType mod, const gchar *uuid) { - GcalYearView *self = GCAL_YEAR_VIEW (view); - GList *result, *children; - - result = NULL; - - children = gtk_container_get_children (GTK_CONTAINER (self->sidebar)); - result = filter_event_list_by_uid_and_modtype (children, mod, uuid); - - g_list_free (children); - - return result; + return NULL; } static GDateTime* @@ -1820,20 +611,11 @@ static void gcal_year_view_finalize (GObject *object) { GcalYearView *year_view = GCAL_YEAR_VIEW (object); - guint i; - g_free (year_view->navigator_grid); - g_free (year_view->selected_data); - - g_clear_pointer (&year_view->start_selected_date, g_date_time_unref); - g_clear_pointer (&year_view->end_selected_date, g_date_time_unref); g_clear_pointer (&year_view->date, g_date_time_unref); - + g_clear_pointer (&year_view->events, gcal_range_tree_unref); g_clear_object (&year_view->calendar_settings); - for (i = 0; i < 12; i++) - g_clear_pointer (&year_view->events[i], g_ptr_array_unref); - G_OBJECT_CLASS (gcal_year_view_parent_class)->finalize (object); } @@ -1855,10 +637,6 @@ gcal_year_view_get_property (GObject *object, g_value_set_object (value, self->context); break; - case PROP_SHOW_WEEK_NUMBERS: - g_value_set_boolean (value, self->show_week_numbers); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -1884,26 +662,9 @@ gcal_year_view_set_property (GObject *object, g_signal_connect_object (gcal_context_get_clock (self->context), "day-changed", - G_CALLBACK (gtk_widget_queue_draw), + G_CALLBACK (on_clock_day_changed_cb), self, G_CONNECT_SWAPPED); - - g_signal_connect_object (gcal_context_get_weather_service (self->context), - "weather-changed", - G_CALLBACK (weather_changed), - self, - 0); - update_weather (self); - break; - - case PROP_SHOW_WEEK_NUMBERS: - if (self->show_week_numbers != g_value_get_boolean (value)) - { - self->show_week_numbers = g_value_get_boolean (value); - calculate_grid_sizes (self); - g_object_notify (object, "show-week-numbers"); - gtk_widget_queue_allocate (GTK_WIDGET (self)); - } break; default: @@ -1911,108 +672,6 @@ gcal_year_view_set_property (GObject *object, } } -static void -gcal_year_view_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - GcalYearView *year_view = GCAL_YEAR_VIEW (widget); - GtkStyleContext *context; - gint padding_left, padding_right, hpadding; - - context = gtk_widget_get_style_context (year_view->navigator); - - gtk_style_context_get (context, - gtk_style_context_get_state (context), - "padding-left", &padding_left, - "padding-right", &padding_right, NULL); - - hpadding = padding_left + padding_right; - if (minimum != NULL) - *minimum = hpadding + year_view->column_width; - if (natural != NULL) - *natural = hpadding + year_view->column_width + year_view->sidebar_width; -} - -static void -gcal_year_view_size_allocate (GtkWidget *widget, - GtkAllocation *alloc) -{ - GcalYearView *year_view = GCAL_YEAR_VIEW (widget); - GtkStyleContext *context; - gint padding_left, padding_right, padding_top, padding_bottom, hpadding, vpadding; - gint number_of_rows; - - context = gtk_widget_get_style_context (widget); - gtk_style_context_save (context); - gtk_style_context_add_class (context, "year-navigator"); - gtk_style_context_get (context, - gtk_style_context_get_state (context), - "padding-left", &padding_left, - "padding-right", &padding_right, - "padding-top", &padding_top, - "padding-bottom", &padding_bottom, NULL); - gtk_style_context_restore (context); - - hpadding = padding_left + padding_right; - vpadding = padding_top + padding_bottom; - - year_view->popover_mode = (alloc->width < (hpadding + year_view->column_width * 2 + year_view->sidebar_width)); - - year_view->number_of_columns = (alloc->width - hpadding - year_view->sidebar_width * !year_view->popover_mode) / year_view->column_width; - - if (year_view->number_of_columns > NAVIGATOR_MAX_GRID_SIZE) - year_view->number_of_columns = NAVIGATOR_MAX_GRID_SIZE; - - number_of_rows = ceil (12.0 / year_view->number_of_columns); - - gtk_widget_set_size_request (year_view->navigator, - hpadding + year_view->column_width * year_view->number_of_columns, - vpadding + year_view->row_height * number_of_rows + year_view->header_height); - - if (year_view->popover_mode && !gtk_widget_is_ancestor (year_view->events_sidebar, year_view->popover)) - { - g_object_ref (year_view->sidebar); - - gtk_container_remove (GTK_CONTAINER (widget), year_view->sidebar); - gtk_container_add (GTK_CONTAINER (year_view->popover), year_view->sidebar); - - g_object_unref (year_view->sidebar); - - gtk_widget_show_all (year_view->sidebar); - popover_closed_cb (GCAL_YEAR_VIEW (widget), GTK_POPOVER (year_view->popover)); - } - else if (!year_view->popover_mode && gtk_widget_is_ancestor (year_view->events_sidebar, year_view->popover)) - { - g_object_ref (year_view->sidebar); - - gtk_container_remove (GTK_CONTAINER (year_view->popover), year_view->sidebar); - gtk_box_pack_end (GTK_BOX (widget), year_view->sidebar, FALSE, TRUE, 0); - - g_object_unref (year_view->sidebar); - - gtk_widget_show (year_view->sidebar); - g_signal_handlers_block_by_func (year_view->popover, popover_closed_cb, widget); - gtk_widget_hide (year_view->popover); - g_signal_handlers_unblock_by_func (year_view->popover, popover_closed_cb, widget); - } - - GTK_WIDGET_CLASS (gcal_year_view_parent_class)->size_allocate (widget, alloc); -} - -static void -gcal_year_view_direction_changed (GtkWidget *widget, - GtkTextDirection previous_direction) -{ - GcalYearView *year_view = GCAL_YEAR_VIEW (widget); - - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) - year_view->k = 0; - else if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - year_view->k = 1; -} - - static void gcal_year_view_class_init (GcalYearViewClass *klass) { @@ -2023,45 +682,15 @@ gcal_year_view_class_init (GcalYearViewClass *klass) object_class->get_property = gcal_year_view_get_property; object_class->set_property = gcal_year_view_set_property; - widget_class->get_preferred_width = gcal_year_view_get_preferred_width; - widget_class->size_allocate = gcal_year_view_size_allocate; - widget_class->direction_changed = gcal_year_view_direction_changed; - g_object_class_override_property (object_class, PROP_DATE, "active-date"); g_object_class_override_property (object_class, PROP_CONTEXT, "context"); - g_object_class_install_property (object_class, - PROP_SHOW_WEEK_NUMBERS, - g_param_spec_boolean ("show-week-numbers", - "Show Week Numbers", - "Show Week Numbers Column", - FALSE, - G_PARAM_READWRITE)); - gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/views/gcal-year-view.ui"); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, navigator); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, sidebar); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, events_sidebar); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, navigator_stack); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, navigator_sidebar); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, no_events_title); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, popover); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, scrolled_window); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, temp_label); - gtk_widget_class_bind_template_child (widget_class, GcalYearView, weather_icon); + gtk_widget_class_bind_template_child (widget_class, GcalYearView, flowbox); + gtk_widget_class_bind_template_child (widget_class, GcalYearView, year_label); - gtk_widget_class_bind_template_callback (widget_class, draw_navigator); - gtk_widget_class_bind_template_callback (widget_class, navigator_button_press_cb); - gtk_widget_class_bind_template_callback (widget_class, navigator_button_release_cb); - gtk_widget_class_bind_template_callback (widget_class, navigator_drag_drop_cb); - gtk_widget_class_bind_template_callback (widget_class, navigator_drag_leave_cb); - gtk_widget_class_bind_template_callback (widget_class, navigator_drag_motion_cb); - gtk_widget_class_bind_template_callback (widget_class, navigator_edge_overshot_cb); - gtk_widget_class_bind_template_callback (widget_class, navigator_motion_notify_cb); - gtk_widget_class_bind_template_callback (widget_class, navigator_scroll_event_cb); - gtk_widget_class_bind_template_callback (widget_class, add_event_clicked_cb); - gtk_widget_class_bind_template_callback (widget_class, popover_closed_cb); + gtk_widget_class_bind_template_callback (widget_class, on_flowbox_child_activated_cb); gtk_widget_class_set_css_name (widget_class, "calendar-view"); } @@ -2071,94 +700,15 @@ gcal_year_view_init (GcalYearView *self) { guint i; - for (i = 0; i < 12; i++) - self->events[i] = g_ptr_array_new_with_free_func (g_object_unref); - gtk_widget_init_template (GTK_WIDGET (self)); - if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR) - self->k = 0; - else if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL) - self->k = 1; - self->first_weekday = get_first_weekday (); - - self->navigator_grid = g_new0 (GridData, 1); - self->selected_data = g_new0 (ButtonData, 1); + self->events = gcal_range_tree_new_with_free_func (g_object_unref); /* bind GNOME Shell' show week numbers property to GNOME Calendar's one */ self->calendar_settings = g_settings_new ("org.gnome.desktop.calendar"); - g_settings_bind (self->calendar_settings, "show-weekdate", self, "show-week-numbers", G_SETTINGS_BIND_DEFAULT); - g_signal_connect_object (self->calendar_settings, "changed::show-weekdate", G_CALLBACK (gtk_widget_queue_draw), self, G_CONNECT_SWAPPED); + g_signal_connect (self->calendar_settings, "changed::show-weekdate", G_CALLBACK (on_show_weekdate_changed_cb), self); - /* layout */ - self->number_of_columns = 4; - calculate_sizes (self); - - gtk_list_box_set_header_func (GTK_LIST_BOX (self->events_sidebar), update_sidebar_headers, self, NULL); - gtk_list_box_set_sort_func (GTK_LIST_BOX (self->events_sidebar), sidebar_sort_func, NULL, NULL); - - /* The year navigator is a DnD destination */ - gtk_drag_dest_set (self->navigator, - 0, - NULL, - 0, - GDK_ACTION_MOVE); + for (i = 0; i < 12; i++) + init_month_data (self, i, &self->months[i]); } - - -static void -update_weather (GcalYearView *self) -{ - GcalWeatherService *weather_service; - gboolean updated = FALSE; - - g_return_if_fail (GCAL_IS_YEAR_VIEW (self)); - - weather_service = gcal_context_get_weather_service (self->context); - - if (self->date) - { - GPtrArray *weather_infos; - GDate date; - guint i; - - g_date_set_dmy (&date, - g_date_time_get_day_of_month (self->date), - g_date_time_get_month (self->date), - g_date_time_get_year (self->date)); - - weather_infos = gcal_weather_service_get_weather_infos (weather_service); - - for (i = 0; weather_infos && i < weather_infos->len; i++) - { - GcalWeatherInfo *info; - GDate wdate; - - info = g_ptr_array_index (weather_infos, i); - - gcal_weather_info_get_date (info, &wdate); - - if (g_date_compare (&date, &wdate) == 0) - { - const gchar *temp_str; /* unowned */ - const gchar *icon_nm; /* unowned */ - - temp_str = gcal_weather_info_get_temperature (info); - icon_nm = gcal_weather_info_get_icon_name (info); - - gtk_label_set_text (self->temp_label, temp_str); - gtk_image_set_from_icon_name (self->weather_icon, icon_nm, GTK_ICON_SIZE_SMALL_TOOLBAR); - updated = TRUE; - break; - } - } - } - - if (!updated) - { - gtk_label_set_text (self->temp_label, ""); - gtk_image_clear (self->weather_icon); - } -} - diff --git a/src/gui/views/gcal-year-view.ui b/src/gui/views/gcal-year-view.ui index 6dc8328d..a32d1b2e 100644 --- a/src/gui/views/gcal-year-view.ui +++ b/src/gui/views/gcal-year-view.ui @@ -1,172 +1,68 @@ - - - navigator - - - diff --git a/src/theme/Adwaita.css b/src/theme/Adwaita.css index 31cf12fe..334ce01a 100644 --- a/src/theme/Adwaita.css +++ b/src/theme/Adwaita.css @@ -37,130 +37,56 @@ calendar-view:selected { } /* Year View CSS */ -.year-view { - padding: 0px; + +.year-navigator grid.month { + padding: 12px; } -/* Header the padding if for sizing, on drawing the spacing between cells, - * and the padding will be automatically calculated - * Because of year-view widget internals, the color property should be the same - * of .start-header selector */ -.year-navigator { - padding: 12px; - color: @theme_selected_bg_color; -} - -.year-navigator.header { - color: @theme_selected_bg_color; - font-weight: bold; -} - -.year-navigator.lines { - color: alpha(@theme_fg_color, 0.4); -} - -.year-navigator.days { +.year-navigator label.days { padding: 5px; color: @theme_fg_color; font-size: 9pt; + min-width: 18px; + min-height: 18px; } -.year-navigator.non-workday { +.year-navigator label.non-workday { color: alpha(@theme_fg_color, 0.5); } -.year-navigator.week-numbers { - font-size: 70%; - font-weight: bold; - border-radius: 2px; +.year-navigator label.week-number { + font-size: 0.5rem; + border-radius: 50%; background-color: alpha(@theme_fg_color, 0.05); color: alpha(@theme_fg_color, 0.4); + min-width: 18px; + min-height: 18px; } -/* these two are supposed be changed in sync with .calendar-view */ -.year-navigator.current { - background-color: black; - border-radius: 2px; - color: white; - font-weight: bold; -} -.year-navigator:selected { - color: @theme_selected_bg_color; +.year-navigator .current label { + color: @accent_fg_color; + background-color: @accent_bg_color; + border-radius: 50%; font-weight: bold; } -.year-navigator:hover { - background-color: alpha(@theme_fg_color, 0.1); - border-radius: 2px; -} - -.year-navigator.dnd { - border: solid 1px #4e9a06; - box-shadow: inset 0 0 0 1px #4e9a06; -} - -.year-navigator.with-events { +.year-navigator dot { + transform: translateX(-1px) translateY(-3px); background-color: @theme_fg_color; border-radius: 3px; + min-width: 3px; + min-height: 3px; } -.year-navigator.with-events-selected { - background-color: @theme_selected_bg_color; +.year-navigator .current dot { + background-color: @accent_fg_color; } -.year-navigator.with-events-non-workday { + +.year-navigator .non-workday dot { background-color: alpha(@theme_fg_color, 0.5); } -.sidebar-header { - font-weight: bold; - font-size: 11pt; -} - -.italic-label { - font-style: italic; -} - -.year-view .sidebar { - padding: 4px; - border: 1px none @borders; -} - -.year-view .sidebar:backdrop { - border-color: @unfocused_borders; -} - -.year-view .sidebar:dir(ltr) { - border-left-style: solid; -} -.year-view .sidebar:dir(rtl) { - border-right-style: solid; -} - -/* no events label */ -.year-view box.sidebar label:nth-child(2) { - margin-top: 4px; -} - -.year-view button { - border-radius: 0; - border-bottom-style: none; -} - -.year-view button:dir(ltr) { - border-right-style: none; -} - -.year-view button:dir(rtl) { - border-left-style: none; -} - - -.year-view scrolledwindow { - border-top-width: 0; - border-bottom-width: 0; -} - popover.events { background-color: @theme_bg_color; padding: 0;