Bug fix: Minor coding error in bar_rating.c
[geeqie.git] / src / bar_rating.c
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2022 The Geeqie Team
4  *
5  * Author: Colin Clark
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "bar_rating.h"
24
25 #include "bar.h"
26 #include "filedata.h"
27 #include "metadata.h"
28 #include "rcfile.h"
29 #include "ui_misc.h"
30
31 /**
32  * @file
33  * Rating values as specified by: \n
34  * Adobe XMP Basic namespace \n
35  * -1 Rejected \n
36  * 0 Unrated \n
37  * 1 to 5 Rating value
38  */
39
40 typedef struct _PaneRatingData PaneRatingData;
41 struct _PaneRatingData
42 {
43         PaneData pane;
44         GtkWidget *widget;
45         GtkWidget *radio_button_first;
46         FileData *fd;
47 };
48
49 static void bar_pane_rating_update(PaneRatingData *prd)
50 {
51         guint64 rating;
52         GSList *list;
53
54         rating = metadata_read_int(prd->fd, RATING_KEY, 0);
55
56         list = gtk_radio_button_get_group(GTK_RADIO_BUTTON(prd->radio_button_first));
57
58         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g_slist_nth_data(list, 5 - rating)), TRUE);
59 }
60
61 static void bar_pane_rating_set_fd(GtkWidget *pane, FileData *fd)
62 {
63         PaneRatingData *prd;
64
65         prd = g_object_get_data(G_OBJECT(pane), "pane_data");
66         if (!prd) return;
67
68         file_data_unref(prd->fd);
69         prd->fd = file_data_ref(fd);
70
71         bar_pane_rating_update(prd);
72 }
73
74 static void bar_pane_rating_write_config(GtkWidget *pane, GString *outstr, gint indent)
75 {
76         PaneRatingData *prd;
77
78         prd = g_object_get_data(G_OBJECT(pane), "pane_data");
79         if (!prd) return;
80
81         WRITE_NL();
82         WRITE_STRING("<pane_rating ");
83         write_char_option(outstr, indent, "id", prd->pane.id);
84         write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(prd->pane.title)));
85         WRITE_BOOL(prd->pane, expanded);
86         WRITE_STRING("/>");
87 }
88
89 static void bar_pane_rating_notify_cb(FileData *fd, NotifyType type, gpointer data)
90 {
91         PaneRatingData *prd = data;
92
93         if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE | NOTIFY_HISTMAP | NOTIFY_PIXBUF)) && fd == prd->fd)
94                 {
95                 DEBUG_1("Notify pane_rating: %s %04x", fd->path, type);
96                 bar_pane_rating_update(prd);
97                 }
98 }
99
100 static void bar_pane_rating_destroy(GtkWidget *widget, gpointer data)
101 {
102         PaneRatingData *prd = data;
103
104         file_data_unregister_notify_func(bar_pane_rating_notify_cb, prd);
105         file_data_unref(prd->fd);
106         g_free(prd->pane.id);
107         g_free(prd);
108 }
109
110 static void bar_pane_rating_selected_cb(GtkToggleButton *togglebutton, gpointer data)
111 {
112         PaneRatingData *prd = data;
113         GSList *list;
114         gint i;
115         gchar *rating;
116
117         if (gtk_toggle_button_get_active(togglebutton))
118                 {
119                 list = gtk_radio_button_get_group(GTK_RADIO_BUTTON(togglebutton));
120                 i = 0;
121
122                 while (list)
123                         {
124                         if (list->data == togglebutton)
125                                 {
126                                 rating = g_strdup_printf("%d", 5 - i);
127                                 metadata_write_string(prd->fd, RATING_KEY, rating);
128                                 g_free(rating);
129                                 break;
130                                 }
131
132                         i++;
133                         list = list->next;
134                         }
135                 }
136 }
137
138 static GtkWidget *bar_pane_rating_new(const gchar *id, const gchar *title, gboolean expanded)
139 {
140         PaneRatingData *prd;
141         GtkWidget *radio_rejected;
142         GtkWidget *radio_unrated;
143         GtkWidget *radio_rating;
144         GtkWidget *row_1;
145         GtkWidget *row_2;
146         gint i;
147         gchar *i_str;
148
149         prd = g_new0(PaneRatingData, 1);
150
151         prd->pane.pane_set_fd = bar_pane_rating_set_fd;
152         prd->pane.pane_write_config = bar_pane_rating_write_config;
153         prd->pane.title = bar_pane_expander_title(title);
154         prd->pane.id = g_strdup(id);
155         prd->pane.type = PANE_RATING;
156
157         prd->pane.expanded = expanded;
158
159         prd->widget = gtk_vbox_new(FALSE, PREF_PAD_GAP);
160
161         g_object_set_data(G_OBJECT(prd->widget), "pane_data", prd);
162         g_signal_connect(G_OBJECT(prd->widget), "destroy", G_CALLBACK(bar_pane_rating_destroy), prd);
163
164         row_1 = gtk_hbox_new(FALSE, PREF_PAD_GAP);
165         gtk_box_pack_start(GTK_BOX(prd->widget), row_1, FALSE, FALSE, 0);
166
167         radio_rejected = gtk_radio_button_new_with_label(NULL, _("Rejected"));
168         gtk_box_pack_start(GTK_BOX(row_1), radio_rejected, FALSE, FALSE, 0);
169         g_signal_connect(radio_rejected, "released", G_CALLBACK(bar_pane_rating_selected_cb), prd);
170
171         radio_unrated = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_rejected), _("Unrated"));
172         gtk_box_pack_start(GTK_BOX(row_1), radio_unrated, FALSE, FALSE, 0);
173         g_signal_connect(radio_unrated, "released", G_CALLBACK(bar_pane_rating_selected_cb), prd);
174
175         row_2 = gtk_hbox_new(FALSE, PREF_PAD_GAP);
176         gtk_box_pack_start(GTK_BOX(prd->widget), row_2, FALSE, FALSE, 0);
177
178         i = 1;
179         while (i <= 5)
180                 {
181                 i_str = g_strdup_printf("%d", i);
182
183                 radio_rating = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_rejected), i_str);
184                 g_signal_connect(radio_rating, "released", G_CALLBACK(bar_pane_rating_selected_cb), prd);
185
186                 gtk_box_pack_start(GTK_BOX(row_2), radio_rating, FALSE, FALSE, 1);
187
188                 g_free(i_str);
189                 i++;
190                 }
191
192         prd->radio_button_first = radio_rating;
193
194         gtk_widget_show(prd->widget);
195
196         file_data_register_notify_func(bar_pane_rating_notify_cb, prd, NOTIFY_PRIORITY_LOW);
197
198         return prd->widget;
199 }
200
201 GtkWidget *bar_pane_rating_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
202 {
203         gchar *title = NULL;
204         gchar *id = g_strdup("rating");
205         gboolean expanded = TRUE;
206         GtkWidget *ret;
207
208         while (*attribute_names)
209                 {
210                 const gchar *option = *attribute_names++;
211                 const gchar *value = *attribute_values++;
212
213                 if (READ_CHAR_FULL("id", id)) continue;
214                 if (READ_CHAR_FULL("title", title)) continue;
215                 if (READ_BOOL_FULL("expanded", expanded)) continue;
216
217                 log_printf("unknown attribute %s = %s\n", option, value);
218                 }
219
220         bar_pane_translate_title(PANE_RATING, id, &title);
221         ret = bar_pane_rating_new(id, title, expanded);
222
223         g_free(title);
224         g_free(id);
225         return ret;
226 }
227
228 void bar_pane_rating_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
229 {
230         PaneRatingData *prd;
231         gchar *title = NULL;
232
233         prd = g_object_get_data(G_OBJECT(pane), "pane_data");
234         if (!prd) return;
235
236         while (*attribute_names)
237                 {
238                 const gchar *option = *attribute_names++;
239                 const gchar *value = *attribute_values++;
240
241                 if (READ_CHAR_FULL("title", title)) continue;
242                 if (READ_CHAR_FULL("id", prd->pane.id)) continue;
243                 if (READ_BOOL_FULL("expanded", prd->pane.expanded)) continue;
244
245                 log_printf("unknown attribute %s = %s\n", option, value);
246                 }
247
248         bar_update_expander(pane);
249         bar_pane_rating_update(prd);
250 }
251 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */