# HG changeset patch
# User nadvornik
# Date 1242152718 0
# Node ID c6d522fe3e5e981d3d1bcbe9bc3c0dfeff1755cf
# Parent 1b29d244599143d8c3c67d8ea3da120709fbdc30
added GPS map support - patch by Colin Clark
diff -r 1b29d2445991 -r c6d522fe3e5e configure.in
--- a/configure.in Tue May 12 06:54:05 2009 +0000
+++ b/configure.in Tue May 12 18:25:18 2009 +0000
@@ -328,6 +328,45 @@
AC_SUBST(LDFLAGS)
+# Libchamplain support - used for GPS map facility - experimental
+# ----------------------------------------------------------------------
+
+AC_ARG_ENABLE([gps],
+ AC_HELP_STRING([--enable-gps], [enable GPS map support - experimental]),
+ [libgps=$enableval], [libgps=auto])
+
+if test "x${libgps}" == "xyes"; then
+ PKG_CHECK_MODULES(LIBCHAMPLAIN, [champlain-0.3 >= 0.3],
+ [
+ HAVE_LIBCHAMPLAIN=yes
+ AC_DEFINE(HAVE_LIBCHAMPLAIN, 1, [define to enable use of GPS maps])
+ ],
+ [
+ HAVE_LIBCHAMPLAIN=no
+ AC_MSG_WARN([$LIBCHAMPLAIN_PKG_ERRORS])
+ ])
+else
+ HAVE_LIBCHAMPLAIN=disabled
+fi
+
+if test "x${libgps}" == "xyes"; then
+ PKG_CHECK_MODULES(LIBCHAMPLAIN_GTK, [champlain-gtk-0.3 >= 0.3],
+ [
+ HAVE_LIBCHAMPLAIN_GTK=yes
+ AC_DEFINE(HAVE_LIBCHAMPLAIN_GTK, 1, [define to enable use of GPS maps])
+ ],
+ [
+ HAVE_LIBCHAMPLAIN_GTK=no
+ AC_MSG_WARN([$LIBCHAMPLAIN_GTK_PKG_ERRORS])
+ ])
+else
+ HAVE_LIBCHAMPLAIN_GTK=disabled
+fi
+
+AM_CONDITIONAL(HAVE_LIBCHAMPLAIN_GTK, [test "x$HAVE_LIBCHAMPLAIN_GTK" = xyes])
+AC_SUBST(LIBCHAMPLAIN_GTK_CFLAGS)
+AC_SUBST(LIBCHAMPLAIN_GTK_LIBS)
+
AH_TOP([
/** @file config.h
* autogenerated definition by autoheader.
@@ -398,7 +437,7 @@
Gtk: $GTK_CFLAGS
Glib: $GLIB_CFLAGS
Thread: $GTHREAD_LIBS
- Others: $LCMS_LIBS $EXIV2_LIBS
+ Others: $LCMS_LIBS $EXIV2_LIBS $LIBCHAMPLAIN_LIBS $LIBCHAMPLAIN_GTK_LIBS
Localization:
NLS support: $USE_NLS
@@ -414,6 +453,8 @@
LCMS: $HAVE_LCMS
Exiv2: $HAVE_EXIV2
Lirc: $HAVE_LIRC
+ Libchamplain: $HAVE_LIBCHAMPLAIN
+ Libchamplain-gtk: $HAVE_LIBCHAMPLAIN_GTK
Documentation:
Doxygen: $DOXYGEN
diff -r 1b29d2445991 -r c6d522fe3e5e src/Makefile.am
--- a/src/Makefile.am Tue May 12 06:54:05 2009 +0000
+++ b/src/Makefile.am Tue May 12 18:25:18 2009 +0000
@@ -5,6 +5,8 @@
$(GLIB_CFLAGS) $(GTK_CFLAGS) \
$(LCMS_CFLAGS) \
$(EXIV2_CFLAGS) \
+ $(LIBCHAMPLAIN_CFLAGS) \
+ $(LIBCHAMPLAIN_GTK_CFLAGS)
-I$(top_srcdir) \
-I$(top_builddir)
@@ -13,6 +15,8 @@
$(GLIB_CFLAGS) $(GTK_CFLAGS) \
$(LCMS_CFLAGS) \
$(EXIV2_CFLAGS) \
+ $(LIBCHAMPLAIN_CFLAGS) \
+ $(LIBCHAMPLAIN_GTK_CFLAGS)
-I$(top_srcdir) \
-I$(top_builddir)
@@ -83,6 +87,8 @@
bar.h \
bar_comment.c \
bar_comment.h \
+ bar_gps.c \
+ bar_gps.h \
bar_histogram.c \
bar_histogram.h \
bar_keywords.c \
@@ -238,7 +244,7 @@
window.c \
window.h
-geeqie_LDADD = $(GTK_LIBS) $(GLIB_LIBS) $(INTLLIBS) $(LCMS_LIBS) $(EXIV2_LIBS)
+geeqie_LDADD = $(GTK_LIBS) $(GLIB_LIBS) $(INTLLIBS) $(LCMS_LIBS) $(EXIV2_LIBS) $(LIBCHAMPLAIN_LIBS) $(LIBCHAMPLAIN_GTK_LIBS)
EXTRA_DIST = \
$(extra_SLIK)
diff -r 1b29d2445991 -r c6d522fe3e5e src/bar.c
--- a/src/bar.c Tue May 12 06:54:05 2009 +0000
+++ b/src/bar.c Tue May 12 18:25:18 2009 +0000
@@ -29,6 +29,7 @@
#include "bar_histogram.h"
#include "histogram.h"
#include "rcfile.h"
+#include "bar_gps.h"
typedef struct _KnownPanes KnownPanes;
struct _KnownPanes
@@ -144,6 +145,23 @@
" "
"";
+#ifdef HAVE_LIBCHAMPLAIN
+#ifdef HAVE_LIBCHAMPLAIN_GTK
+static const gchar default_config_gps[] =
+""
+" "
+" "
+" "
+" "
+" "
+"";
+#endif
+#endif
+
static const KnownPanes known_panes[] = {
/* default sidebar */
{PANE_HISTOGRAM, "histogram", N_("Histogram"), default_config_histogram},
@@ -155,7 +173,11 @@
{PANE_EXIF, "file_info", N_("File info"), default_config_file_info},
{PANE_EXIF, "location", N_("Location and GPS"), default_config_location},
{PANE_EXIF, "copyright", N_("Copyright"), default_config_copyright},
-
+#ifdef HAVE_LIBCHAMPLAIN
+#ifdef HAVE_LIBCHAMPLAIN_GTK
+ {PANE_GPS, "gps", N_("GPS Map"), default_config_gps},
+#endif
+#endif
{PANE_UNDEF, NULL, NULL, NULL}
};
diff -r 1b29d2445991 -r c6d522fe3e5e src/bar.h
--- a/src/bar.h Tue May 12 06:54:05 2009 +0000
+++ b/src/bar.h Tue May 12 18:25:18 2009 +0000
@@ -19,7 +19,8 @@
PANE_COMMENT,
PANE_EXIF,
PANE_HISTOGRAM,
- PANE_KEYWORDS
+ PANE_KEYWORDS,
+ PANE_GPS
} PaneType;
typedef struct _PaneData PaneData;
diff -r 1b29d2445991 -r c6d522fe3e5e src/bar_gps.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bar_gps.c Tue May 12 18:25:18 2009 +0000
@@ -0,0 +1,906 @@
+/*
+ * Geeqie
+ * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2009 The Geeqie Team
+ *
+ * Author: Colin Clark
+ *
+ * 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"
+#ifdef HAVE_LIBCHAMPLAIN
+#ifdef HAVE_LIBCHAMPLAIN_GTK
+
+#include "bar_gps.h"
+
+#include "bar.h"
+#include "filedata.h"
+#include "layout.h"
+#include "metadata.h"
+#include "menu.h"
+#include "rcfile.h"
+#include "thumb.h"
+#include "ui_menu.h"
+
+#include
+#include
+#include
+
+#define MARKER_COLOUR 0x00, 0x00, 0xff, 0xff
+#define TEXT_COLOUR 0x00, 0x00, 0x00, 0xff
+#define THUMB_COLOUR 0xff, 0xff, 0xff, 0xff
+#define THUMB_SIZE 100
+
+/*
+ *-------------------------------------------------------------------
+ * GPS Map utils
+ *-------------------------------------------------------------------
+ */
+
+typedef struct _PaneGPSData PaneGPSData;
+struct _PaneGPSData
+{
+ PaneData pane;
+ GtkWidget *widget;
+ FileData *fd;
+ gchar *map_source;
+ gint height;
+ ClutterActor *gps_view;
+ ChamplainLayer *icon_layer;
+ GList *selection_list;
+ GPtrArray *marker_list;
+ guint create_markers_id;
+ GtkWidget *progress;
+ GtkWidget *slider;
+ GtkWidget *state;
+ gint selection_count;
+ gboolean centre_map_checked;
+ gboolean enable_markers_checked;
+};
+
+static void bar_pane_gps_thumb_done_cb(ThumbLoader *tl, gpointer data)
+{
+ FileData *fd;
+ ClutterActor *marker;
+ ClutterActor *actor;
+
+ marker = CLUTTER_ACTOR(data);
+ fd = g_object_get_data(G_OBJECT(marker), "file_fd");
+ if (fd->thumb_pixbuf != NULL)
+ {
+ actor = clutter_texture_new();
+ gtk_clutter_texture_set_from_pixbuf(CLUTTER_TEXTURE(actor), fd->thumb_pixbuf);
+ champlain_marker_set_image(CHAMPLAIN_MARKER(marker), actor);
+ }
+ thumb_loader_free(tl);
+}
+
+static void bar_pane_gps_thumb_error_cb(ThumbLoader *tl, gpointer data)
+{
+ thumb_loader_free(tl);
+}
+
+static gboolean bar_pane_gps_marker_keypress_cb(GtkWidget *widget, ClutterButtonEvent *bevent, gpointer data)
+{
+ //PaneGPSData *pgd = data;
+ FileData *fd;
+ ClutterActor *marker;
+ ClutterColor marker_colour = { MARKER_COLOUR };
+ ClutterColor text_colour = { TEXT_COLOUR };
+ ClutterColor thumb_colour = { THUMB_COLOUR };
+ gchar *current_text;
+ ClutterActor *actor;
+ ClutterActor *current_image;
+ GString *text;
+ gint height, width, rotate;
+ gchar *altitude = NULL;
+ ThumbLoader *tl;
+
+ if (bevent->button == MOUSE_BUTTON_LEFT)
+ {
+ marker = CLUTTER_ACTOR(widget);
+ fd = g_object_get_data(G_OBJECT(marker), "file_fd");
+
+ /* If the marker is showing a thumbnail, delete it
+ */
+ current_image = champlain_marker_get_image(CHAMPLAIN_MARKER(marker));
+ if (current_image != NULL)
+ {
+ clutter_actor_destroy(CLUTTER_ACTOR(current_image));
+ champlain_marker_set_image(CHAMPLAIN_MARKER(marker), NULL);
+ }
+
+ current_text = g_strdup(champlain_marker_get_text(CHAMPLAIN_MARKER(marker)));
+
+ /* If the marker is showing only the text character, replace it with a
+ * thumbnail and date and altitude
+ */
+ if (g_strcmp0(current_text, "i") == 0)
+ {
+ /* If a thumbail has already been generated, use that. If not try the pixbuf of the full image.
+ * If not, call the thumb_loader to generate a thumbnail and update the marker later in the
+ * thumb_loader callback
+ */
+ if (fd->thumb_pixbuf != NULL)
+ {
+ actor = clutter_texture_new();
+ gtk_clutter_texture_set_from_pixbuf(CLUTTER_TEXTURE(actor), fd->thumb_pixbuf);
+ champlain_marker_set_image(CHAMPLAIN_MARKER(marker), actor);
+ }
+ else if (fd->pixbuf != NULL)
+ {
+ actor = clutter_texture_new();
+ width = gdk_pixbuf_get_width (fd->pixbuf);
+ height = gdk_pixbuf_get_height (fd->pixbuf);
+ switch (fd->exif_orientation)
+ {
+ case 8:
+ rotate = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
+ break;
+ case 3:
+ rotate = GDK_PIXBUF_ROTATE_UPSIDEDOWN;
+ break;
+ case 6:
+ rotate = GDK_PIXBUF_ROTATE_CLOCKWISE;
+ break;
+ default:
+ rotate = GDK_PIXBUF_ROTATE_NONE;
+ }
+
+ gtk_clutter_texture_set_from_pixbuf(CLUTTER_TEXTURE(actor),
+ gdk_pixbuf_rotate_simple(gdk_pixbuf_scale_simple(fd->pixbuf, THUMB_SIZE, height * THUMB_SIZE / width,
+ GDK_INTERP_NEAREST), rotate));
+ champlain_marker_set_image(CHAMPLAIN_MARKER(marker), actor);
+ }
+ else
+ {
+ tl = thumb_loader_new(THUMB_SIZE, THUMB_SIZE);
+ thumb_loader_set_callbacks(tl,
+ bar_pane_gps_thumb_done_cb,
+ bar_pane_gps_thumb_error_cb,
+ NULL,
+ marker);
+ thumb_loader_start(tl, fd);
+ }
+
+ text = g_string_new(fd->name);
+ g_string_append(text, "\n");
+ g_string_append(text, text_from_time(fd->date));
+ g_string_append(text, "\n");
+ altitude = metadata_read_string(fd, "formatted.GPSAltitude", METADATA_FORMATTED);
+ if (altitude != NULL)
+ {
+ g_string_append(text, altitude);
+ }
+
+ champlain_marker_set_text(CHAMPLAIN_MARKER(marker), text->str);
+ champlain_marker_set_color(CHAMPLAIN_MARKER(marker), &thumb_colour);
+ champlain_marker_set_text_color(CHAMPLAIN_MARKER(marker), &text_colour);
+ champlain_marker_set_font_name(CHAMPLAIN_MARKER(marker), "sans 8");
+
+ g_free(altitude);
+ g_string_free(text, TRUE);
+ }
+ /* otherwise, revert to the hidden text marker
+ */
+ else
+ {
+ champlain_marker_set_text(CHAMPLAIN_MARKER(marker), "i");
+ champlain_marker_set_color(CHAMPLAIN_MARKER(marker), &marker_colour);
+ champlain_marker_set_text_color(CHAMPLAIN_MARKER(marker), &marker_colour);
+ champlain_marker_set_font_name(CHAMPLAIN_MARKER(marker), "courier 5");
+ }
+
+ g_free(current_text);
+
+ return TRUE;
+ }
+ return TRUE;
+}
+
+static gboolean bar_pane_gps_create_markers_cb(gpointer data)
+{
+ PaneGPSData *pgd = data;
+ gdouble latitude;
+ gdouble longitude;
+ GList *work;
+ ClutterActor *marker;
+ FileData *fd;
+ ClutterColor marker_colour = { MARKER_COLOUR };
+ GString *message;
+
+ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pgd->progress),
+ (gdouble)(pgd->selection_count - g_list_length(pgd->selection_list)) /
+ (gdouble)pgd->selection_count);
+
+ message = g_string_new("");
+ g_string_printf(message, "%i/%i", (pgd->selection_count - g_list_length(pgd->selection_list)),
+ pgd->selection_count);
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pgd->progress), message->str);
+ g_string_free(message, TRUE);
+
+ work = pgd->selection_list;
+ while (work)
+ {
+ fd = work->data;
+ pgd->selection_list = g_list_remove(pgd->selection_list, work->data);
+ if (fd != NULL)
+ {
+ latitude = metadata_read_GPS_coord(fd, "Xmp.exif.GPSLatitude", 1000);
+ longitude = metadata_read_GPS_coord(fd, "Xmp.exif.GPSLongitude", 1000);
+
+ if ((latitude != 1000) && (longitude != 1000))
+ {
+ marker = champlain_marker_new_with_text("i","courier 5", &marker_colour, &marker_colour);
+
+ champlain_base_marker_set_position(CHAMPLAIN_BASE_MARKER(marker), latitude, longitude);
+ clutter_container_add(CLUTTER_CONTAINER(pgd->icon_layer), marker, NULL);
+ clutter_actor_set_reactive(marker, TRUE);
+
+ g_signal_connect(G_OBJECT(marker), "button_press_event",
+ G_CALLBACK(bar_pane_gps_marker_keypress_cb), pgd);
+
+ g_object_set_data(G_OBJECT(marker), "file_fd", fd);
+
+ g_ptr_array_add(pgd->marker_list, marker);
+ if (pgd->centre_map_checked)
+ {
+ g_ptr_array_add(pgd->marker_list, NULL);
+ champlain_view_ensure_markers_visible(CHAMPLAIN_VIEW(pgd->gps_view),
+ (void *)pgd->marker_list->pdata, FALSE);
+ g_ptr_array_remove(pgd->marker_list, NULL);
+ }
+ }
+ }
+ return TRUE;
+ }
+
+ if (pgd->marker_list->len >= 1)
+ {
+ g_ptr_array_add(pgd->marker_list, NULL);
+
+ if (pgd->centre_map_checked)
+ {
+ champlain_view_ensure_markers_visible(CHAMPLAIN_VIEW(pgd->gps_view), (void *)pgd->marker_list->pdata, FALSE);
+ }
+ }
+
+ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pgd->progress), 0);
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pgd->progress), NULL);
+ g_list_free(pgd->selection_list);
+ g_ptr_array_free(pgd->marker_list, TRUE);
+ pgd->create_markers_id = 0;
+
+ return FALSE;
+}
+
+static void bar_pane_gps_update(PaneGPSData *pgd)
+{
+ GList *list;
+ GList *work;
+
+ /* The widget does not have a parent during bar_pane_gps_new, so calling gtk_widget_show_all there gives a
+ * "Gtk-CRITICAL **: gtk_widget_realize: assertion `GTK_WIDGET_ANCHORED (widget) || GTK_IS_INVISIBLE (widget)' failed"
+ * error. gtk_widget_show_all can be given after it has been added to the bar.
+ */
+ if (gtk_widget_get_parent(pgd->widget) != NULL)
+ gtk_widget_show_all(pgd->widget);
+
+ /* If a create-marker background process is running, kill it
+ * and start again
+ */
+ if (pgd->create_markers_id != 0)
+ {
+ if (g_idle_remove_by_data(pgd))
+ {
+ pgd->create_markers_id = 0;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ /* Delete any markers currently displayed
+ */
+ work = clutter_container_get_children(CLUTTER_CONTAINER(pgd->icon_layer));
+ while (work)
+ {
+ clutter_container_remove(CLUTTER_CONTAINER(pgd->icon_layer), work->data, NULL);
+ work = work->next;
+ }
+ g_list_free(work);
+
+ if (!pgd->enable_markers_checked)
+ {
+ return;
+ }
+
+ /* For each selected photo that has GPS data, create a marker containing
+ * a single, small text character the same colour as the marker background.
+ * Use a background process in case the user selects a large number of files.
+ */
+ list = layout_selection_list(pgd->pane.lw);
+
+ if (list != NULL)
+ {
+ pgd->selection_list = g_list_copy(list);
+ pgd->marker_list = g_ptr_array_new();
+ pgd->selection_count = g_list_length(pgd->selection_list);
+ pgd->create_markers_id = g_idle_add(bar_pane_gps_create_markers_cb, pgd);
+ }
+
+ g_list_free(list);
+ g_list_free(work);
+}
+
+void bar_pane_gps_set_map_source(PaneGPSData *pgd, const gchar *map_id)
+{
+ ChamplainMapSource *map_source;
+ ChamplainMapSourceFactory *map_factory;
+
+ map_factory = champlain_map_source_factory_get_default();
+ map_source = champlain_map_source_factory_create(map_factory, map_id);
+
+ if (map_source != NULL)
+ {
+ g_object_set(G_OBJECT(pgd->gps_view), "map-source", map_source, NULL);
+ g_object_unref(map_factory);
+ }
+
+ g_object_unref(map_source);
+}
+
+void bar_pane_gps_enable_markers_checked_toggle_cb(GtkWidget *menu_widget, gpointer data)
+{
+ PaneGPSData *pgd = data;
+
+ if (pgd->enable_markers_checked)
+ {
+ pgd->enable_markers_checked = FALSE;
+ }
+ else
+ {
+ pgd->enable_markers_checked = TRUE;
+ }
+}
+
+static void bar_pane_gps_centre_map_checked_toggle_cb(GtkWidget *menu_widget, gpointer data)
+{
+ PaneGPSData *pgd = data;
+
+ if (pgd->centre_map_checked)
+ {
+ pgd->centre_map_checked = FALSE;
+ }
+ else
+ {
+ pgd->centre_map_checked = TRUE;
+ }
+}
+
+static void bar_pane_gps_change_map_cb(GtkWidget *widget, gpointer data)
+{
+ PaneGPSData *pgd;
+ gchar *mapsource;
+
+ if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
+ return;
+
+ pgd = (PaneGPSData *) submenu_item_get_data(widget);
+
+ if (!pgd) return;
+
+ mapsource = data;
+ bar_pane_gps_set_map_source(pgd, mapsource);
+}
+
+static void bar_pane_gps_notify_selection(GtkWidget *bar, gint count)
+{
+ PaneGPSData *pgd;
+
+ if (count == 0) return;
+
+ pgd = g_object_get_data(G_OBJECT(bar), "pane_data");
+ if (!pgd) return;
+
+ bar_pane_gps_update(pgd);
+}
+
+static void bar_pane_gps_set_fd(GtkWidget *bar, FileData *fd)
+{
+ PaneGPSData *pgd;
+
+ pgd = g_object_get_data(G_OBJECT(bar), "pane_data");
+ if (!pgd) return;
+
+ file_data_unref(pgd->fd);
+ pgd->fd = file_data_ref(fd);
+
+ bar_pane_gps_update(pgd);
+}
+
+static gint bar_pane_gps_event(GtkWidget *bar, GdkEvent *event)
+{
+ PaneGPSData *pgd;
+
+ pgd = g_object_get_data(G_OBJECT(bar), "pane_data");
+ if (!pgd) return FALSE;
+
+ if (GTK_WIDGET_HAS_FOCUS(pgd->widget)) return gtk_widget_event(GTK_WIDGET(pgd->widget), event);
+
+ return FALSE;
+}
+
+static void bar_pane_gps_write_config(GtkWidget *pane, GString *outstr, gint indent)
+{
+ PaneGPSData *pgd;
+ gint zoom;
+ ChamplainMapSource *mapsource;
+ const gchar *map_id;
+ gchar *str = NULL;
+ GString *buffer = g_string_new(str);
+ gdouble position;
+ gint int_position;
+
+ pgd = g_object_get_data(G_OBJECT(pane), "pane_data");
+ if (!pgd) return;
+
+ WRITE_NL();
+ WRITE_STRING("pane.id);
+ write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(pgd->pane.title)));
+ WRITE_BOOL(pgd->pane, expanded);
+ WRITE_INT(*pgd, height);
+ indent++;
+
+ g_object_get(G_OBJECT(pgd->gps_view), "map-source", &mapsource, NULL);
+ map_id = champlain_map_source_get_id(mapsource);
+ WRITE_NL();
+ write_char_option(outstr, indent, "map-id", map_id);
+
+ g_object_get(G_OBJECT(pgd->gps_view), "zoom-level", &zoom, NULL);
+ g_string_printf(buffer, "%d", zoom);
+ WRITE_NL();
+ write_char_option(outstr, indent, "zoom-level", buffer->str);
+
+ g_object_get(G_OBJECT(pgd->gps_view), "latitude", &position, NULL);
+ int_position = position * 1000000;
+ g_string_printf(buffer, "%i", int_position);
+ WRITE_NL();
+ write_char_option(outstr, indent, "latitude", buffer->str);
+
+ g_object_get(G_OBJECT(pgd->gps_view), "longitude", &position, NULL);
+ int_position = position * 1000000;
+ g_string_printf(buffer, "%i", int_position);
+ WRITE_NL();
+ write_char_option(outstr, indent, "longitude", buffer->str);
+
+ indent--;
+ WRITE_NL();
+ WRITE_STRING("/>");
+
+ g_object_unref(mapsource);
+
+}
+
+static void bar_pane_gps_slider_changed_cb(GtkScaleButton *slider,
+ gdouble zoom,
+ gpointer data)
+{
+ PaneGPSData *pgd = data;
+ GString *message;
+
+ message = g_string_new("");
+ g_string_printf(message, _("Zoom %i"), (gint)zoom);
+
+ g_object_set(G_OBJECT(CHAMPLAIN_VIEW(pgd->gps_view)), "zoom-level", (gint)zoom, NULL);
+ gtk_widget_set_tooltip_text(GTK_WIDGET(slider), message->str);
+ g_string_free(message, TRUE);
+
+}
+static void bar_pane_gps_view_state_changed_cb(ChamplainView *view,
+ GParamSpec *gobject,
+ gpointer data)
+{
+ PaneGPSData *pgd = data;
+ ChamplainState status;
+ gint zoom;
+ GString *message;
+
+ g_object_get(G_OBJECT(view), "zoom-level", &zoom, NULL);
+ message = g_string_new("");
+ g_string_printf(message, _("Zoom level %i"), zoom);
+
+ g_object_get(G_OBJECT(view), "state", &status, NULL);
+ if (status == CHAMPLAIN_STATE_LOADING)
+ {
+ gtk_label_set_text(GTK_LABEL(pgd->state), _("Loading map"));
+ }
+ else
+ {
+ gtk_label_set_text(GTK_LABEL(pgd->state), message->str);
+ }
+
+ gtk_widget_set_tooltip_text(GTK_WIDGET(pgd->slider), message->str);
+ gtk_scale_button_set_value(GTK_SCALE_BUTTON(pgd->slider), (gdouble)zoom);
+
+ g_string_free(message, TRUE);
+}
+
+static void bar_pane_gps_notify_cb(FileData *fd, NotifyType type, gpointer data)
+{
+ PaneGPSData *pgd = data;
+
+ if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE | NOTIFY_METADATA)) && fd == pgd->fd)
+ {
+ bar_pane_gps_update(pgd);
+ }
+}
+
+const gchar *bar_pane_gps_get_map_id(PaneGPSData *pgd)
+{
+ const gchar *map_id;
+ ChamplainMapSource *mapsource;
+
+ g_object_get(G_OBJECT(pgd->gps_view), "map-source", &mapsource, NULL);
+ map_id = champlain_map_source_get_id(mapsource);
+
+ g_object_unref(mapsource);
+
+ return map_id;
+}
+
+static GtkWidget *bar_pane_gps_add_radio(GtkWidget *menu, GtkWidget *parent,
+ const gchar *label, GCallback func, gchar *value,
+ gboolean show_current, const gchar *current_value)
+{
+ GtkWidget *item;
+
+ if (show_current)
+ {
+ item = menu_item_add_radio(menu, parent,
+ label, (g_strcmp0(value, current_value) == 0), func, value);
+ }
+ else
+ {
+ item = menu_item_add(menu, label, func, value);
+ }
+
+ return item;
+}
+
+static GtkWidget *bar_pane_gps_menu(PaneGPSData *pgd)
+{
+ GtkWidget *menu;
+ GtkWidget *map_centre;
+ static gboolean show_current = TRUE;
+ GtkWidget *parent;
+ ChamplainMapSourceFactory *map_factory;
+ GSList *map_list;
+ ChamplainMapSourceDesc *map_desc;
+
+ menu = popup_menu_short_lived();
+
+ map_factory = champlain_map_source_factory_get_default();
+ map_list = champlain_map_source_factory_get_list(map_factory);
+ map_desc = (ChamplainMapSourceDesc *)(map_list->data);
+ map_list = g_slist_next(map_list);
+
+ g_object_set_data(G_OBJECT(menu), "submenu_data", pgd);
+
+ parent = bar_pane_gps_add_radio(menu, NULL, (map_desc->name), G_CALLBACK(bar_pane_gps_change_map_cb), map_desc->id, show_current, bar_pane_gps_get_map_id(pgd));
+
+ while (map_list)
+ {
+ map_desc = (ChamplainMapSourceDesc *)(map_list->data);
+ bar_pane_gps_add_radio(menu, parent, (map_desc->name), G_CALLBACK(bar_pane_gps_change_map_cb), map_desc->id,
+ show_current, bar_pane_gps_get_map_id(pgd));
+ map_list = g_slist_next(map_list);
+ }
+
+ menu_item_add_divider(menu);
+ menu_item_add_check(menu, _("Enable markers"), pgd->enable_markers_checked,
+ G_CALLBACK(bar_pane_gps_enable_markers_checked_toggle_cb), pgd);
+ map_centre = menu_item_add_check(menu, _("Centre map on marker"), pgd->centre_map_checked,
+ G_CALLBACK(bar_pane_gps_centre_map_checked_toggle_cb), pgd);
+ if (!pgd->enable_markers_checked)
+ {
+ gtk_widget_set_sensitive(map_centre, FALSE);
+ }
+
+ g_slist_free(map_list);
+ g_object_unref(map_factory);
+ //g_object_unref(map_centre);
+
+ return menu;
+}
+
+/* Determine if the map is to be re-centred on the marker when another photo is selected
+ */
+void bar_pane_gps_map_centreing(PaneGPSData *pgd)
+{
+ GtkWidget *dialog;
+ GString *message = g_string_new("");
+
+ if (pgd->centre_map_checked)
+ {
+ message = g_string_append(message, _("Move map centre to marker\n is disabled"));
+ pgd->centre_map_checked = FALSE;
+ }
+ else
+ {
+ message = g_string_append(message, _("Move map centre to marker\n is enabled"));
+ pgd->centre_map_checked = TRUE;
+ }
+
+ dialog = gtk_message_dialog_new(NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ "%s", message->str);
+ gtk_window_set_title(GTK_WINDOW(dialog), _("Map Centreing"));
+ gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+
+ gtk_widget_destroy(dialog);
+ g_string_free(message, TRUE);
+}
+
+static gboolean bar_pane_gps_map_keypress_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+{
+ PaneGPSData *pgd = data;
+ GtkWidget *menu;
+
+ if (bevent->button == MOUSE_BUTTON_RIGHT)
+ {
+ menu = bar_pane_gps_menu(pgd);
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
+ return TRUE;
+ }
+ else if (bevent->button == MOUSE_BUTTON_MIDDLE)
+ {
+ bar_pane_gps_map_centreing(pgd);
+ return TRUE;
+ }
+ else if (bevent->button == MOUSE_BUTTON_LEFT)
+ {
+ return FALSE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static void bar_pane_gps_destroy(GtkWidget *widget, gpointer data)
+{
+ PaneGPSData *pgd = data;
+
+ file_data_unregister_notify_func(bar_pane_gps_notify_cb, pgd);
+
+ file_data_unref(pgd->fd);
+ g_free(pgd->map_source);
+ g_free(pgd->pane.id);
+ clutter_actor_destroy(pgd->gps_view);
+ g_free(pgd);
+}
+
+
+GtkWidget *bar_pane_gps_new(const gchar *id, const gchar *title, const gchar *map_id,
+ const gint zoom, const gdouble latitude, const gdouble longitude,
+ gboolean expanded, gint height)
+{
+ PaneGPSData *pgd;
+ GtkWidget *vbox, *scrolled;
+ GtkWidget *gpswidget, *viewport;
+ GtkWidget *status, *state, *progress, *slider;
+ ChamplainLayer *layer;
+ ClutterActor *view;
+ const gchar *slider_list[] = {GTK_STOCK_ZOOM_IN, GTK_STOCK_ZOOM_OUT, NULL};
+ const gchar **slider_icons = slider_list;
+
+ pgd = g_new0(PaneGPSData, 1);
+
+ pgd->pane.pane_set_fd = bar_pane_gps_set_fd;
+ pgd->pane.pane_notify_selection = bar_pane_gps_notify_selection;
+ pgd->pane.pane_event = bar_pane_gps_event;
+ pgd->pane.pane_write_config = bar_pane_gps_write_config;
+ pgd->pane.title = bar_pane_expander_title(title);
+ pgd->pane.id = g_strdup(id);
+ pgd->pane.type = PANE_GPS;
+ pgd->pane.expanded = expanded;
+ pgd->height = height;
+
+ scrolled = gtk_scrolled_window_new(NULL, NULL);
+ vbox = gtk_vbox_new(FALSE, 0);
+ view = champlain_view_new();
+ gpswidget = champlain_view_embed_new(CHAMPLAIN_VIEW(view));
+ viewport = gtk_viewport_new(NULL, NULL);
+
+ gtk_container_add(GTK_CONTAINER(viewport), gpswidget);
+ gtk_box_pack_start(GTK_BOX(vbox),viewport, TRUE, TRUE, 0);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), vbox);
+
+ status = gtk_hbox_new(FALSE,0);
+ slider = gtk_scale_button_new(GTK_ICON_SIZE_SMALL_TOOLBAR, 1, 17, 1, slider_icons);
+ gtk_widget_set_tooltip_text(slider, "Zoom");
+ gtk_scale_button_set_value(GTK_SCALE_BUTTON(slider), (gdouble)zoom);
+
+ progress = gtk_progress_bar_new();
+ state = gtk_label_new("");
+ gtk_label_set_justify(GTK_LABEL(state), GTK_JUSTIFY_CENTER);
+
+ gtk_box_pack_start(GTK_BOX(status), GTK_WIDGET(slider), FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(status), GTK_WIDGET(state), FALSE, FALSE, 5);
+ gtk_box_pack_end(GTK_BOX(status), GTK_WIDGET(progress), FALSE, FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox),GTK_WIDGET(status), FALSE, FALSE, 0);
+
+ layer = champlain_layer_new();
+ champlain_view_add_layer(CHAMPLAIN_VIEW(view), layer);
+
+ pgd->icon_layer = layer;
+ pgd->gps_view = view;
+ pgd->widget = scrolled;
+ pgd->progress = progress;
+ pgd->slider = slider;
+ pgd->state = state;
+
+ bar_pane_gps_set_map_source(pgd, map_id);
+
+ g_object_set(G_OBJECT(CHAMPLAIN_VIEW(view)), "scroll-mode", CHAMPLAIN_SCROLL_MODE_KINETIC,
+ "zoom-level", zoom,
+ "keep-center-on-resize", TRUE,
+ "decel-rate", 1.0,
+ "show-license", TRUE,
+ "zoom-on-double-click", FALSE,
+ "max-zoom-level", 17,
+ "min-zoom-level", 1,
+ NULL);
+ champlain_view_center_on(CHAMPLAIN_VIEW(view), latitude, longitude);
+ pgd->centre_map_checked = TRUE;
+ g_object_set_data(G_OBJECT(pgd->widget), "pane_data", pgd);
+ g_signal_connect(G_OBJECT(pgd->widget), "destroy", G_CALLBACK(bar_pane_gps_destroy), pgd);
+
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+
+ gtk_widget_set_size_request(pgd->widget, -1, height);
+
+ clutter_set_motion_events_enabled(TRUE);
+ g_signal_connect(G_OBJECT(vbox), "button_press_event", G_CALLBACK(bar_pane_gps_map_keypress_cb), pgd);
+ g_signal_connect(pgd->gps_view, "notify::state", G_CALLBACK(bar_pane_gps_view_state_changed_cb), pgd);
+ g_signal_connect(pgd->gps_view, "notify::zoom-level", G_CALLBACK(bar_pane_gps_view_state_changed_cb), pgd);
+ g_signal_connect(G_OBJECT(slider), "value-changed", G_CALLBACK(bar_pane_gps_slider_changed_cb), pgd);
+
+ file_data_register_notify_func(bar_pane_gps_notify_cb, pgd, NOTIFY_PRIORITY_LOW);
+
+ pgd->create_markers_id = 0;
+ pgd->enable_markers_checked = TRUE;
+ pgd->centre_map_checked = TRUE;
+
+ return pgd->widget;
+}
+
+GtkWidget *bar_pane_gps_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
+{
+ gchar *title = g_strdup(_("GPS Map"));
+ gchar *map_id = NULL;
+ gboolean expanded = TRUE;
+ gint height = 350;
+ gint zoom = 7;
+ gdouble latitude;
+ gdouble longitude;
+ /* Latitude and longitude are stored in the config file as an integer of
+ * (actual value * 1,000,000). There is no READ_DOUBLE utilty function.
+ */
+ gint int_latitude = 54000000;
+ gint int_longitude = -4000000;
+ gchar *id = g_strdup("gps");
+ 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("map-id", map_id))
+ continue;
+ /* There is a bug in the libchamplain libraries which prevents correct
+ * initialisation if the zoom level starts higher than 8
+ */
+ if (READ_INT_CLAMP_FULL("zoom-level", zoom, 1, 8))
+ continue;
+ if (READ_INT_CLAMP_FULL("latitude", int_latitude, -90000000, +90000000))
+ continue;
+ if (READ_INT_CLAMP_FULL("longitude", int_longitude, -90000000, +90000000))
+ 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_COMMENT, id, &title);
+ latitude = int_latitude / 1000000;
+ longitude = int_longitude / 1000000;
+ ret = bar_pane_gps_new(id, title, map_id, zoom, latitude, longitude, expanded, height);
+ g_free(title);
+ g_free(map_id);
+ g_free(id);
+ return ret;
+}
+
+void bar_pane_gps_update_from_config(GtkWidget *pane, const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ PaneGPSData *pgd;
+ gint zoom;
+ gint int_longitude, int_latitude;
+ gdouble longitude, latitude;
+
+ pgd = g_object_get_data(G_OBJECT(pane), "pane_data");
+ if (!pgd)
+ 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("map-id", pgd->map_source))
+ continue;
+ if (READ_BOOL_FULL("expanded", pgd->pane.expanded))
+ continue;
+ if (READ_INT_FULL("height", pgd->height))
+ continue;
+ if (READ_CHAR_FULL("id", pgd->pane.id))
+ continue;
+ if (READ_INT_CLAMP_FULL("zoom-level", zoom, 1, 8))
+ {
+ g_object_set(G_OBJECT(CHAMPLAIN_VIEW(pgd->gps_view)), "zoom-level", zoom, NULL);
+ continue;
+ }
+ if (READ_INT_CLAMP_FULL("longitude", int_longitude, -90000000, +90000000))
+ {
+ longitude = int_longitude / 1000000;
+ g_object_set(G_OBJECT(CHAMPLAIN_VIEW(pgd->gps_view)), "longitude", longitude, NULL);
+ continue;
+ }
+ if (READ_INT_CLAMP_FULL("latitude", int_latitude, -90000000, +90000000))
+ {
+ latitude = int_latitude / 1000000;
+ g_object_set(G_OBJECT(CHAMPLAIN_VIEW(pgd->gps_view)), "latitude", latitude, NULL);
+ continue;
+ }
+ log_printf("unknown attribute %s = %s\n", option, value);
+ }
+
+ if (title)
+ {
+ bar_pane_translate_title(PANE_COMMENT, pgd->pane.id, &title);
+ gtk_label_set_text(GTK_LABEL(pgd->pane.title), title);
+ g_free(title);
+ }
+
+ gtk_widget_set_size_request(pgd->widget, -1, pgd->height);
+ bar_update_expander(pane);
+}
+
+#endif
+#endif
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff -r 1b29d2445991 -r c6d522fe3e5e src/bar_gps.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bar_gps.h Tue May 12 18:25:18 2009 +0000
@@ -0,0 +1,25 @@
+/*
+ * Geeqie
+ * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2009 The Geeqie Team
+ *
+ * Author: Vladimir Nadvornik
+ *
+ * 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_GPS_H
+#define BAR_GPS_H
+
+GtkWidget *bar_pane_gps_new(const gchar *id, const gchar *title, const gchar *map_source, const gint zoom,
+ const gdouble latitude, const gdouble longitude, gboolean expanded, gint height);
+GtkWidget *bar_pane_gps_new_from_config(const gchar **attribute_names, const gchar **attribute_values);
+void bar_pane_gps_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values);
+
+
+#endif
+
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff -r 1b29d2445991 -r c6d522fe3e5e src/main.c
--- a/src/main.c Tue May 12 06:54:05 2009 +0000
+++ b/src/main.c Tue May 12 18:25:18 2009 +0000
@@ -37,6 +37,11 @@
#include "pixbuf_util.h"
#include /* for keyboard values */
+#ifdef HAVE_LIBCHAMPLAIN
+#ifdef HAVE_LIBCHAMPLAIN_GTK
+#include
+#endif
+#endif
#include
#include
@@ -748,7 +753,16 @@
file_data_register_notify_func(collect_manager_notify_cb, NULL, NOTIFY_PRIORITY_LOW);
gtkrc_load();
+
+#ifdef HAVE_LIBCHAMPLAIN
+#ifdef HAVE_LIBCHAMPLAIN_GTK
+ gtk_clutter_init(&argc, &argv);
+#else
gtk_init(&argc, &argv);
+#endif
+#else
+ gtk_init(&argc, &argv);
+#endif
if (gtk_major_version < GTK_MAJOR_VERSION ||
(gtk_major_version == GTK_MAJOR_VERSION && gtk_minor_version < GTK_MINOR_VERSION) )
diff -r 1b29d2445991 -r c6d522fe3e5e src/rcfile.c
--- a/src/rcfile.c Tue May 12 06:54:05 2009 +0000
+++ b/src/rcfile.c Tue May 12 18:25:18 2009 +0000
@@ -33,6 +33,7 @@
#include "layout_util.h"
#include "bar.h"
#include "metadata.h"
+#include "bar_gps.h"
/*
@@ -910,6 +911,24 @@
}
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)
+ {
+ GtkWidget *pane = bar_find_pane_by_id(bar, PANE_GPS, options_get_id(attribute_names, attribute_values));
+ if (pane)
+ {
+ bar_pane_gps_update_from_config(pane, attribute_names, attribute_values);
+ }
+ else
+ {
+ pane = bar_pane_gps_new_from_config(attribute_names, attribute_values);
+ bar_add(bar, pane);
+ }
+ options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
+ }
+#endif
+#endif
else if (g_ascii_strcasecmp(element_name, "pane_exif") == 0)
{
GtkWidget *pane = bar_find_pane_by_id(bar, PANE_EXIF, options_get_id(attribute_names, attribute_values));