diff --git a/src/gui/gcal-calendar-combo-row-item.c b/src/gui/gcal-calendar-combo-row-item.c new file mode 100644 index 00000000..2dd52b4b --- /dev/null +++ b/src/gui/gcal-calendar-combo-row-item.c @@ -0,0 +1,189 @@ +/* gcal-calendar-combo-row-item.c + * + * Copyright 2024 Diego Iván M.E + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "GcalCalendarComboRowItem" + +#include "config.h" +#include "gcal-calendar-combo-row-item.h" +#include "gcal-debug.h" +#include "gcal-utils.h" + +#include + +struct _GcalCalendarComboRowItem +{ + AdwActionRow parent; + + GtkImage *color_image; + GtkImage *visibility_image; + GcalCalendar *calendar; +}; + +G_DEFINE_TYPE (GcalCalendarComboRowItem, gcal_calendar_combo_row_item, ADW_TYPE_PREFERENCES_ROW) + +enum +{ + PROP_0, + PROP_CALENDAR, + N_PROPS, +}; + +static GParamSpec *properties [N_PROPS] = { NULL, }; + +static gboolean +paintable_from_gdk_rgb (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + GdkRGBA *rgba = g_value_get_boxed (from_value); + g_value_take_object (to_value, get_circle_paintable_from_color (rgba, 16)); + return TRUE; +} + +static void +updated_visibility_cb (GcalCalendarComboRowItem *self) +{ + g_autofree gchar *accessible_description = NULL; + + GCAL_ENTRY; + gtk_widget_set_visible (GTK_WIDGET (self->visibility_image), !gcal_calendar_get_visible (self->calendar)); + + if (!gcal_calendar_get_visible (self->calendar)) + accessible_description = g_strdup (_("This calendar is hidden")); + + gtk_accessible_update_property (GTK_ACCESSIBLE (self), + GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, accessible_description, -1); + GCAL_EXIT; +} + +static void +set_calendar (GcalCalendarComboRowItem *self, + GcalCalendar *calendar) +{ + g_return_if_fail (GCAL_IS_CALENDAR (calendar)); + g_set_object (&self->calendar, calendar); + + g_object_bind_property_full (self->calendar, "color", + self->color_image, "paintable", + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE, + paintable_from_gdk_rgb, + NULL, + NULL, + NULL); + g_signal_connect_object (self->calendar, + "notify::visible", (GCallback) updated_visibility_cb, + self, G_CONNECT_SWAPPED); + + g_object_bind_property (calendar, "name", self, "title", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); + + updated_visibility_cb (self); +} + +/* + * GObject overrides + */ + +static void +gcal_calendar_combo_row_item_finalize (GObject *object) +{ + GcalCalendarComboRowItem *self = (GcalCalendarComboRowItem *)object; + + g_clear_object (&self->calendar); + + G_OBJECT_CLASS (gcal_calendar_combo_row_item_parent_class)->finalize (object); +} + +static void +gcal_calendar_combo_row_item_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GcalCalendarComboRowItem *self = GCAL_CALENDAR_COMBO_ROW_ITEM (object); + + switch (prop_id) + { + case PROP_CALENDAR: + g_value_set_object (value, self->calendar); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_calendar_combo_row_item_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GcalCalendarComboRowItem *self = GCAL_CALENDAR_COMBO_ROW_ITEM (object); + + switch (prop_id) + { + case PROP_CALENDAR: + g_assert (self->calendar == NULL); + set_calendar (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_calendar_combo_row_item_class_init (GcalCalendarComboRowItemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = gcal_calendar_combo_row_item_finalize; + object_class->get_property = gcal_calendar_combo_row_item_get_property; + object_class->set_property = gcal_calendar_combo_row_item_set_property; + + properties[PROP_CALENDAR] = g_param_spec_object ("calendar", + "Calendar", + "Calendar", + GCAL_TYPE_CALENDAR, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/gui/gcal-calendar-combo-row-item.ui"); + + gtk_widget_class_bind_template_child (widget_class, GcalCalendarComboRowItem, color_image); + gtk_widget_class_bind_template_child (widget_class, GcalCalendarComboRowItem, visibility_image); +} + +static void +gcal_calendar_combo_row_item_init (GcalCalendarComboRowItem *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +GtkWidget* +gcal_calendar_combo_row_item_new (GcalCalendar *calendar) +{ + return g_object_new (GCAL_TYPE_CALENDAR_COMBO_ROW_ITEM, + "calendar", calendar, + NULL); +} diff --git a/src/gui/gcal-calendar-combo-row-item.h b/src/gui/gcal-calendar-combo-row-item.h new file mode 100644 index 00000000..bf7ccf1e --- /dev/null +++ b/src/gui/gcal-calendar-combo-row-item.h @@ -0,0 +1,33 @@ +/* gcal-calendar-combo-row-item.h + * + * Copyright 2024 Diego Iván M.E + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "gcal-calendar.h" +G_BEGIN_DECLS + +#define GCAL_TYPE_CALENDAR_COMBO_ROW_ITEM (gcal_calendar_combo_row_item_get_type()) + +G_DECLARE_FINAL_TYPE (GcalCalendarComboRowItem, gcal_calendar_combo_row_item, GCAL, CALENDAR_COMBO_ROW_ITEM, AdwPreferencesRow) + +GtkWidget* gcal_calendar_combo_row_item_new (GcalCalendar *calendar); + +G_END_DECLS diff --git a/src/gui/gcal-calendar-combo-row-item.ui b/src/gui/gcal-calendar-combo-row-item.ui new file mode 100644 index 00000000..7499529d --- /dev/null +++ b/src/gui/gcal-calendar-combo-row-item.ui @@ -0,0 +1,32 @@ + + + + diff --git a/src/gui/gcal-calendar-combo-row.c b/src/gui/gcal-calendar-combo-row.c new file mode 100644 index 00000000..61d65f14 --- /dev/null +++ b/src/gui/gcal-calendar-combo-row.c @@ -0,0 +1,262 @@ +/* gcal-calendar-combo-row.c + * + * Copyright (C) 2024 Titouan Real + * + * gnome-calendar is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gnome-calendar is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#define G_LOG_DOMAIN "GcalCalendarComboRow" + +#include "gcal-calendar-combo-row.h" +#include "gcal-calendar-combo-row-item.h" + +#include +#include +#include +#include + +struct _GcalCalendarComboRow +{ + AdwComboRow parent; +}; + +G_DEFINE_TYPE (GcalCalendarComboRow, gcal_calendar_combo_row, ADW_TYPE_COMBO_ROW); + +enum +{ + PROP_0, + PROP_CALENDAR, + N_PROPS +}; + +static GParamSpec* properties[N_PROPS] = { NULL, }; + + +/* + * Callbacks + */ + +static void +on_calendar_selected_cb (AdwComboRow *row, + GParamSpec *pspec, + GtkListItem *item) +{ + GtkWidget *checkmark = g_object_get_data (G_OBJECT (item), "checkmark"); + + if (adw_combo_row_get_selected_item (row) == gtk_list_item_get_item (item)) + gtk_widget_set_opacity (checkmark, 1); + else + gtk_widget_set_opacity (checkmark, 0); +} + +static void +calendar_item_setup_cb (GtkSignalListItemFactory *factory, + GtkListItem *item) +{ + GtkWidget *box, *checkmark; + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + + checkmark = g_object_new (GTK_TYPE_IMAGE, + "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION, + "icon-name", "object-select-symbolic", + NULL); + gtk_box_append (GTK_BOX (box), checkmark); + + g_object_set_data (G_OBJECT (item), "box", box); + g_object_set_data (G_OBJECT (item), "checkmark", checkmark); + + gtk_list_item_set_child (item, box); +} + +static void +calendar_item_bind_cb (GtkSignalListItemFactory *factory, + GtkListItem *item, + GcalCalendarComboRow *self) +{ + AdwComboRow *row = ADW_COMBO_ROW (self); + GtkWidget *box, *calendar_row, *checkmark; + GcalCalendar *data; + GtkWidget *popup; + + data = gtk_list_item_get_item (item); + + box = g_object_get_data (G_OBJECT (item), "box"); + checkmark = g_object_get_data (G_OBJECT (item), "checkmark"); + + calendar_row = gcal_calendar_combo_row_item_new (data); + + gtk_box_insert_child_after (GTK_BOX (box), calendar_row, NULL); + + popup = gtk_widget_get_ancestor (box, GTK_TYPE_POPOVER); + if (popup && gtk_widget_is_ancestor (popup, GTK_WIDGET (row))) + { + gtk_box_set_spacing (GTK_BOX (box), 0); + gtk_widget_set_visible (checkmark, TRUE); + g_signal_connect (row, "notify::selected-item", G_CALLBACK (on_calendar_selected_cb), item); + on_calendar_selected_cb (row, NULL, item); + } + else + { + gtk_box_set_spacing (GTK_BOX (box), 6); + gtk_widget_set_visible (checkmark, FALSE); + } + +} + +static void +calendar_item_unbind_cb (GtkSignalListItemFactory *factory, + GtkListItem *item, + GcalCalendarComboRow *self) +{ + AdwComboRow *row = ADW_COMBO_ROW (self); + + g_signal_handlers_disconnect_by_func (row, on_calendar_selected_cb, item); +} + + +/* + * GObject overrides + */ + +static void +gcal_calendar_combo_row_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GcalCalendarComboRow *self = GCAL_CALENDAR_COMBO_ROW (object); + + switch (prop_id) + { + case PROP_CALENDAR: + g_value_set_object (value, GCAL_CALENDAR (adw_combo_row_get_selected_item (ADW_COMBO_ROW (self)))); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_calendar_combo_row_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GcalCalendarComboRow *self = GCAL_CALENDAR_COMBO_ROW (object); + + switch (prop_id) + { + case PROP_CALENDAR: + gcal_calendar_combo_row_set_calendar (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_calendar_combo_row_class_init (GcalCalendarComboRowClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gcal_calendar_combo_row_get_property; + object_class->set_property = gcal_calendar_combo_row_set_property; + + /** + * GcalCalendarComboRow::calendar: + * + * The selected calendar of the combo row. + */ + properties[PROP_CALENDAR] = g_param_spec_object ("calendar", + "Calendar of the combo row", + "The selected calendar from the combo row", + GCAL_TYPE_CALENDAR, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/gui/gcal-calendar-combo-row.ui"); + + gtk_widget_class_bind_template_callback (widget_class, calendar_item_setup_cb); + gtk_widget_class_bind_template_callback (widget_class, calendar_item_bind_cb); + gtk_widget_class_bind_template_callback (widget_class, calendar_item_unbind_cb); +} + +static void +gcal_calendar_combo_row_init (GcalCalendarComboRow *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +/** + * gcal_calendar_combo_row_new: + * + * Creates a new `CalendarComboRow`. + * + * Returns: the newly created `CalendarComboRow` + */ +GtkWidget* +gcal_calendar_combo_row_new (void) +{ + return g_object_new (GCAL_TYPE_CALENDAR_COMBO_ROW, NULL); +} + +/** + * gcal_calendar_combo_row_set_calendar: + * @self: a #GcalCalendarComboRow + * @calendar: a valid #GcalCalendar + * + * Sets the selected calendar. + */ +void +gcal_calendar_combo_row_set_calendar (GcalCalendarComboRow *self, + GcalCalendar *calendar) +{ + GListModel *model; + + g_return_if_fail (GCAL_IS_CALENDAR_COMBO_ROW (self)); + + model = adw_combo_row_get_model (ADW_COMBO_ROW (self)); + + if (model == NULL) + return; + + for (guint i = 0; i < g_list_model_get_n_items (model); i++) + { + if (g_list_model_get_item (model, i) == calendar) + adw_combo_row_set_selected (ADW_COMBO_ROW (self), i); + } + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CALENDAR]); +} + +/** + * gcal_calendar_combo_row_get_calendar: + * @self: a #GcalCalendarComboRow + * + * Gets the selected calendar. + * + * Returns: (nullable) (transfer none): The selected calendar + */ +GcalCalendar* +gcal_calendar_combo_row_get_calendar (GcalCalendarComboRow *self) +{ + g_return_val_if_fail (GCAL_IS_CALENDAR_COMBO_ROW (self), NULL); + + return adw_combo_row_get_selected_item (ADW_COMBO_ROW (self)); +} diff --git a/src/gui/gcal-calendar-combo-row.h b/src/gui/gcal-calendar-combo-row.h new file mode 100644 index 00000000..79cb272c --- /dev/null +++ b/src/gui/gcal-calendar-combo-row.h @@ -0,0 +1,38 @@ +/* gcal-calendar-combo-row.h + * + * Copyright (C) 2024 Titouan Real + * + * gnome-calendar is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gnome-calendar is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#pragma once + +#include + +#include "gcal-calendar.h" + +G_BEGIN_DECLS + +#define GCAL_TYPE_CALENDAR_COMBO_ROW (gcal_calendar_combo_row_get_type ()) + +G_DECLARE_FINAL_TYPE (GcalCalendarComboRow, gcal_calendar_combo_row, GCAL, CALENDAR_COMBO_ROW, AdwComboRow) + +GtkWidget* gcal_calendar_combo_row_new (void); + +GcalCalendar* gcal_calendar_combo_row_get_calendar (GcalCalendarComboRow *self); + +void gcal_calendar_combo_row_set_calendar (GcalCalendarComboRow *self, + GcalCalendar *calendar); + +G_END_DECLS diff --git a/src/gui/gcal-calendar-combo-row.ui b/src/gui/gcal-calendar-combo-row.ui new file mode 100644 index 00000000..5794f443 --- /dev/null +++ b/src/gui/gcal-calendar-combo-row.ui @@ -0,0 +1,16 @@ + + + + diff --git a/src/gui/gui.gresource.xml b/src/gui/gui.gresource.xml index 1abfeff8..1eb6437c 100644 --- a/src/gui/gui.gresource.xml +++ b/src/gui/gui.gresource.xml @@ -2,6 +2,8 @@ gcal-calendar-button.ui + gcal-calendar-combo-row.ui + gcal-calendar-combo-row-item.ui gcal-event-popover.ui gcal-event-widget.ui gcal-meeting-row.ui diff --git a/src/gui/meson.build b/src/gui/meson.build index 55599ef3..9cb5cc0c 100644 --- a/src/gui/meson.build +++ b/src/gui/meson.build @@ -16,6 +16,8 @@ built_sources += gnome.compile_resources( sources += files( 'gcal-application.c', 'gcal-calendar-button.c', + 'gcal-calendar-combo-row.c', + 'gcal-calendar-combo-row-item.c', 'gcal-drop-overlay.c', 'gcal-event-popover.c', 'gcal-event-widget.c',