[gimp] app: display the release notes as a GtkListBox instead of text.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: display the release notes as a GtkListBox instead of text.
- Date: Sat, 5 Mar 2022 16:44:22 +0000 (UTC)
commit 3011795407db45919bc8cd312da4fd00c1a61463
Author: Jehan <jehan girinstud io>
Date: Fri Mar 4 21:26:05 2022 +0100
app: display the release notes as a GtkListBox instead of text.
What it means is that we will be a bit strict over our <release>
formatting which will have to always be a <p> introduction followed by a
list of items. This is what gimp_appstream_to_pango_markups() expects.
Since so far, this is how all our <release> tags were formatted anyway,
this is not too much of a problem.
Note that I keep the less strict gimp_appstream_to_pango_markup() and
use it for extension's appstream description as we will have no control
over these.
The main reason for this new rule and new display of our release notes
is that I am going to add the ability to click independent release items
so that people can get "blinking" indications of what changed when
relevant.
app/core/gimp-utils.c | 134 ++++++++++++++++++++++++++++++-------------
app/core/gimp-utils.h | 3 +
app/dialogs/welcome-dialog.c | 73 ++++++++++++++++-------
3 files changed, 147 insertions(+), 63 deletions(-)
---
diff --git a/app/core/gimp-utils.c b/app/core/gimp-utils.c
index 5bd0f493fd..ba6c2ee1a7 100644
--- a/app/core/gimp-utils.c
+++ b/app/core/gimp-utils.c
@@ -75,9 +75,15 @@ typedef struct
const gchar *lang;
GString *original;
gint foreign_level;
+
+ gchar **introduction;
+ GList **release_items;
} ParseState;
+static gchar * gimp_appstream_parse (const gchar *as_text,
+ gchar **introduction,
+ GList **release_items);
static void appstream_text_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
@@ -955,50 +961,20 @@ gimp_ascii_strtod (const gchar *nptr,
gchar *
gimp_appstream_to_pango_markup (const gchar *as_text)
{
- static const GMarkupParser appstream_text_parser =
- {
- appstream_text_start_element,
- appstream_text_end_element,
- appstream_text_characters,
- NULL, /* passthrough */
- NULL /* error */
- };
-
- GimpXmlParser *xml_parser;
- gchar *markup = NULL;
- GError *error = NULL;
- ParseState state;
-
- state.level = 0;
- state.foreign_level = -1;
- state.text = g_string_new (NULL);
- state.numbered_list = FALSE;
- state.unnumbered_list = FALSE;
- state.lang = g_getenv ("LANGUAGE");
- state.original = NULL;
-
- xml_parser = gimp_xml_parser_new (&appstream_text_parser, &state);
- if (as_text &&
- ! gimp_xml_parser_parse_buffer (xml_parser, as_text, -1, &error))
- {
- g_printerr ("%s: %s\n", G_STRFUNC, error->message);
- g_error_free (error);
- }
-
- /* Append possibly last original text without proper localization. */
- if (state.original)
- {
- g_string_append (state.text, state.original->str);
- g_string_free (state.original, TRUE);
- }
+ return gimp_appstream_parse (as_text, NULL, NULL);
+}
- markup = g_string_free (state.text, FALSE);
- gimp_xml_parser_free (xml_parser);
+void
+gimp_appstream_to_pango_markups (const gchar *as_text,
+ gchar **introduction,
+ GList **release_items)
+{
+ gchar * markup;
- return markup;
+ markup = gimp_appstream_parse (as_text, introduction, release_items);
+ g_free (markup);
}
-
gint
gimp_g_list_compare (GList *list1,
GList *list2)
@@ -1308,6 +1284,61 @@ gimp_create_image_from_buffer (Gimp *gimp,
/* Private functions */
+
+static gchar *
+gimp_appstream_parse (const gchar *as_text,
+ gchar **introduction,
+ GList **release_items)
+{
+ static const GMarkupParser appstream_text_parser =
+ {
+ appstream_text_start_element,
+ appstream_text_end_element,
+ appstream_text_characters,
+ NULL, /* passthrough */
+ NULL /* error */
+ };
+
+ GimpXmlParser *xml_parser;
+ gchar *markup = NULL;
+ GError *error = NULL;
+ ParseState state;
+
+ state.level = 0;
+ state.foreign_level = -1;
+ state.text = g_string_new (NULL);
+ state.list_num = 0;
+ state.numbered_list = FALSE;
+ state.unnumbered_list = FALSE;
+ state.lang = g_getenv ("LANGUAGE");
+ state.original = NULL;
+ state.introduction = introduction;
+ state.release_items = release_items;
+
+ xml_parser = gimp_xml_parser_new (&appstream_text_parser, &state);
+ if (as_text &&
+ ! gimp_xml_parser_parse_buffer (xml_parser, as_text, -1, &error))
+ {
+ g_printerr ("%s: %s\n", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ /* Append possibly last original text without proper localization. */
+ if (state.original)
+ {
+ g_string_append (state.text, state.original->str);
+ g_string_free (state.original, TRUE);
+ }
+
+ if (release_items)
+ *release_items = g_list_reverse (*release_items);
+
+ markup = g_string_free (state.text, FALSE);
+ gimp_xml_parser_free (xml_parser);
+
+ return markup;
+}
+
static void
appstream_text_start_element (GMarkupParseContext *context,
const gchar *element_name,
@@ -1367,6 +1398,7 @@ appstream_text_start_element (GMarkupParseContext *context,
else if (g_strcmp0 (element_name, "ul") == 0)
{
state->unnumbered_list = TRUE;
+ state->list_num = 0;
}
else if (g_strcmp0 (element_name, "ol") == 0)
{
@@ -1407,6 +1439,10 @@ appstream_text_end_element (GMarkupParseContext *context,
{
if (state->foreign_level < 0)
{
+ if (state->introduction &&
+ *state->introduction == NULL)
+ *state->introduction = g_strdup (state->original ? state->original->str : state->text->str);
+
if (state->original)
g_string_append (state->original, "\n\n");
else
@@ -1440,8 +1476,24 @@ appstream_text_characters (GMarkupParseContext *context,
{
ParseState *state = user_data;
- if (state->foreign_level < 0)
+ if (state->foreign_level < 0 && text_len > 0)
{
+ if (state->list_num > 0 && state->release_items)
+ {
+ GList **items = state->release_items;
+
+ if (state->list_num == g_list_length (*(state->release_items)))
+ {
+ gchar *tmp = (*items)->data;
+
+ (*items)->data = g_strconcat (tmp, text, NULL);
+ g_free (tmp);
+ }
+ else
+ {
+ *items = g_list_prepend (*items, g_strdup (text));
+ }
+ }
if (state->original)
g_string_append (state->original, text);
else
diff --git a/app/core/gimp-utils.h b/app/core/gimp-utils.h
index 4523b9247c..ccc8906b48 100644
--- a/app/core/gimp-utils.h
+++ b/app/core/gimp-utils.h
@@ -102,6 +102,9 @@ gboolean gimp_ascii_strtod (const gchar *nptr,
gdouble *result);
gchar * gimp_appstream_to_pango_markup (const gchar *as_text);
+void gimp_appstream_to_pango_markups (const gchar *as_text,
+ gchar **introduction,
+ GList **release_items);
gint gimp_g_list_compare (GList *list1,
GList *list2);
diff --git a/app/dialogs/welcome-dialog.c b/app/dialogs/welcome-dialog.c
index 004b9f6749..f4e1b15f3a 100644
--- a/app/dialogs/welcome-dialog.c
+++ b/app/dialogs/welcome-dialog.c
@@ -74,15 +74,15 @@ welcome_dialog_create (Gimp *gimp)
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *image;
+ GtkWidget *listbox;
GtkWidget *widget;
- GtkTextBuffer *buffer;
- GtkTextIter iter;
-
gchar *release_link;
gchar *appdata_path;
gchar *title;
gchar *markup;
+ gchar *release_introduction = NULL;
+ GList *release_items = NULL;
gchar *tmp;
gint row;
@@ -344,26 +344,55 @@ welcome_dialog_create (Gimp *gimp)
/* Release note contents. */
- scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
- gtk_widget_show (scrolled_window);
-
- widget = gtk_text_view_new ();
- gtk_widget_set_vexpand (widget, TRUE);
- gtk_widget_set_hexpand (widget, TRUE);
- gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (widget), GTK_WRAP_WORD_CHAR);
- gtk_text_view_set_editable (GTK_TEXT_VIEW (widget), FALSE);
- gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (widget), FALSE);
- gtk_text_view_set_justification (GTK_TEXT_VIEW (widget), GTK_JUSTIFY_LEFT);
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
- gtk_text_buffer_get_start_iter (buffer, &iter);
-
- markup = gimp_appstream_to_pango_markup (release_notes);
- gtk_text_buffer_insert_markup (buffer, &iter, markup, -1);
- g_free (markup);
+ gimp_appstream_to_pango_markups (release_notes,
+ &release_introduction,
+ &release_items);
+ if (release_introduction)
+ {
+ widget = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (widget), release_introduction);
+ gtk_label_set_max_width_chars (GTK_LABEL (widget), 70);
+ gtk_label_set_selectable (GTK_LABEL (widget), FALSE);
+ gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
+ gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ g_free (release_introduction);
+ }
- gtk_container_add (GTK_CONTAINER (scrolled_window), widget);
- gtk_widget_show (widget);
+ if (release_items)
+ {
+ GList *item;
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+ gtk_widget_show (scrolled_window);
+
+ listbox = gtk_list_box_new ();
+
+ for (item = release_items; item; item = item->next)
+ {
+ GtkWidget *row;
+
+ row = gtk_list_box_row_new ();
+ widget = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (widget), item->data);
+ gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
+ gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_label_set_xalign (GTK_LABEL (widget), 0.0);
+ gtk_container_add (GTK_CONTAINER (row), widget);
+
+ gtk_list_box_insert (GTK_LIST_BOX (listbox), row, -1);
+ gtk_widget_show_all (row);
+ }
+ gtk_container_add (GTK_CONTAINER (scrolled_window), listbox);
+ gtk_widget_show (listbox);
+
+ g_list_free_full (release_items, g_free);
+ }
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]