common/date-chooser: Jump to first day of month on button press

Encode the day in the combined choice value and use the callbacks
introduced in the previous commit to always jump to the first day
of the month when the next/previous month buttons are clicked.

Closes: https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/1103
Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/369>
This commit is contained in:
Fabian Hügel
2026-02-21 20:22:34 -05:00
committed by Hari Rana
parent 8af5298e50
commit 66a8c6b7ab
2 changed files with 96 additions and 23 deletions
+4 -2
View File
@@ -41,8 +41,10 @@ template $GcalDateChooser: Adw.Bin {
$GcalMultiChoice combined_choice {
visible: bind $get_combined_choice_visible(template.show-heading, template.split-month-year) as <bool>;
halign: fill;
min-value: 12;
max-value: 119999;
// From January 1st, 1 (32 * (1 * 12 + 0) + 0):
min-value: 384;
// …to December 31st, 9999 (32 * (9999×12+11) + 30):
max-value: 3839998;
popover: popover;
animate: false;
value: 0;
+92 -21
View File
@@ -131,6 +131,70 @@ get_split_choice_visible (gpointer user_data,
return show_heading && split_month_year;
}
static void
decode_combined_choice_value (gint value,
gint *year,
gint *month,
gint *day)
{
gint y, m, d, ym;
d = value % 32 + 1;
ym = value / 32;
y = ym / 12;
m = ym % 12 + 1;
g_assert (g_date_valid_dmy (d, m, y));
if (year)
*year = y;
if (month)
*month = m;
if (day)
*day = d;
}
static gint
encode_combined_choice_value (gint year,
gint month,
gint day)
{
g_assert (g_date_valid_dmy (day, month, year));
return (year * 12 + month - 1) * 32 + day - 1;
}
static gint
compute_prev_combined_choice_value (gint value)
{
gint year, month;
decode_combined_choice_value (value, &year, &month, NULL);
if (--month < 1)
{
month = 12;
year--;
}
return encode_combined_choice_value (year, month, 1);
}
static gint
compute_next_combined_choice_value (gint value)
{
gint year, month;
decode_combined_choice_value (value, &year, &month, NULL);
if (++month > 12)
{
month = 1;
year++;
}
return encode_combined_choice_value (year, month, 1);
}
static gboolean
leap (guint year)
{
@@ -342,13 +406,12 @@ format_month_year (GcalMultiChoice *choice,
g_autoptr (GDateTime) now = g_date_time_new_now (g_date_time_get_timezone (self->date));
gint year, month;
year = value / 12;
month = value % 12;
decode_combined_choice_value (value, &year, &month, NULL);
if (g_date_time_get_year (now) == year)
return g_strdup (gcal_get_month_name (month));
return g_strdup (gcal_get_month_name (month - 1));
else
return g_strdup_printf ("%s %d", gcal_get_month_name (month), year);
return g_strdup_printf ("%s %d", gcal_get_month_name (month - 1), year);
}
static void
@@ -515,11 +578,14 @@ gcal_date_chooser_set_date (GcalView *view,
gcal_set_date_time (&self->date, date);
if (y1 != y2 || m1 != m2 || d1 != d2)
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->combined_choice),
encode_combined_choice_value (y2, m2, d2));
if (y1 != y2 || m1 != m2)
{
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->year_choice), y2);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->month_choice), m2 - 1);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->combined_choice), y2 * 12 + m2 - 1);
calendar_compute_days (self);
gcal_timeline_subscriber_range_changed (GCAL_TIMELINE_SUBSCRIBER (self));
}
@@ -753,15 +819,10 @@ calendar_get_property (GObject *obj,
static void
multi_choice_changed (GcalDateChooser *self,
gint year,
gint month)
gint month,
gint day)
{
g_autoptr (GDateTime) date = NULL;
gint day;
day = g_date_time_get_day_of_month (self->date);
/* Make sure the day is valid at that month */
day = MIN (day, month_length[leap (year)][month]);
date = g_date_time_new_local (year, month, day, 0, 0, 0);
gcal_date_chooser_set_date (GCAL_VIEW (self), date);
@@ -770,23 +831,28 @@ multi_choice_changed (GcalDateChooser *self,
static void
combined_multi_choice_changed (GcalDateChooser *self)
{
gint year, month;
gint year, month, day, value;
year = gcal_multi_choice_get_value (GCAL_MULTI_CHOICE (self->combined_choice)) / 12;
month = gcal_multi_choice_get_value (GCAL_MULTI_CHOICE (self->combined_choice)) % 12 + 1;
value = gcal_multi_choice_get_value (GCAL_MULTI_CHOICE (self->combined_choice));
decode_combined_choice_value (value, &year, &month, &day);
multi_choice_changed (self, year, month);
multi_choice_changed (self, year, month, day);
}
static void
split_multi_choice_changed (GcalDateChooser *self)
{
gint year, month;
gint year, month, day;
year = gcal_multi_choice_get_value (GCAL_MULTI_CHOICE (self->year_choice));
month = gcal_multi_choice_get_value (GCAL_MULTI_CHOICE (self->month_choice)) + 1;
multi_choice_changed (self, year, month);
day = g_date_time_get_day_of_month (self->date);
/* Make sure the day is valid at that month */
day = MIN (day, month_length[leap (year)][month]);
multi_choice_changed (self, year, month, day);
}
static gboolean
@@ -1017,7 +1083,7 @@ gcal_date_chooser_init (GcalDateChooser *self)
GtkDropTarget *drop_target;
GtkWidget *label;
gint row, col;
gint year, month;
gint year, month, day;
GtkLayoutManager *layout_manager;
self->show_heading = TRUE;
@@ -1145,12 +1211,17 @@ gcal_date_chooser_init (GcalDateChooser *self)
calendar_init_weekday_display (self);
calendar_compute_days (self);
g_date_time_get_ymd (self->date, &year, &month, NULL);
g_date_time_get_ymd (self->date, &year, &month, &day);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->year_choice), year);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->month_choice), month - 1);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->combined_choice), year * 12 + month - 1);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->combined_choice),
encode_combined_choice_value (year, month, day));
calendar_update_selected_day_display (self);
gcal_multi_choice_set_value_callbacks (GCAL_MULTI_CHOICE (self->combined_choice),
compute_prev_combined_choice_value,
compute_next_combined_choice_value);
drop_target = gtk_drop_target_new (G_TYPE_STRING, GDK_ACTION_COPY);
gtk_drop_target_set_preload (drop_target, TRUE);
g_signal_connect (drop_target, "drop", G_CALLBACK (on_drop_target_drop_cb), NULL);