Change sidebar rating pane layout
authorColin Clark <colin.clark@cclark.uk>
Tue, 12 Apr 2022 15:25:06 +0000 (16:25 +0100)
committerColin Clark <colin.clark@cclark.uk>
Tue, 12 Apr 2022 15:25:06 +0000 (16:25 +0100)
Change the sidebar Star Rating pane to use radio buttons.

src/Makefile.am
src/bar.c
src/bar.h
src/bar_rating.c [new file with mode: 0644]
src/bar_rating.h [new file with mode: 0644]
src/rcfile.c

index ec709bc..15013f3 100644 (file)
@@ -119,6 +119,8 @@ geeqie_SOURCES = \
        bar_keywords.h  \
        bar_exif.c      \
        bar_exif.h      \
+       bar_rating.c    \
+       bar_rating.h    \
        bar_sort.c      \
        bar_sort.h      \
        cache.c         \
index 11b4168..9d81b73 100644 (file)
--- a/src/bar.c
+++ b/src/bar.c
@@ -98,7 +98,7 @@ static const gchar default_config_rating[] =
 "<gq>"
 "    <layout id = '_current_'>"
 "        <bar>"
-"            <pane_comment id = 'rating' expanded = 'true' key = '" RATING_KEY "' height = '10' />"
+"            <pane_rating id = 'rating' expanded = 'true' />"
 "        </bar>"
 "    </layout>"
 "</gq>";
@@ -202,7 +202,7 @@ static const KnownPanes known_panes[] = {
        {PANE_COMMENT,          "title",        N_("Title"),            default_config_title},
        {PANE_KEYWORDS,         "keywords",     N_("Keywords"),         default_config_keywords},
        {PANE_COMMENT,          "comment",      N_("Comment"),          default_config_comment},
-       {PANE_COMMENT,          "rating",       N_("Rating"),           default_config_rating},
+       {PANE_RATING,           "rating",       N_("Star Rating"),      default_config_rating},
        {PANE_COMMENT,          "headline",     N_("Headline"),         default_config_headline},
        {PANE_EXIF,             "exif",         N_("Exif"),             default_config_exif},
 /* other pre-configured panes */
index 12b81d1..6569122 100644 (file)
--- a/src/bar.h
+++ b/src/bar.h
@@ -28,7 +28,8 @@ typedef enum {
        PANE_EXIF,
        PANE_HISTOGRAM,
        PANE_KEYWORDS,
-       PANE_GPS
+       PANE_GPS,
+       PANE_RATING
 } PaneType;
 
 typedef struct _PaneData PaneData;
diff --git a/src/bar_rating.c b/src/bar_rating.c
new file mode 100644 (file)
index 0000000..fdd23d0
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2022 The Geeqie Team
+ *
+ * Author: Colin Clark
+ *
+ * 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 2 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "main.h"
+#include "bar_rating.h"
+
+#include "bar.h"
+#include "filedata.h"
+#include "metadata.h"
+#include "rcfile.h"
+#include "ui_misc.h"
+
+/**
+ * @file
+ * Rating values as specified by: \n
+ * Adobe XMP Basic namespace \n
+ * -1 Rejected \n
+ * 0 Unrated \n
+ * 1 to 5 Rating value
+ */
+
+typedef struct _PaneRatingData PaneRatingData;
+struct _PaneRatingData
+{
+       PaneData pane;
+       GtkWidget *widget;
+       GtkWidget *radio_button_first;
+       FileData *fd;
+};
+
+static void bar_pane_rating_update(PaneRatingData *prd)
+{
+       guint64 rating;
+       GSList *list;
+
+       rating = metadata_read_int(prd->fd, RATING_KEY, 0);
+
+       list = gtk_radio_button_get_group(GTK_RADIO_BUTTON(prd->radio_button_first));
+
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g_slist_nth_data(list, 5 - rating)), TRUE);
+}
+
+static void bar_pane_rating_set_fd(GtkWidget *pane, FileData *fd)
+{
+       PaneRatingData *prd;
+
+       prd = g_object_get_data(G_OBJECT(pane), "pane_data");
+       if (!prd) return;
+
+       file_data_unref(prd->fd);
+       prd->fd = file_data_ref(fd);
+
+       bar_pane_rating_update(prd);
+}
+
+static void bar_pane_rating_write_config(GtkWidget *pane, GString *outstr, gint indent)
+{
+       PaneRatingData *prd;
+
+       prd = g_object_get_data(G_OBJECT(pane), "pane_data");
+       if (!prd) return;
+
+       WRITE_NL();
+       WRITE_STRING("<pane_rating ");
+       write_char_option(outstr, indent, "id", prd->pane.id);
+       write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(prd->pane.title)));
+       WRITE_BOOL(prd->pane, expanded);
+       WRITE_STRING("/>");
+}
+
+static void bar_pane_rating_notify_cb(FileData *fd, NotifyType type, gpointer data)
+{
+       PaneRatingData *prd = data;
+
+       if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE | NOTIFY_HISTMAP | NOTIFY_PIXBUF)) && fd == prd->fd)
+               {
+               DEBUG_1("Notify pane_rating: %s %04x", fd->path, type);
+               bar_pane_rating_update(prd);
+               }
+}
+
+static void bar_pane_rating_destroy(GtkWidget *widget, gpointer data)
+{
+       PaneRatingData *prd = data;
+
+       file_data_unregister_notify_func(bar_pane_rating_notify_cb, prd);
+       file_data_unref(prd->fd);
+       g_free(prd->pane.id);
+       g_free(prd);
+}
+
+static void bar_pane_rating_selected_cb(GtkToggleButton *togglebutton, gpointer data)
+{
+       PaneRatingData *prd = data;
+       GSList *list;
+       gint i;
+       gchar *rating;
+
+       if (gtk_toggle_button_get_active(togglebutton))
+               {
+               list = gtk_radio_button_get_group(GTK_RADIO_BUTTON(togglebutton));
+               i = 0;
+
+               while (list)
+                       {
+                       if (list->data == togglebutton)
+                               {
+                               rating = g_strdup_printf("%d", 5 - i);
+                               metadata_write_string(prd->fd, RATING_KEY, rating);
+                               g_free(rating);
+                               break;
+                               }
+
+                       i++;
+                       list = list->next;
+                       }
+               }
+}
+
+static GtkWidget *bar_pane_rating_new(const gchar *id, const gchar *title, gboolean expanded)
+{
+       PaneRatingData *prd;
+       GtkWidget *radio_rejected;
+       GtkWidget *radio_unrated;
+       GtkWidget *radio_rating;
+       GtkWidget *row_1;
+       GtkWidget *row_2;
+       gint i;
+       gchar *i_str;
+
+       prd = g_new0(PaneRatingData, 1);
+
+       prd->pane.pane_set_fd = bar_pane_rating_set_fd;
+       prd->pane.pane_write_config = bar_pane_rating_write_config;
+       prd->pane.title = bar_pane_expander_title(title);
+       prd->pane.id = g_strdup(id);
+       prd->pane.type = PANE_RATING;
+
+       prd->pane.expanded = expanded;
+
+       prd->widget = gtk_vbox_new(FALSE, PREF_PAD_GAP);
+
+       g_object_set_data(G_OBJECT(prd->widget), "pane_data", prd);
+       g_signal_connect(G_OBJECT(prd->widget), "destroy", G_CALLBACK(bar_pane_rating_destroy), prd);
+
+       row_1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+       gtk_box_pack_start(GTK_BOX(prd->widget), row_1, FALSE, FALSE, 0);
+
+       radio_rejected = gtk_radio_button_new_with_label(NULL, _("Rejected"));
+       gtk_box_pack_start(GTK_BOX(row_1), radio_rejected, FALSE, FALSE, 0);
+       g_signal_connect(radio_rejected, "released", G_CALLBACK(bar_pane_rating_selected_cb), prd);
+
+       radio_unrated = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_rejected), _("Unrated"));
+       gtk_box_pack_start(GTK_BOX(row_1), radio_unrated, FALSE, FALSE, 0);
+       g_signal_connect(radio_unrated, "released", G_CALLBACK(bar_pane_rating_selected_cb), prd);
+
+       row_2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+       gtk_box_pack_start(GTK_BOX(prd->widget), row_2, FALSE, FALSE, 0);
+
+       i = 1;
+       while (i <= 5)
+               {
+               i_str = g_strdup_printf("%d", i);
+
+               radio_rating = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_rejected), i_str);
+               g_signal_connect(radio_rating, "released", G_CALLBACK(bar_pane_rating_selected_cb), prd);
+
+               gtk_box_pack_start(GTK_BOX(row_2), radio_rating, FALSE, FALSE, 1);
+
+               g_free(i_str);
+               i++;
+               }
+
+       prd->radio_button_first = radio_rating;
+
+       gtk_widget_show(prd->widget);
+
+       file_data_register_notify_func(bar_pane_rating_notify_cb, prd, NOTIFY_PRIORITY_LOW);
+
+       return prd->widget;
+}
+
+GtkWidget *bar_pane_rating_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
+{
+       gchar *title = NULL;
+       gchar *id = g_strdup("rating");
+       gboolean expanded = TRUE;
+       GtkWidget *ret;
+
+       while (*attribute_names)
+               {
+               const gchar *option = *attribute_names++;
+               const gchar *value = *attribute_values++;
+
+               if (READ_CHAR_FULL("id", id)) continue;
+               if (READ_CHAR_FULL("title", title)) continue;
+               if (READ_BOOL_FULL("expanded", expanded)) continue;
+
+               log_printf("unknown attribute %s = %s\n", option, value);
+               }
+
+       bar_pane_translate_title(PANE_RATING, id, &title);
+       ret = bar_pane_rating_new(id, title, expanded);
+
+       g_free(title);
+       g_free(id);
+       return ret;
+}
+
+void bar_pane_rating_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
+{
+       PaneRatingData *prd;
+       gchar *title = NULL;
+
+       prd = g_object_get_data(G_OBJECT(pane), "pane_data");
+       if (!prd) return;
+
+       while (*attribute_names)
+               {
+               const gchar *option = *attribute_names++;
+               const gchar *value = *attribute_values++;
+
+               if (READ_CHAR_FULL("title", title)) continue;
+               if (READ_CHAR_FULL("id", prd->pane.id)) continue;
+               if (READ_BOOL_FULL("expanded", prd->pane.expanded)) continue;
+
+               log_printf("unknown attribute %s = %s\n", option, value);
+               }
+
+       bar_update_expander(pane);
+       bar_pane_rating_update(prd);
+}
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff --git a/src/bar_rating.h b/src/bar_rating.h
new file mode 100644 (file)
index 0000000..63a7f01
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2022 The Geeqie Team
+ *
+ * Author: Colin Clark
+ *
+ * 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 2 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef BAR_RATING_H
+#define BAR_RATING_H
+
+GtkWidget *bar_pane_rating_new_from_config(const gchar **attribute_names, const gchar **attribute_values);
+void bar_pane_rating_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values);
+
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index cc80f20..1e98e4c 100644 (file)
@@ -30,6 +30,7 @@
 #include "bar_exif.h"
 #include "bar_histogram.h"
 #include "bar_keywords.h"
+#include "bar_rating.h"
 #include "bar_sort.h"
 #include "editors.h"
 #include "filefilter.h"
@@ -1436,6 +1437,20 @@ static void options_parse_bar(GQParserData *parser_data, GMarkupParseContext *co
                        }
                options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
                }
+       else if (g_ascii_strcasecmp(element_name, "pane_rating") == 0)
+               {
+               GtkWidget *pane = bar_find_pane_by_id(bar, PANE_RATING, options_get_id(attribute_names, attribute_values));
+               if (pane)
+                       {
+                       bar_pane_rating_update_from_config(pane, attribute_names, attribute_values);
+                       }
+               else
+                       {
+                       pane = bar_pane_rating_new_from_config(attribute_names, attribute_values);
+                       bar_add(bar, pane);
+                       }
+               options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
+               }
        else if (g_ascii_strcasecmp(element_name, "pane_keywords") == 0)
                {
                GtkWidget *pane = bar_find_pane_by_id(bar, PANE_KEYWORDS, options_get_id(attribute_names, attribute_values));