diff --git a/data/theme/gtk-styles.css b/data/theme/gtk-styles.css index 96d6bcc4..017b621b 100644 --- a/data/theme/gtk-styles.css +++ b/data/theme/gtk-styles.css @@ -223,3 +223,7 @@ GcalEventWidget.color-light:backdrop { background-color: @theme_base_color; } +/* calendar popover */ +.calendar-list { + background-color: rgba(0, 0, 0, 0); +} diff --git a/data/ui/window.ui b/data/ui/window.ui index dbcccf23..13c0b6fe 100644 --- a/data/ui/window.ui +++ b/data/ui/window.ui @@ -333,6 +333,77 @@ False + False + 6 + + + True + False + vertical + 6 + + + True + False + True + True + none + + + + False + True + 0 + + + + + True + True + none + True + + + True + False + 12 + + + True + False + list-add-symbolic + + + False + True + 0 + + + + + True + False + Add Calendar… + + + False + True + 1 + + + + + + + False + True + 1 + + + + False diff --git a/src/gcal-window.c b/src/gcal-window.c index 2467ce0d..43cafd09 100644 --- a/src/gcal-window.c +++ b/src/gcal-window.c @@ -109,10 +109,12 @@ typedef struct /* calendar management */ GtkWidget *calendar_popover; - GMenu *calendar_menu; + GtkWidget *calendar_listbox; gint refresh_timeout; gint refresh_timeout_id; + GHashTable *calendar_source_to_row; + /* temp to keep event_creation */ gboolean open_edit_dialog; } GcalWindowPrivate; @@ -185,12 +187,15 @@ static void add_source (GcalManager *m gboolean enabled, gpointer user_data); +static GtkWidget* make_row_for_source (GcalWindow *window, + ESource *source); + static void remove_source (GcalManager *manager, ESource *source, gpointer user_data); -static void on_calendar_toggled (GSimpleAction *action, - GVariant *value, +static void on_calendar_toggled (GObject *object, + GParamSpec *pspec, gpointer user_data); static gboolean refresh_sources (GcalWindow *window); @@ -763,38 +768,69 @@ add_source (GcalManager *manager, gpointer user_data) { GcalWindowPrivate *priv; - - GdkRGBA color; - GdkPixbuf *pix; - GMenuItem *item; - GSimpleAction *action; - - gchar *item_name; + GtkWidget *row; priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data)); + row = make_row_for_source (GCAL_WINDOW (user_data), source); - /* create the action itself */ - action = g_simple_action_new_stateful (e_source_get_uid (source), NULL, g_variant_new_boolean (enabled)); - g_signal_connect (action, "change-state", G_CALLBACK (on_calendar_toggled), user_data); - g_action_map_add_action (G_ACTION_MAP (user_data), G_ACTION (action)); + /* add to the hash */ + g_hash_table_insert (priv->calendar_source_to_row, source, row); - /* retrieve the source's color & build item name */ - item_name = g_strdup_printf ("%s", e_source_get_uid (source)); - get_color_name_from_source (source, &color); - pix = gcal_get_pixbuf_from_color (&color, 16); + gtk_container_add (GTK_CONTAINER (priv->calendar_listbox), row); +} - /* create the menu item */ - item = g_menu_item_new (e_source_get_display_name (source), item_name); - g_menu_item_set_attribute_value (item, "uid", g_variant_new_string (e_source_get_uid (source))); - g_menu_item_set_icon (item, G_ICON (pix)); - g_menu_append_item (priv->calendar_menu, item); +/** + * make_row_for_source: + * + * Create a GtkListBoxRow for a given + * ESource. + * + * Returns: (transfer full) the new row + */ +static GtkWidget* +make_row_for_source (GcalWindow *window, + ESource *source) +{ + GcalWindowPrivate *priv = gcal_window_get_instance_private (window); + GtkWidget *label, *icon, *separator, *checkbox, *box, *row; + GdkPixbuf *pixbuf; + GdkRGBA color; - /* HACK: show images of the popover menu */ - fix_popover_menu_icons (GTK_POPOVER (priv->calendar_popover)); + row = gtk_list_box_row_new (); - g_object_unref (pix); - g_object_unref (item); - g_free (item_name); + /* main box */ + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_container_set_border_width (GTK_CONTAINER (box), 6); + + /* source color icon */ + gdk_rgba_parse (&color, get_color_name_from_source (source)); + pixbuf = gcal_get_pixbuf_from_color (&color, 16); + icon = gtk_image_new_from_pixbuf (pixbuf); + + /* source name label */ + label = gtk_label_new (e_source_get_display_name (source)); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_widget_set_hexpand (label, TRUE); + + /* vertical separator */ + separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL); + + /* checkbox */ + checkbox = gtk_check_button_new (); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), gcal_manager_source_enabled (priv->manager, source)); + g_signal_connect (checkbox, "notify::active", G_CALLBACK (on_calendar_toggled), window); + + gtk_container_add (GTK_CONTAINER (box), icon); + gtk_container_add (GTK_CONTAINER (box), label); + gtk_container_add (GTK_CONTAINER (box), separator); + gtk_container_add (GTK_CONTAINER (box), checkbox); + gtk_container_add (GTK_CONTAINER (row), box); + + gtk_widget_show_all (row); + + g_object_unref (pixbuf); + + return row; } static void @@ -802,89 +838,51 @@ remove_source (GcalManager *manager, ESource *source, gpointer user_data) { - GcalWindowPrivate *priv; - gboolean source_found; - gint n_items; - gint i; + GcalWindowPrivate *priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data)); - priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data)); - n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->calendar_menu)); - source_found = FALSE; - - for (i = 0; i < n_items; i++) - { - GMenuAttributeIter *iter; - - iter = g_menu_model_iterate_item_attributes (G_MENU_MODEL (priv->calendar_menu), i); - - /* look for 'uid' attribute */ - while (g_menu_attribute_iter_next (iter)) - { - if (g_strcmp0 (g_menu_attribute_iter_get_name (iter), "uid") == 0) - { - GVariant *uid; - uid = g_menu_attribute_iter_get_value (iter); - - /* if we find the item with uid == source::uid, remove it */ - if (g_strcmp0 (g_variant_get_string (uid, NULL), e_source_get_uid (source)) == 0) - { - g_menu_remove (priv->calendar_menu, i); - source_found = TRUE; - break; - } - } - } - - g_object_unref (iter); - - if (source_found) - break; - } - - /* remove the action */ - g_action_map_remove_action (G_ACTION_MAP (user_data), e_source_get_uid (source)); + /** + * Since a destroyer function was + * defined, simply removing the + * source will call gtk_widget_destroy + * on the row, which will remove it + * from the listbox. + */ + g_hash_table_remove (priv->calendar_source_to_row, source); } static void -on_calendar_toggled (GSimpleAction *action, - GVariant *value, - gpointer user_data) +on_calendar_toggled (GObject *object, + GParamSpec *pspec, + gpointer user_data) { - GcalWindowPrivate *priv; - ESource *source; - GList *l; - GList *aux; + GcalWindowPrivate *priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data)); + gboolean active; + GtkWidget *row; + GList *l, *aux; - priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data)); - - /* lookup source */ - source = NULL; - l = gcal_manager_get_sources_connected (priv->manager); + row = gtk_widget_get_parent (gtk_widget_get_parent (GTK_WIDGET (object))); + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object)); + l = g_hash_table_get_keys (priv->calendar_source_to_row); for (aux = l; aux != NULL; aux = aux->next) { - ESource *tmp; - tmp = (ESource *) aux->data; + GtkWidget *current_row; - if (g_strcmp0 (e_source_get_uid (tmp), g_action_get_name (G_ACTION (action))) == 0) + current_row = g_hash_table_lookup (priv->calendar_source_to_row, aux->data); + + /* Enable/disable the toggled calendar */ + if (current_row == row) { - source = tmp; + if (active) + gcal_manager_enable_source (priv->manager, E_SOURCE (aux->data)); + else + gcal_manager_disable_source (priv->manager, E_SOURCE (aux->data)); + break; } } g_list_free (l); - - if (source == NULL) - return; - - /* toggle source visibility */ - if (g_variant_get_boolean (value)) - gcal_manager_enable_source (priv->manager, source); - else - gcal_manager_disable_source (priv->manager, source); - - g_simple_action_set_state (action, value); } static gboolean @@ -1288,6 +1286,7 @@ gcal_window_class_init(GcalWindowClass *klass) gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, search_bar); gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, search_button); gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, calendars_button); + gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, calendar_listbox); gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, calendar_popover); gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, search_entry); gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, back_button); @@ -1386,10 +1385,6 @@ gcal_window_constructed (GObject *object) g_object_unref (builder); - /* calendar menu */ - priv->calendar_menu = g_menu_new (); - gtk_popover_bind_model (GTK_POPOVER (priv->calendar_popover), G_MENU_MODEL (priv->calendar_menu), "win"); - /* edit dialog initialization */ priv->edit_dialog = gcal_edit_dialog_new (use_24h_format); gtk_window_set_transient_for (GTK_WINDOW (priv->edit_dialog), GTK_WINDOW (object)); @@ -1404,6 +1399,10 @@ gcal_window_constructed (GObject *object) g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->search_bar)), "notify::child-revealed", G_CALLBACK (search_bar_revealer_toggled), object); + /* calendars menu */ + priv->calendar_source_to_row = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, + (GDestroyNotify) gtk_widget_destroy); + /* XXX: Week view disabled until after the release when we restart the work on it*/ //priv->views[GCAL_WINDOW_VIEW_WEEK] = gcal_week_view_new (); //gcal_week_view_set_manager (GCAL_WEEK_VIEW (priv->views[GCAL_WINDOW_VIEW_WEEK]), priv->manager);