Howdy, everybody

This feature is still under development and still has some rough edges, but it's finally gotten to the point where I think it'll be a big help to anyone dealing with a lot of images.

### What it does so far:
- Reads/updates/creates the 'xap:Rating' tag, where most if not all image viewers store image ratings (LightRoom, Adobe Bridge, etc.) - Has an "auto-advance" feature; if it's checked, you'll automatically advance to the next image after changing the Rating for the current image. - Supports keyboard accelerators with defaults for increment, decrement, and rate 0–10

This means that you'll be able to go through and rate a directory of photos
without taking your hands off of the number-pad. If you change your mind on one, just use normal navigation (backspace/space) to go back, and then go back to hitting numbers.


### How to get it:
1) Compile geeqie with the attached patch
2) Hit Ctrl+k to bring up the metadata bar, if you don't have it open already
3) Right-click on the metadata bar, and select "Rating" from the pop-up menu to
add it.
4) Profit.
5) ???

### How to use it:
Increment the rating:
 - Press the "Inc. " button
 - Hit the spinbutton "+" button
 - Hit the Increment accelerator, Alt+(KP+) by default
Decrement the rating:
 - Press the "Dec." button; twiddle the spinbutton; Alt+(KP-)
Set the rating arbitrarily:
 - Spin the spinbutton with your scroll-wheel
 - Type a number in the box
 - Use one of the numeric accels: Alt+(KP0) up to Alt+(KP9), or Alt+(KP.) for 10
Auto-advance:
- When checked, any change of the rating will automatically advance you to the next image. This includes one spin if you use your scroll-wheel with the spin-button.

### To change the keyboard accelerators:
  a) Go to Edit->Preferences->Preferences to bring up the Prefs dialog
  b) Switch to the "Keyboard" tab
  c) Look for the "Increment Rating" and "Decrement Rating" entries.
  d) Click the empty box in the "KEY" column for that row and then type the
shortcut you want


### What's missing right now:
 - Non-ugly UI
 - Ability to sort by rating
 - Ability to remove the rating from an image


Let me know what you like, what you don't like, and what you'd like to change.


Full patch:
http://ocaml.xvm.mit.edu/~xsdg/stuff/geeqie/ratings/ratings.v4.full.patch.txt

Incremental patches:
http://ocaml.xvm.mit.edu/~xsdg/stuff/geeqie/ratings/ratings.v1.patch.txt
http://ocaml.xvm.mit.edu/~xsdg/stuff/geeqie/ratings/ratings.v2.inc.patch.txt
http://ocaml.xvm.mit.edu/~xsdg/stuff/geeqie/ratings/ratings.v3.inc.patch.txt
http://ocaml.xvm.mit.edu/~xsdg/stuff/geeqie/ratings/ratings.v4.inc.patch.txt

--xsdg

diff --git a/trunk/src/Makefile.am b/trunk/src/Makefile.am
index 144b090..9528d30 100644
--- a/trunk/src/Makefile.am
+++ b/trunk/src/Makefile.am
@@ -94,6 +94,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		\
diff --git a/trunk/src/bar.c b/trunk/src/bar.c
index 52d6a54..4d64b71 100644
--- a/trunk/src/bar.c
+++ b/trunk/src/bar.c
@@ -25,6 +25,7 @@
 #include "ui_menu.h"
 #include "bar_comment.h"
 #include "bar_keywords.h"
+#include "bar_rating.h"
 #include "bar_exif.h"
 #include "bar_histogram.h"
 #include "histogram.h"
@@ -76,6 +77,15 @@ static const gchar default_config_comment[] =
 "    </layout>"
 "</gq>";
 
+static const gchar default_config_rating[] =
+"<gq>"
+"    <layout id = '_current_'>"
+"        <bar>"
+"            <pane_rating id = 'rating' expanded = 'true' key = '" RATING_KEY "' />"
+"        </bar>"
+"    </layout>"
+"</gq>";
+
 static const gchar default_config_exif[] = 
 "<gq>"
 "    <layout id = '_current_'>"
@@ -178,6 +188,7 @@ static const KnownPanes known_panes[] = {
 	{PANE_GPS,		"gps",	N_("GPS Map"),	default_config_gps},
 #endif
 #endif
+	{PANE_RATING,		"rating",       N_("Rating"),   default_config_rating},
 	{PANE_UNDEF,		NULL,		NULL,			NULL}
 };
 
diff --git a/trunk/src/bar.h b/trunk/src/bar.h
index 61dc4be..d24acf3 100644
--- a/trunk/src/bar.h
+++ b/trunk/src/bar.h
@@ -20,7 +20,8 @@ typedef enum {
 	PANE_EXIF,
 	PANE_HISTOGRAM,
 	PANE_KEYWORDS,
-	PANE_GPS
+	PANE_GPS,
+	PANE_RATING
 } PaneType;
 
 typedef struct _PaneData PaneData;
diff --git a/trunk/src/bar_rating.c b/trunk/src/bar_rating.c
new file mode 100644
index 0000000..80b972c
--- /dev/null
+++ b/trunk/src/bar_rating.c
@@ -0,0 +1,400 @@
+/*
+ * Geeqie
+ * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2009 The Geeqie Team
+ *
+ * Author: Omari Stephens
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+
+#include "main.h"
+#include "bar_rating.h"
+
+#include "bar.h"
+#include "metadata.h"
+#include "filedata.h"
+#include "ui_menu.h"
+#include "ui_misc.h"
+#include "rcfile.h"
+#include "layout.h"
+#include "layout_image.h"
+
+static void bar_pane_rating_changed(GtkSpinButton *button, gpointer data);
+
+/*
+ *-------------------------------------------------------------------
+ * rating utils
+ *-------------------------------------------------------------------
+ */
+
+
+
+typedef struct _PaneRatingData PaneRatingData;
+struct _PaneRatingData
+{
+	PaneData pane;
+	GtkHBox *container;
+	GtkSpinButton *spinbutton;
+	GtkToggleButton *auto_adv;      // autoadvance
+	FileData *fd;
+	gchar *key;
+	gint height;
+};
+
+
+static void bar_pane_rating_write(PaneRatingData *prd)
+{
+	guint value;
+
+	if (!prd->fd) return;
+
+	value = gtk_spin_button_get_value_as_int(prd->spinbutton);
+
+	metadata_write_int(prd->fd, prd->key, value);
+}
+
+
+static void bar_pane_rating_update(PaneRatingData *prd)
+{
+	guint64 value;
+
+	g_signal_handlers_block_by_func(prd->spinbutton, bar_pane_rating_changed, prd);
+
+	value = metadata_read_int(prd->fd, prd->key, (guint64)-1);
+
+	if(value != (guint64)-1)
+		{
+		gtk_spin_button_set_value(prd->spinbutton, value);
+		}
+	else
+		{
+		gtk_spin_button_set_value(prd->spinbutton, 0);
+		}
+
+	g_signal_handlers_unblock_by_func(prd->spinbutton, bar_pane_rating_changed, prd);
+
+	gtk_widget_set_sensitive((GtkWidget*) prd->spinbutton, (prd->fd != NULL));
+}
+
+static void bar_pane_rating_set_selection(PaneRatingData *prd, gboolean overwrite)
+{
+	GList *list = NULL;
+	GList *work;
+	gint value = -1;
+
+	value = gtk_spin_button_get_value_as_int(prd->spinbutton);
+
+	list = layout_selection_list(prd->pane.lw);
+	list = file_data_process_groups_in_selection(list, FALSE, NULL);
+
+	work = list;
+	while (work)
+		{
+		FileData *fd = work->data;
+		work = work->next;
+		if (fd == prd->fd) continue;
+
+		if (overwrite || (metadata_read_int(fd, prd->key, -1) == (guint64)-1))
+			{
+			metadata_write_int(fd, prd->key, value);
+			}
+		}
+
+	filelist_free(list);
+}
+
+/*
+static void bar_pane_comment_sel_add_cb(GtkWidget *button, gpointer data)
+{
+	PaneCommentData *pcd = data;
+
+	bar_pane_comment_set_selection(pcd, TRUE);
+}
+
+
+static void bar_pane_comment_sel_replace_cb(GtkWidget *button, gpointer data)
+{
+	PaneCommentData *pcd = data;
+
+	bar_pane_comment_set_selection(pcd, FALSE);
+}
+*/
+
+static void bar_pane_rating_set_fd(GtkWidget *bar, FileData *fd)
+{
+	PaneRatingData *prd;
+
+	prd = g_object_get_data(G_OBJECT(bar), "pane_data");
+	if (!prd) return;
+
+	file_data_unref(prd->fd);
+	prd->fd = file_data_ref(fd);
+
+	bar_pane_rating_update(prd);
+}
+
+static gint bar_pane_rating_event(GtkWidget *bar, GdkEvent *event)
+{
+	PaneRatingData *prd;
+
+	prd = g_object_get_data(G_OBJECT(bar), "pane_data");
+	if (!prd) return FALSE;
+
+	if (GTK_WIDGET_HAS_FOCUS(prd->spinbutton))
+		{
+		return gtk_widget_event((GtkWidget*) prd->spinbutton, event);
+		}
+
+	return FALSE;
+}
+
+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_CHAR(*prd, key);
+	WRITE_INT(*prd, height);
+	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_METADATA)) && fd == prd->fd)
+		{
+		DEBUG_1("Notify pane_rating: %s %04x", fd->path, type);
+
+		bar_pane_rating_update(prd);
+		}
+}
+
+static void bar_pane_rating_changed(GtkSpinButton *button, gpointer data)
+{
+	PaneRatingData *prd = data;
+
+	file_data_unregister_notify_func(bar_pane_rating_notify_cb, prd);
+	bar_pane_rating_write(prd);
+	file_data_register_notify_func(bar_pane_rating_notify_cb, prd, NOTIFY_PRIORITY_LOW);
+}
+
+static void bar_pane_rating_inc_value_cb(GtkButton *button, gpointer data)
+{
+	bar_pane_rating_inc_value(data);
+}
+
+void bar_pane_rating_inc_value(gpointer data)
+{
+	PaneRatingData *prd = data;
+	gtk_spin_button_spin(prd->spinbutton, GTK_SPIN_STEP_FORWARD, 1.0);
+	if(gtk_toggle_button_get_active(prd->auto_adv)) layout_image_next(NULL);
+}
+
+static void bar_pane_rating_dec_value_cb(GtkButton *button, gpointer data)
+{
+	bar_pane_rating_dec_value(data);
+}
+
+void bar_pane_rating_dec_value(gpointer data)
+{
+	PaneRatingData *prd = data;
+	gtk_spin_button_spin(prd->spinbutton, GTK_SPIN_STEP_BACKWARD, 1.0);
+	if(gtk_toggle_button_get_active(prd->auto_adv)) layout_image_next(NULL);
+}
+
+void bar_pane_rating_set_value(gint value, gpointer data)
+{
+	PaneRatingData *prd = data;
+	gtk_spin_button_set_value(prd->spinbutton, value);
+	if(gtk_toggle_button_get_active(prd->auto_adv)) layout_image_next(NULL);
+}
+
+
+/*
+static void bar_pane_comment_populate_popup(GtkTextView *textview, GtkMenu *menu, gpointer data)
+{
+	PaneCommentData *pcd = data;
+
+	menu_item_add_divider(GTK_WIDGET(menu));
+	menu_item_add_stock(GTK_WIDGET(menu), _("Add text to selected files"), GTK_STOCK_ADD, G_CALLBACK(bar_pane_comment_sel_add_cb), pcd);
+	menu_item_add_stock(GTK_WIDGET(menu), _("Replace existing text in selected files"), GTK_STOCK_CONVERT, G_CALLBACK(bar_pane_comment_sel_replace_cb), data);
+}
+*/
+
+#if 0
+static void bar_pane_comment_close(GtkWidget *bar)
+{
+	PaneCommentData *pcd;
+
+	pcd = g_object_get_data(G_OBJECT(bar), "pane_data");
+	if (!pcd) return;
+
+	gtk_widget_destroy(pcd->comment_view);
+}
+#endif
+
+static void bar_pane_rating_destroy(GtkWidget *widget, gpointer data)
+{
+	// FIXME: make sure we free the spinbutton
+	PaneRatingData *prd = data;
+
+	file_data_unregister_notify_func(bar_pane_rating_notify_cb, prd);
+
+	file_data_unref(prd->fd);
+	g_free(prd->key);
+
+	g_free(prd->pane.id);
+
+	g_free(prd);
+}
+
+
+static GtkWidget *bar_pane_rating_new(const gchar *id, const gchar *title, const gchar *key,
+	gboolean expanded, gint height)
+{
+	PaneRatingData *prd;
+	GtkHBox *hbox;
+	GtkWidget *tmp;
+
+	prd = g_new0(PaneRatingData, 1);
+
+	prd->pane.pane_set_fd = bar_pane_rating_set_fd;
+	prd->pane.pane_event = bar_pane_rating_event;
+	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->key = g_strdup(key);
+	prd->height = height;
+
+	// HBOX
+	hbox = (GtkHBox*)gtk_hbox_new(FALSE, 0);
+
+	prd->container = hbox;
+	g_object_set_data(G_OBJECT(prd->container), "pane_data", prd);
+	g_signal_connect(G_OBJECT(prd->container), "destroy",
+			 G_CALLBACK(bar_pane_rating_destroy), prd);
+
+	gtk_widget_set_size_request((GtkWidget*) prd->container, -1, -1);
+	gtk_widget_show((GtkWidget*) hbox);
+
+	// AUTOADVANCE CHECKBOX
+	tmp = gtk_check_button_new_with_label("AA");
+	gtk_box_pack_start((GtkBox*) hbox, tmp, TRUE, TRUE, 0);
+	gtk_widget_show(tmp);
+	prd->auto_adv = (GtkToggleButton*) tmp;
+
+	// INCREMENT/DECREMENT BUTTONS
+	tmp = gtk_button_new_with_label(_("↓ Dec."));
+	gtk_box_pack_start((GtkBox*) hbox, tmp, TRUE, TRUE, 0);
+	g_signal_connect(G_OBJECT(tmp), "clicked", G_CALLBACK(bar_pane_rating_dec_value_cb), prd);
+	gtk_widget_show(tmp);
+
+	tmp = gtk_button_new_with_label(_("↑ Inc."));
+	gtk_box_pack_end((GtkBox*) hbox, tmp, TRUE, TRUE, 0);
+	g_signal_connect(G_OBJECT(tmp), "clicked", G_CALLBACK(bar_pane_rating_inc_value_cb), prd);
+	gtk_widget_show(tmp);
+
+
+	// SPIN BUTTON
+	prd->spinbutton = (GtkSpinButton*) gtk_spin_button_new_with_range(0.0, 10.0, 1.0);
+	gtk_spin_button_set_numeric(prd->spinbutton, TRUE);
+	gtk_spin_button_set_snap_to_ticks(prd->spinbutton, TRUE);
+
+	gtk_box_pack_start((GtkBox*) hbox, (GtkWidget*) prd->spinbutton, FALSE, TRUE, 0);
+//	g_signal_connect(G_OBJECT(pcd->comment_view), "populate-popup",
+//			 G_CALLBACK(bar_pane_comment_populate_popup), pcd);
+	gtk_widget_show((GtkWidget*) prd->spinbutton);
+
+	g_signal_connect(G_OBJECT(prd->spinbutton), "value-changed",
+			 G_CALLBACK(bar_pane_rating_changed), prd);
+
+
+	file_data_register_notify_func(bar_pane_rating_notify_cb, prd, NOTIFY_PRIORITY_LOW);
+
+	return (GtkWidget*) prd->container;
+}
+
+GtkWidget *bar_pane_rating_new_from_config(const gchar **attribute_names,
+	const gchar **attribute_values)
+{
+	gchar *title = NULL;
+	gchar *key = g_strdup(RATING_KEY);
+	gboolean expanded = TRUE;
+	gint height = 50;
+	gchar *id = g_strdup("rating");
+	GtkWidget *ret;
+
+	while (*attribute_names)
+		{
+		const gchar *option = *attribute_names++;
+		const gchar *value = *attribute_values++;
+
+		if (READ_CHAR_FULL("title", title)) continue;
+		if (READ_CHAR_FULL("key", key)) continue;
+		if (READ_BOOL_FULL("expanded", expanded)) continue;
+		if (READ_INT_FULL("height", height)) continue;
+		if (READ_CHAR_FULL("id", id)) 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, key, expanded, height);
+	g_free(title);
+	g_free(key);
+	g_free(id);
+	return ret;
+}
+
+void bar_pane_rating_update_from_config(GtkWidget *pane, const gchar **attribute_names,
+	const gchar **attribute_values)
+{
+	PaneRatingData *prd;
+
+	prd = g_object_get_data(G_OBJECT(pane), "pane_data");
+	if (!prd) return;
+
+	gchar *title = NULL;
+
+	while (*attribute_names)
+		{
+		const gchar *option = *attribute_names++;
+		const gchar *value = *attribute_values++;
+
+		if (READ_CHAR_FULL("title", title)) continue;
+		if (READ_CHAR_FULL("key", prd->key)) continue;
+		if (READ_BOOL_FULL("expanded", prd->pane.expanded)) continue;
+		if (READ_INT_FULL("height", prd->height)) continue;
+		if (READ_CHAR_FULL("id", prd->pane.id)) continue;
+
+
+		log_printf("unknown attribute %s = %s\n", option, value);
+		}
+
+	if (title)
+		{
+		bar_pane_translate_title(PANE_RATING, prd->pane.id, &title);
+		gtk_label_set_text(GTK_LABEL(prd->pane.title), title);
+		g_free(title);
+		}
+	gtk_widget_set_size_request((GtkWidget*) prd->container, -1, -1);
+	bar_update_expander(pane);
+	bar_pane_rating_update(prd);
+}
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff --git a/trunk/src/bar_rating.h b/trunk/src/bar_rating.h
new file mode 100644
index 0000000..7453a4c
--- /dev/null
+++ b/trunk/src/bar_rating.h
@@ -0,0 +1,27 @@
+/*
+ * Geeqie
+ * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2009 The Geeqie Team
+ *
+ * Author: Omari Stephens
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+
+#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);
+void bar_pane_rating_inc_value(gpointer data);
+void bar_pane_rating_dec_value(gpointer data);
+void bar_pane_rating_set_value(gint value, gpointer data);
+
+
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff --git a/trunk/src/layout_util.c b/trunk/src/layout_util.c
index b853852..fa09e4f 100644
--- a/trunk/src/layout_util.c
+++ b/trunk/src/layout_util.c
@@ -17,6 +17,7 @@
 #include "advanced_exif.h"
 #include "bar_sort.h"
 #include "bar.h"
+#include "bar_rating.h"
 #include "cache_maint.h"
 #include "collect.h"
 #include "collect-dlg.h"
@@ -750,6 +751,38 @@ static void layout_menu_bar_exif_cb(GtkAction *action, gpointer data)
 	layout_exif_window_new(lw);
 }
 
+static void layout_menu_bar_rating_cb(GtkAction *action, gpointer data)
+{
+	LayoutWindow *lw = data;
+	GtkWidget *pane;
+	void *prd;
+	const gchar *action_name;
+
+	if(!lw->bar) return;
+
+	pane = bar_find_pane_by_id(lw->bar, PANE_RATING, "rating");
+	if(!pane) return;
+
+	prd = g_object_get_data(G_OBJECT(pane), "pane_data");
+	if(!prd) return;
+
+	// Got a pane; now poke at it
+	action_name = gtk_action_get_name(action);
+	if(!g_strcmp0(action_name, "IncRating")) bar_pane_rating_inc_value(prd);
+	else if(!g_strcmp0(action_name, "DecRating")) bar_pane_rating_dec_value(prd);
+	else if(!g_strcmp0(action_name, "Rating0")) bar_pane_rating_set_value(0, prd);
+	else if(!g_strcmp0(action_name, "Rating1")) bar_pane_rating_set_value(1, prd);
+	else if(!g_strcmp0(action_name, "Rating2")) bar_pane_rating_set_value(2, prd);
+	else if(!g_strcmp0(action_name, "Rating3")) bar_pane_rating_set_value(3, prd);
+	else if(!g_strcmp0(action_name, "Rating4")) bar_pane_rating_set_value(4, prd);
+	else if(!g_strcmp0(action_name, "Rating5")) bar_pane_rating_set_value(5, prd);
+	else if(!g_strcmp0(action_name, "Rating6")) bar_pane_rating_set_value(6, prd);
+	else if(!g_strcmp0(action_name, "Rating7")) bar_pane_rating_set_value(7, prd);
+	else if(!g_strcmp0(action_name, "Rating8")) bar_pane_rating_set_value(8, prd);
+	else if(!g_strcmp0(action_name, "Rating9")) bar_pane_rating_set_value(9, prd);
+	else if(!g_strcmp0(action_name, "Rating10")) bar_pane_rating_set_value(10, prd);
+}
+
 static void layout_menu_float_cb(GtkToggleAction *action, gpointer data)
 {
 	LayoutWindow *lw = data;
@@ -1236,6 +1269,8 @@ static GtkActionEntry menu_entries[] = {
   { "EditMenu",		NULL,			N_("_Edit"),				NULL, 			NULL,					NULL },
   { "SelectMenu",	NULL,			N_("_Select"),				NULL, 			NULL,					NULL },
   { "OrientationMenu",	NULL,			N_("_Orientation"),			NULL, 			NULL,					NULL },
+  { "MetadataMenu",	NULL,			N_("_Metadata"),			NULL, 			NULL,					NULL },
+  { "MetadataRateMenu",	NULL,			N_("_Set Rating"),			NULL, 			NULL,					NULL },
   { "ExternalMenu",	NULL,			N_("E_xternal Editors"),		NULL, 			NULL,					NULL },
   { "PreferencesMenu",	NULL,			N_("P_references"),			NULL, 			NULL,					NULL },
   { "ViewMenu",		NULL,			N_("_View"),				NULL, 			NULL,					NULL },
@@ -1293,6 +1328,19 @@ static GtkActionEntry menu_entries[] = {
   { "Maintenance",	NULL,			N_("_Thumbnail maintenance..."),	NULL,			N_("Thumbnail maintenance..."),		CB(layout_menu_remove_thumb_cb) },
   { "Wallpaper",	NULL,			N_("Set as _wallpaper"),		NULL,			N_("Set as wallpaper"),			CB(layout_menu_wallpaper_cb) },
   { "SaveMetadata",	GTK_STOCK_SAVE,		N_("_Save metadata"),			"<control>S",		N_("Save metadata"),			CB(layout_menu_metadata_write_cb) },
+  { "IncRating",	NULL,			N_("_Increment Rating"),		"<alt>KP_Add",		N_("Increment image rating"),		CB(layout_menu_bar_rating_cb) },
+  { "DecRating",	NULL,			N_("_Decrement Rating"),		"<alt>KP_Subtract",	N_("Decrement image rating"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating0",		NULL,			N_("Rate _0"),				"<alt>KP_0",		N_("Set image rating to 0"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating1",		NULL,			N_("Rate _1"),				"<alt>KP_1",		N_("Set image rating to 1"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating2",		NULL,			N_("Rate _2"),				"<alt>KP_2",		N_("Set image rating to 2"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating3",		NULL,			N_("Rate _3"),				"<alt>KP_3",		N_("Set image rating to 3"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating4",		NULL,			N_("Rate _4"),				"<alt>KP_4",		N_("Set image rating to 4"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating5",		NULL,			N_("Rate _5"),				"<alt>KP_5",		N_("Set image rating to 5"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating6",		NULL,			N_("Rate _6"),				"<alt>KP_6",		N_("Set image rating to 6"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating7",		NULL,			N_("Rate _7"),				"<alt>KP_7",		N_("Set image rating to 7"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating8",		NULL,			N_("Rate _8"),				"<alt>KP_8",		N_("Set image rating to 8"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating9",		NULL,			N_("Rate _9"),				"<alt>KP_9",		N_("Set image rating to 9"),		CB(layout_menu_bar_rating_cb) },
+  { "Rating10",		NULL,			N_("Rate _10"),				"<alt>KP_Decimal",	N_("Set image rating to 10"),		CB(layout_menu_bar_rating_cb) },
   { "ZoomIn",		GTK_STOCK_ZOOM_IN,	N_("Zoom _in"),				"equal",		N_("Zoom in"),				CB(layout_menu_zoom_in_cb) },
   { "ZoomInAlt1",	GTK_STOCK_ZOOM_IN,	N_("Zoom _in"),				"KP_Add",		N_("Zoom in"),				CB(layout_menu_zoom_in_cb) },
   { "ZoomOut",		GTK_STOCK_ZOOM_OUT,	N_("Zoom _out"),			"minus",		N_("Zoom out"),				CB(layout_menu_zoom_out_cb) },
@@ -1343,7 +1391,6 @@ static GtkActionEntry menu_entries[] = {
   { "About",		GTK_STOCK_ABOUT,	N_("_About"),				NULL,			N_("About"),				CB(layout_menu_about_cb) },
   { "LogWindow",	NULL,			N_("_Log Window"),			NULL,			N_("Log Window"),			CB(layout_menu_log_window_cb) },
   { "ExifWin",		NULL,			N_("_Exif window"),			"<control>E",		N_("Exif window"),			CB(layout_menu_bar_exif_cb) },
-
 };
 
 static GtkToggleActionEntry menu_toggle_entries[] = {
@@ -1469,7 +1516,25 @@ static const gchar *menu_ui_description =
 "        <menuitem action='Flip'/>"
 "        <menuitem action='AlterNone'/>"
 "      </menu>"
-"      <menuitem action='SaveMetadata'/>"
+"      <menu action='MetadataMenu'>"
+"        <menuitem action='SaveMetadata'/>"
+"        <separator/>"
+"        <menuitem action='IncRating'/>"
+"        <menuitem action='DecRating'/>"
+"        <menu action='MetadataRateMenu'>"
+"          <menuitem action='Rating0'/>"
+"          <menuitem action='Rating1'/>"
+"          <menuitem action='Rating2'/>"
+"          <menuitem action='Rating3'/>"
+"          <menuitem action='Rating4'/>"
+"          <menuitem action='Rating5'/>"
+"          <menuitem action='Rating6'/>"
+"          <menuitem action='Rating7'/>"
+"          <menuitem action='Rating8'/>"
+"          <menuitem action='Rating9'/>"
+"          <menuitem action='Rating10'/>"
+"        </menu>"
+"      </menu>"
 "      <placeholder name='PropertiesSection'/>"
 "      <separator/>"
 "        <menu action='PreferencesMenu'>"
diff --git a/trunk/src/metadata.h b/trunk/src/metadata.h
index 639da6d..be265cc 100644
--- a/trunk/src/metadata.h
+++ b/trunk/src/metadata.h
@@ -17,6 +17,7 @@
 #define COMMENT_KEY "Xmp.dc.description"
 #define KEYWORD_KEY "Xmp.dc.subject"
 #define ORIENTATION_KEY "Xmp.tiff.Orientation"
+#define RATING_KEY "Xmp.xmp.Rating"
 
 gboolean metadata_write_queue_remove(FileData *fd);
 gboolean metadata_write_queue_remove_list(GList *list);
diff --git a/trunk/src/rcfile.c b/trunk/src/rcfile.c
index 4053b58..babd0a4 100644
--- a/trunk/src/rcfile.c
+++ b/trunk/src/rcfile.c
@@ -22,6 +22,7 @@
 #include "bar_histogram.h"
 #include "bar_keywords.h"
 #include "bar_sort.h"
+#include "bar_rating.h"
 #include "editors.h"
 #include "filefilter.h"
 #include "misc.h"
@@ -918,6 +919,22 @@ 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);
+		}
 #ifdef HAVE_LIBCHAMPLAIN
 #ifdef HAVE_LIBCHAMPLAIN_GTK
 	else if (g_ascii_strcasecmp(element_name, "pane_gps") == 0)
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Geeqie-devel mailing list
Geeqie-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geeqie-devel

Reply via email to