[libpanel/wip/chergert/fix-14] save-dialog: implement save dialog visuals
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpanel/wip/chergert/fix-14] save-dialog: implement save dialog visuals
- Date: Tue, 13 Sep 2022 15:00:38 +0000 (UTC)
commit 73b7c859e360bd85992f9818312ed96784077532
Author: Christian Hergert <chergert redhat com>
Date: Tue Sep 13 08:00:31 2022 -0700
save-dialog: implement save dialog visuals
This still doesn't pump the save delegates, but it does start to implement
the bits that are relevant for the mockups with how drafts are handled, as
well as 1 vs N documents.
I had to shove the list in a preferences page so that we could scroll in
case things get too large.
Additionally, the button visiblity is a total hack, and we probably want
proper API for that in libaddwaita directly.
po/POTFILES.in | 1 +
src/panel-save-dialog-row-private.h | 12 ++-
src/panel-save-dialog-row.c | 53 +++++++++-
src/panel-save-dialog-row.ui | 6 +-
src/panel-save-dialog.c | 193 +++++++++++++++++++++++++++++++++++-
src/panel-save-dialog.ui | 8 +-
6 files changed, 254 insertions(+), 19 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a013c11..e26cda6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,6 +2,7 @@ src/panel-frame-header-bar.c
src/panel-frame-header-bar.ui
src/panel-frame.ui
src/panel-maximized-controls.c
+src/panel-save-dialog-row.c
src/panel-save-dialog.c
src/panel-save-dialog.ui
src/panel-signal-group.c
diff --git a/src/panel-save-dialog-row-private.h b/src/panel-save-dialog-row-private.h
index f6f31db..71e0086 100644
--- a/src/panel-save-dialog-row-private.h
+++ b/src/panel-save-dialog-row-private.h
@@ -30,10 +30,12 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (PanelSaveDialogRow, panel_save_dialog_row, PANEL, SAVE_DIALOG_ROW, AdwActionRow)
-GtkWidget *panel_save_dialog_row_new (PanelSaveDelegate *delegate);
-PanelSaveDelegate *panel_save_dialog_row_get_delegate (PanelSaveDialogRow *self);
-gboolean panel_save_dialog_row_get_selected (PanelSaveDialogRow *self);
-void panel_save_dialog_row_set_selected (PanelSaveDialogRow *self,
- gboolean selected);
+GtkWidget *panel_save_dialog_row_new (PanelSaveDelegate *delegate);
+PanelSaveDelegate *panel_save_dialog_row_get_delegate (PanelSaveDialogRow *self);
+gboolean panel_save_dialog_row_get_selected (PanelSaveDialogRow *self);
+void panel_save_dialog_row_set_selected (PanelSaveDialogRow *self,
+ gboolean selected);
+void panel_save_dialog_row_set_selection_mode (PanelSaveDialogRow *self,
+ gboolean selection_mode);
G_END_DECLS
diff --git a/src/panel-save-dialog-row.c b/src/panel-save-dialog-row.c
index d8afcc2..a8d0192 100644
--- a/src/panel-save-dialog-row.c
+++ b/src/panel-save-dialog-row.c
@@ -20,6 +20,8 @@
#include "config.h"
+#include <glib/gi18n.h>
+
#include "panel-save-delegate.h"
#include "panel-save-dialog-row-private.h"
@@ -54,6 +56,46 @@ on_notify_active_cb (PanelSaveDialogRow *self,
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTED]);
}
+static gboolean
+map_title_with_draft (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ PanelSaveDelegate *delegate = user_data;
+ const char *str;
+
+ g_assert (G_IS_BINDING (binding));
+ g_assert (PANEL_IS_SAVE_DELEGATE (delegate));
+
+ if ((str = g_value_get_string (from_value)))
+ {
+ if (panel_save_delegate_get_is_draft (delegate))
+ g_value_take_string (to_value,
+ g_strdup_printf ("%s <span fgalpha='32767'>%s</span>",
+ str, _("(new)")));
+ else
+ g_value_set_string (to_value, str);
+ }
+
+ return TRUE;
+}
+
+static void
+panel_save_dialog_row_set_delegate (PanelSaveDialogRow *self,
+ PanelSaveDelegate *delegate)
+{
+ g_assert (PANEL_IS_SAVE_DIALOG_ROW (self));
+ g_assert (PANEL_IS_SAVE_DELEGATE (delegate));
+ g_assert (self->delegate == NULL);
+
+ g_set_object (&self->delegate, delegate);
+ g_object_bind_property_full (delegate, "title", self, "title",
+ G_BINDING_SYNC_CREATE,
+ map_title_with_draft, NULL,
+ delegate, NULL);
+}
+
static void
panel_save_dialog_row_dispose (GObject *object)
{
@@ -94,7 +136,7 @@ panel_save_dialog_row_set_property (GObject *object,
switch (prop_id)
{
case PROP_DELEGATE:
- self->delegate = g_value_dup_object (value);
+ panel_save_dialog_row_set_delegate (self, g_value_get_object (value));
break;
default:
@@ -173,3 +215,12 @@ panel_save_dialog_row_set_selected (PanelSaveDialogRow *self,
gtk_check_button_set_active (self->check, selected);
}
+
+void
+panel_save_dialog_row_set_selection_mode (PanelSaveDialogRow *self,
+ gboolean selection_mode)
+{
+ g_return_if_fail (PANEL_IS_SAVE_DIALOG_ROW (self));
+
+ gtk_widget_set_visible (GTK_WIDGET (self->check), selection_mode);
+}
diff --git a/src/panel-save-dialog-row.ui b/src/panel-save-dialog-row.ui
index 4a08073..d3eb8ab 100644
--- a/src/panel-save-dialog-row.ui
+++ b/src/panel-save-dialog-row.ui
@@ -1,11 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="PanelSaveDialogRow" parent="AdwActionRow">
- <binding name="title">
- <lookup name="title" type="PanelSaveDelegate">
- <lookup name="delegate">PanelSaveDialogRow</lookup>
- </lookup>
- </binding>
<binding name="subtitle">
<lookup name="subtitle" type="PanelSaveDelegate">
<lookup name="delegate">PanelSaveDialogRow</lookup>
@@ -18,5 +13,6 @@
<signal name="notify::active" handler="on_notify_active_cb" swapped="true"
object="PanelSaveDialogRow"/>
</object>
</child>
+ <property name="activatable-widget">check</property>
</template>
</interface>
diff --git a/src/panel-save-dialog.c b/src/panel-save-dialog.c
index 0137e93..39398dc 100644
--- a/src/panel-save-dialog.c
+++ b/src/panel-save-dialog.c
@@ -31,9 +31,10 @@
struct _PanelSaveDialog
{
AdwMessageDialog parent_instance;
+ GPtrArray *rows;
+ AdwPreferencesPage *page;
AdwPreferencesGroup *group;
GTask *task;
- guint count;
};
G_DEFINE_FINAL_TYPE (PanelSaveDialog, panel_save_dialog, ADW_TYPE_MESSAGE_DIALOG)
@@ -105,14 +106,71 @@ panel_save_dialog_response_save_cb (PanelSaveDialog *self,
g_clear_object (&task);
}
+static void
+find_button_and_set_visible (GtkWidget *parent,
+ const char *label,
+ gboolean visible)
+{
+ for (GtkWidget *child = gtk_widget_get_first_child (parent);
+ child != NULL;
+ child = gtk_widget_get_next_sibling (child))
+ {
+ if (GTK_IS_BUTTON (child) &&
+ g_strcmp0 (label, gtk_button_get_label (GTK_BUTTON (child))) == 0)
+ {
+ gtk_widget_set_visible (child, visible);
+ break;
+ }
+ }
+}
+
+static void
+set_response_visible (AdwMessageDialog *dialog,
+ const char *response,
+ gboolean visible)
+{
+ const char *label;
+ GObject *wide;
+ GObject *narrow;
+
+ g_assert (ADW_IS_MESSAGE_DIALOG (dialog));
+ g_assert (response != NULL);
+ g_assert (adw_message_dialog_has_response (dialog, response));
+
+ adw_message_dialog_set_response_enabled (dialog, response, visible);
+
+ if (!(label = adw_message_dialog_get_response_label (dialog, response)))
+ return;
+
+ wide = gtk_widget_get_template_child (GTK_WIDGET (dialog), ADW_TYPE_MESSAGE_DIALOG, "wide_response_box");
+ narrow = gtk_widget_get_template_child (GTK_WIDGET (dialog), ADW_TYPE_MESSAGE_DIALOG,
"narrow_response_box");
+
+ find_button_and_set_visible (GTK_WIDGET (wide), label, visible);
+ find_button_and_set_visible (GTK_WIDGET (narrow), label, visible);
+}
+
+static void
+panel_save_dialog_dispose (GObject *object)
+{
+ PanelSaveDialog *self = (PanelSaveDialog *)object;
+
+ g_clear_pointer (&self->rows, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (panel_save_dialog_parent_class)->dispose (object);
+}
+
static void
panel_save_dialog_class_init (PanelSaveDialogClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ object_class->dispose = panel_save_dialog_dispose;
+
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/libpanel/panel-save-dialog.ui");
gtk_widget_class_bind_template_child (widget_class, PanelSaveDialog, group);
+ gtk_widget_class_bind_template_child (widget_class, PanelSaveDialog, page);
gtk_widget_class_bind_template_callback (widget_class, panel_save_dialog_response_cancel_cb);
gtk_widget_class_bind_template_callback (widget_class, panel_save_dialog_response_discard_cb);
@@ -122,20 +180,145 @@ panel_save_dialog_class_init (PanelSaveDialogClass *klass)
static void
panel_save_dialog_init (PanelSaveDialog *self)
{
+ self->rows = g_ptr_array_new ();
+
gtk_widget_init_template (GTK_WIDGET (self));
}
+static void
+panel_save_dialog_update (PanelSaveDialog *self)
+{
+ g_assert (PANEL_IS_SAVE_DIALOG (self));
+
+ if (self->rows->len == 1)
+ {
+ PanelSaveDialogRow *row = g_ptr_array_index (self->rows, 0);
+ PanelSaveDelegate *delegate = panel_save_dialog_row_get_delegate (row);
+
+ panel_save_dialog_row_set_selection_mode (row, FALSE);
+
+ if (panel_save_delegate_get_is_draft (delegate))
+ {
+ const char *title = panel_save_delegate_get_title (delegate);
+ g_autofree char *body = NULL;
+
+ /* translators: %s is replaced with the document title */
+ body = g_strdup_printf (_("The draft “%s” has not been saved. It can be saved or discarded."),
title);
+
+ adw_message_dialog_set_heading (ADW_MESSAGE_DIALOG (self),
+ _("Save or Discard Draft?"));
+ adw_message_dialog_set_body (ADW_MESSAGE_DIALOG (self), body);
+
+ adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (self), "discard",
ADW_RESPONSE_DESTRUCTIVE);
+ adw_message_dialog_set_response_label (ADW_MESSAGE_DIALOG (self), "discard", _("_Discard"));
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "discard", TRUE);
+
+ adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (self), "save",
ADW_RESPONSE_SUGGESTED);
+ adw_message_dialog_set_response_label (ADW_MESSAGE_DIALOG (self), "save", _("_Save As…"));
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "save", TRUE);
+ }
+ else
+ {
+ const char *title = panel_save_delegate_get_title (delegate);
+ g_autofree char *body = NULL;
+
+ /* translators: %s is replaced with the document title */
+ body = g_strdup_printf (_("“%s” contains unsaved changes. Changes can be saved or discarded."),
title);
+
+ adw_message_dialog_set_heading (ADW_MESSAGE_DIALOG (self),
+ _("Save or Discard Changes?"));
+ adw_message_dialog_set_body (ADW_MESSAGE_DIALOG (self), body);
+
+ adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (self), "discard",
ADW_RESPONSE_DESTRUCTIVE);
+ adw_message_dialog_set_response_label (ADW_MESSAGE_DIALOG (self), "discard", _("_Discard"));
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "discard", TRUE);
+
+ adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (self), "save",
ADW_RESPONSE_SUGGESTED);
+ adw_message_dialog_set_response_label (ADW_MESSAGE_DIALOG (self), "save", _("_Save"));
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "save", TRUE);
+ }
+
+ gtk_widget_hide (GTK_WIDGET (self->page));
+ }
+ else
+ {
+ gboolean has_selected = FALSE;
+ gboolean has_unselected = FALSE;
+
+ for (guint i = 0; i < self->rows->len; i++)
+ {
+ PanelSaveDialogRow *row = g_ptr_array_index (self->rows, i);
+ gboolean selected = panel_save_dialog_row_get_selected (row);
+
+ has_selected |= selected;
+ has_unselected |= !selected;
+
+ panel_save_dialog_row_set_selection_mode (row, TRUE);
+ }
+
+ adw_message_dialog_set_heading (ADW_MESSAGE_DIALOG (self),
+ _("Save or Discard Changes?"));
+ adw_message_dialog_set_body (ADW_MESSAGE_DIALOG (self),
+ _("Open documents contain unsaved changes. Changes can be saved or
discarded."));
+
+ if (has_selected && has_unselected)
+ {
+ adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (self), "save",
ADW_RESPONSE_DESTRUCTIVE);
+ adw_message_dialog_set_response_label (ADW_MESSAGE_DIALOG (self), "save", _("Only _Save
Selected"));
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "save", TRUE);
+
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "discard", FALSE);
+ }
+ else if (has_selected)
+ {
+ adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (self), "save",
ADW_RESPONSE_SUGGESTED);
+ adw_message_dialog_set_response_label (ADW_MESSAGE_DIALOG (self), "save", _("Save All"));
+
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "discard", FALSE);
+ }
+ else
+ {
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "save", FALSE);
+
+ adw_message_dialog_set_response_appearance (ADW_MESSAGE_DIALOG (self), "discard",
ADW_RESPONSE_DESTRUCTIVE);
+ adw_message_dialog_set_response_label (ADW_MESSAGE_DIALOG (self), "discard", _("Discard All"));
+ set_response_visible (ADW_MESSAGE_DIALOG (self), "discard", TRUE);
+ }
+
+ gtk_widget_show (GTK_WIDGET (self->page));
+ }
+}
+
+static void
+panel_save_dialog_notify_selected_cb (PanelSaveDialog *self,
+ GParamSpec *pspec,
+ PanelSaveDialogRow *row)
+{
+ g_assert (PANEL_IS_SAVE_DIALOG (self));
+ g_assert (PANEL_IS_SAVE_DIALOG_ROW (row));
+
+ panel_save_dialog_update (self);
+}
+
void
panel_save_dialog_add_delegate (PanelSaveDialog *self,
PanelSaveDelegate *delegate)
{
+ GtkWidget *row;
+
g_return_if_fail (PANEL_IS_SAVE_DIALOG (self));
g_return_if_fail (PANEL_IS_SAVE_DELEGATE (delegate));
- self->count++;
+ row = panel_save_dialog_row_new (delegate);
+ g_signal_connect_object (row,
+ "notify::selected",
+ G_CALLBACK (panel_save_dialog_notify_selected_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ g_ptr_array_add (self->rows, row);
+ adw_preferences_group_add (self->group, row);
- adw_preferences_group_add (self->group,
- panel_save_dialog_row_new (delegate));
+ panel_save_dialog_update (self);
}
void
@@ -154,7 +337,7 @@ panel_save_dialog_run_async (PanelSaveDialog *self,
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, panel_save_dialog_run_async);
- if (self->count == 0)
+ if (self->rows->len == 0)
{
gtk_window_destroy (GTK_WINDOW (self));
g_task_return_boolean (task, TRUE);
diff --git a/src/panel-save-dialog.ui b/src/panel-save-dialog.ui
index 6c7c396..d5668e2 100644
--- a/src/panel-save-dialog.ui
+++ b/src/panel-save-dialog.ui
@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="PanelSaveDialog" parent="AdwMessageDialog">
- <property name="heading" translatable="yes">Save or Discard Changes?</property>
- <property name="body" translatable="yes">Open documents contain unsaved changes. Changes which are not
saved will be permanently lost.</property>
<property name="default-response">save</property>
<property name="close-response">cancel</property>
<signal name="response::cancel" handler="panel_save_dialog_response_cancel_cb"/>
@@ -14,7 +12,11 @@
<response id="save" translatable="yes" appearance="suggested">_Save</response>
</responses>
<property name="extra-child">
- <object class="AdwPreferencesGroup" id="group">
+ <object class="AdwPreferencesPage" id="page">
+ <child>
+ <object class="AdwPreferencesGroup" id="group">
+ </object>
+ </child>
</object>
</property>
</template>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]