gui/event-editor: Rework calendars menu

Use a GtkListBox and bind from the model. Create rows from the model
items, and bind properties as needed.

The action target is set only when the calendar is writable because
setting an invalid action+target pair makes the row insensitive.

Remove the ancient menu icon hack.
This commit is contained in:
Georges Basile Stavracas Neto
2024-03-01 00:39:42 -03:00
parent 2c33d98d82
commit cbe89a9daa
4 changed files with 90 additions and 146 deletions
+70 -71
View File
@@ -50,6 +50,7 @@ struct _GcalEventEditorDialog
{
AdwDialog parent;
GtkListBox *calendars_listbox;
GtkWidget *cancel_button;
GtkWidget *delete_button;
GtkWidget *done_button;
@@ -58,7 +59,6 @@ struct _GcalEventEditorDialog
GcalEventEditorSection *reminders_section;
GcalEventEditorSection *schedule_section;
GtkWidget *sources_button;
GtkPopoverMenu *sources_popover;
GtkWidget *source_image;
GtkWidget *source_label;
GtkWidget *subtitle_label;
@@ -110,73 +110,6 @@ static GParamSpec* properties[N_PROPS] = { NULL, };
* Auxiliary methods
*/
static gint
sources_menu_sort_func (gconstpointer a,
gconstpointer b)
{
GcalCalendar *calendar1, *calendar2;
calendar1 = GCAL_CALENDAR ((gpointer) a);
calendar2 = GCAL_CALENDAR ((gpointer) b);
return g_ascii_strcasecmp (gcal_calendar_get_name (calendar1),
gcal_calendar_get_name (calendar2));
}
static void
fill_sources_menu (GcalEventEditorDialog *self)
{
g_autoptr (GList) list = NULL;
GcalManager *manager;
GList *aux;
if (self->context == NULL)
return;
manager = gcal_context_get_manager (self->context);
list = gcal_manager_get_calendars (manager);
self->sources_menu = g_menu_new ();
list = g_list_sort (list, sources_menu_sort_func);
for (aux = list; aux != NULL; aux = aux->next)
{
g_autoptr (GdkPaintable) paintable = NULL;
g_autoptr (GMenuItem) item = NULL;
g_autoptr (GdkPixbuf) pix = NULL;
g_autoptr (GVariant) target = NULL;
GcalCalendar *calendar;
const GdkRGBA *color;
calendar = GCAL_CALENDAR (aux->data);
/* retrieve color */
color = gcal_calendar_get_color (calendar);
paintable = get_circle_paintable_from_color (color, 16);
pix = paintable_to_pixbuf (paintable);
/* menu item */
item = g_menu_item_new (gcal_calendar_get_name (calendar), "select-calendar");
g_menu_item_set_icon (item, G_ICON (pix));
/* set insensitive for read-only calendars */
if (!gcal_calendar_is_read_only (calendar))
target = g_variant_new_string (gcal_calendar_get_id (calendar));
g_menu_item_set_action_and_target_value (item,
"event-editor-dialog.select-calendar",
g_steal_pointer (&target));
g_menu_append_item (self->sources_menu, item);
}
gtk_popover_menu_set_menu_model (self->sources_popover,
G_MENU_MODEL (self->sources_menu));
/* HACK: show the popover menu icons */
fix_popover_menu_icons (GTK_POPOVER (self->sources_popover));
}
static void
set_writable (GcalEventEditorDialog *self,
gboolean writable)
@@ -256,6 +189,73 @@ apply_event_properties_to_template_event (GcalEvent *template_event,
gcal_event_set_date_end (template_event, end_date);
}
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 GtkWidget *
create_row_func (gpointer data,
gpointer user_data)
{
GcalCalendar *calendar = (GcalCalendar *) data;
GtkWidget *label;
GtkWidget *icon;
GtkWidget *row;
GtkWidget *box;
g_assert (GCAL_IS_CALENDAR (calendar));
row = gtk_list_box_row_new ();
gtk_actionable_set_action_name (GTK_ACTIONABLE (row), "event-editor-dialog.select-calendar");
if (!gcal_calendar_is_read_only (calendar))
gtk_actionable_set_action_target (GTK_ACTIONABLE (row), "s", gcal_calendar_get_id (calendar));
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
icon = gtk_image_new ();
gtk_widget_add_css_class (icon, "calendar-color-image");
g_object_bind_property_full (data, "color",
icon, "paintable",
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE,
paintable_from_gdk_rgb,
NULL,
NULL,
NULL);
gtk_box_append (GTK_BOX (box), icon);
label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
g_object_bind_property (data, "name", label, "label", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
gtk_box_append (GTK_BOX (box), label);
return row;
}
static void
setup_context (GcalEventEditorDialog *self)
{
GcalManager *manager;
GListModel *calendars;
GCAL_ENTRY;
manager = gcal_context_get_manager (self->context);
calendars = gcal_manager_get_calendars_model (manager);
gtk_list_box_bind_model (self->calendars_listbox, calendars, create_row_func, self, NULL);
GCAL_EXIT;
}
/*
* Callbacks
@@ -581,6 +581,7 @@ gcal_event_editor_dialog_set_property (GObject *object,
case PROP_CONTEXT:
g_assert (self->context == NULL);
self->context = g_value_dup_object (value);
setup_context (self);
g_object_notify_by_pspec (object, properties[PROP_CONTEXT]);
break;
@@ -654,6 +655,7 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/event-editor/gcal-event-editor-dialog.ui");
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, calendars_listbox);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, cancel_button);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, delete_button);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, done_button);
@@ -662,7 +664,6 @@ gcal_event_editor_dialog_class_init (GcalEventEditorDialogClass *klass)
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, reminders_section);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, schedule_section);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, sources_button);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, sources_popover);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, source_image);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, subtitle_label);
gtk_widget_class_bind_template_child (widget_class, GcalEventEditorDialog, summary_section);
@@ -758,8 +759,6 @@ gcal_event_editor_dialog_set_event (GcalEventEditorDialog *self,
if (self->sources_menu != NULL)
g_menu_remove_all (self->sources_menu);
fill_sources_menu (self);
/* dialog titlebar's title & subtitle */
paintable = get_circle_paintable_from_color (gcal_event_get_color (cloned_event), 10);
gtk_image_set_from_paintable (GTK_IMAGE (self->source_image), paintable);
@@ -24,7 +24,26 @@
</child>
<child type="title">
<object class="GtkMenuButton" id="sources_button">
<property name="popover">sources_popover</property>
<property name="popover">
<object class="GtkPopover">
<style>
<class name="menu" />
</style>
<child>
<object class="GtkScrolledWindow">
<property name="propagate-natural-height">True</property>
<property name="width-request">250</property>
<property name="max-content-height">600</property>
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkListBox" id="calendars_listbox">
<property name="selection-mode">none</property>
</object>
</child>
</object>
</child>
</object>
</property>
<property name="sensitive" bind-source="GcalEventEditorDialog" bind-property="writable" bind-flags="default|sync-create" />
<property name="tooltip-text" translatable="yes">Select Calendar</property>
<style>
@@ -171,8 +190,6 @@
</object>
</child>
</template>
<object class="GtkPopoverMenu" id="sources_popover">
</object>
<object class="GtkSizeGroup">
<property name="mode">vertical</property>
<widgets>
-69
View File
@@ -659,75 +659,6 @@ e_utf8_strftime_fix_am_pm (gchar *str,
return sz;
}
/**
* fix_popover_menu_icons:
* @window: a #GtkPopover
*
* Hackish code that inspects the popover's children,
* retrieve the hidden GtkImage buried under lots of
* widgets, and make it visible again.
*
* Hopefully, we'll find a better way to do this in
* the long run.
*
*/
void
fix_popover_menu_icons (GtkPopover *popover)
{
GtkWidget *popover_stack;
GtkWidget *menu_section;
GtkWidget *menu_section_box;
GtkWidget *widget;
GtkWidget *child;
/* GtkScrolledWindow */
widget = gtk_popover_get_child (GTK_POPOVER (popover));
/* GtkViewport */
widget = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (widget));
/* GtkStack */
popover_stack = gtk_viewport_get_child (GTK_VIEWPORT (widget));
menu_section = gtk_widget_get_first_child (popover_stack);
/**
* Get the unique box's children.
*/
menu_section_box = gtk_widget_get_first_child (menu_section);
gtk_widget_add_css_class (menu_section_box, "calendars-list");
/**
* Iterate through the GtkModelButtons inside the menu section box.
*/
for (child = gtk_widget_get_first_child (menu_section_box);
child;
child = gtk_widget_get_next_sibling (child))
{
GtkWidget *child2;
/**
* Since there is no guarantee that the first child is
* the GtkImage we're looking for, we have to iterate
* through the children and check if the types match.
*/
for (child2 = gtk_widget_get_first_child (child);
child2;
child2 = gtk_widget_get_next_sibling (child2))
{
if (GTK_IS_IMAGE (child2))
{
gtk_widget_add_css_class (child2, "calendar-color-image");
gtk_widget_set_margin_end (child2, 12);
gtk_widget_set_visible (child2, TRUE);
break;
}
}
}
}
/**
* get_source_parent_name_color:
* @manager: a #GcalManager
-3
View File
@@ -94,9 +94,6 @@ gsize e_utf8_strftime_fix_am_pm (gchar
const gchar *fmt,
const struct tm *tm);
void fix_popover_menu_icons (GtkPopover *popover);
void get_source_parent_name_color (GcalManager *manager,
ESource *source,
gchar **name,