/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Pix
*
* Copyright (C) 2011 Free Software Foundation, Inc.
*
* 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, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include "gth-map-view.h"
#define MAP_HEIGHT 300
static void gth_map_view_gth_property_view_interface_init (GthPropertyViewInterface *iface);
struct _GthMapViewPrivate {
GtkWidget *embed;
ChamplainView *map_view;
ChamplainMarkerLayer *marker_layer;
ClutterActor *marker;
};
G_DEFINE_TYPE_WITH_CODE (GthMapView,
gth_map_view,
GTK_TYPE_BOX,
G_ADD_PRIVATE (GthMapView)
G_IMPLEMENT_INTERFACE (GTH_TYPE_PROPERTY_VIEW,
gth_map_view_gth_property_view_interface_init))
/* Exif format: %d/%d %d/%d %d/%d */
static double
exif_coordinate_to_decimal (const char *raw)
{
double value;
double factor;
char **raw_values;
int i;
value = 0.0;
factor = 1.0;
raw_values = g_strsplit (raw, " ", 3);
for (i = 0; i < 3; i++) {
int numerator;
int denominator;
if (raw_values[i] == NULL)
break; /* Error */
sscanf (raw_values[i], "%d/%d", &numerator, &denominator);
if ((numerator != 0) && (denominator != 0))
value += ((double) numerator / denominator) / factor;
factor *= 60.0;
}
g_strfreev (raw_values);
return value;
}
static char *
decimal_to_string (double value)
{
GString *s;
double part;
s = g_string_new ("");
if (value < 0.0)
value = - value;
/* degree */
part = floor (value);
g_string_append_printf (s, "%.0f°", part);
value = (value - part) * 60.0;
/* minutes */
part = floor (value);
g_string_append_printf (s, " %.0fʹ", part);
value = (value - part) * 60.0;
/* seconds */
g_string_append_printf (s, " %02.3fʺ", value);
return g_string_free (s, FALSE);
}
static char *
decimal_coordinates_to_string (double latitude,
double longitude)
{
char *latitude_s;
char *longitude_s;
char *s;
latitude_s = decimal_to_string (latitude);
longitude_s = decimal_to_string (longitude);
s = g_strdup_printf ("%s %s\n%s %s",
latitude_s,
((latitude < 0.0) ? C_("Cardinal point", "S") : C_("Cardinal point", "N")),
longitude_s,
((longitude < 0.0) ? C_("Cardinal point", "W") : C_("Cardinal point", "E")));
g_free (longitude_s);
g_free (latitude_s);
return s;
}
static int
gth_map_view_get_coordinates (GthMapView *self,
GthFileData *file_data,
double *out_latitude,
double *out_longitude)
{
int coordinates_available;
double latitude = 0.0;
double longitude = 0.0;
coordinates_available = 0;
if (file_data != NULL) {
GthMetadata *metadata;
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLatitude");
if (metadata != NULL) {
latitude = exif_coordinate_to_decimal (gth_metadata_get_raw (metadata));
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLatitudeRef");
if (metadata != NULL) {
if (g_strcmp0 (gth_metadata_get_raw (metadata), "S") == 0)
latitude = - latitude;
}
coordinates_available++;
}
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLongitude");
if (metadata != NULL) {
longitude = exif_coordinate_to_decimal (gth_metadata_get_raw (metadata));
metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLongitudeRef");
if (metadata != NULL) {
if (g_strcmp0 (gth_metadata_get_raw (metadata), "W") == 0)
longitude = - longitude;
}
coordinates_available++;
}
}
if (out_latitude != NULL)
*out_latitude = latitude;
if (out_longitude != NULL)
*out_longitude = longitude;
return coordinates_available;
}
static gboolean
gth_map_view_real_can_view (GthPropertyView *base,
GthFileData *file_data)
{
GthMapView *self = GTH_MAP_VIEW (base);
return gth_map_view_get_coordinates (self, file_data, NULL, NULL) == 2;
}
static void
gth_map_view_real_set_file (GthPropertyView *base,
GthFileData *file_data)
{
GthMapView *self = GTH_MAP_VIEW (base);
int coordinates_available;
double latitude;
double longitude;
coordinates_available = gth_map_view_get_coordinates (self, file_data, &latitude, &longitude);
if (coordinates_available == 2) {
char *position;
position = decimal_coordinates_to_string (latitude, longitude);
champlain_label_set_text (CHAMPLAIN_LABEL (self->priv->marker), position);
g_free (position);
champlain_location_set_location (CHAMPLAIN_LOCATION (self->priv->marker), latitude, longitude);
champlain_view_center_on (CHAMPLAIN_VIEW (self->priv->map_view), latitude, longitude);
}
}
static const char *
gth_map_view_real_get_name (GthPropertyView *self)
{
return _("Map");
}
static const char *
gth_map_view_real_get_icon (GthPropertyView *self)
{
return "map-symbolic";
}
static void
gth_map_view_finalize (GObject *base)
{
G_OBJECT_CLASS (gth_map_view_parent_class)->finalize (base);
}
static void
gth_map_view_class_init (GthMapViewClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = gth_map_view_finalize;
}
static void
gth_map_view_init (GthMapView *self)
{
ClutterActor *scale;
self->priv = gth_map_view_get_instance_private (self);
gtk_box_set_spacing (GTK_BOX (self), 6);
gtk_container_set_border_width (GTK_CONTAINER (self), 2);
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
/* The map widget */
self->priv->embed = gtk_champlain_embed_new ();
gtk_widget_set_size_request (self->priv->embed, -1, MAP_HEIGHT);
self->priv->map_view = gtk_champlain_embed_get_view (GTK_CHAMPLAIN_EMBED (self->priv->embed));
g_object_set (G_OBJECT (self->priv->map_view),
"reactive", TRUE,
"zoom-level", 5,
"zoom-on-double-click", TRUE,
"kinetic-mode", TRUE,
NULL);
scale = champlain_scale_new ();
g_object_set (scale,
"x-align", CLUTTER_ACTOR_ALIGN_START,
"y-align", CLUTTER_ACTOR_ALIGN_END,
NULL);
champlain_scale_connect_view (CHAMPLAIN_SCALE (scale), self->priv->map_view);
clutter_actor_add_child (CLUTTER_ACTOR (self->priv->map_view), scale);
self->priv->marker_layer = champlain_marker_layer_new ();
champlain_view_add_layer (self->priv->map_view, CHAMPLAIN_LAYER (self->priv->marker_layer));
clutter_actor_show (CLUTTER_ACTOR (self->priv->marker_layer));
self->priv->marker = champlain_label_new_with_text ("", "Sans 10", NULL, NULL);
clutter_actor_show (self->priv->marker);
champlain_marker_layer_add_marker (self->priv->marker_layer, CHAMPLAIN_MARKER (self->priv->marker));
gtk_widget_show_all (self->priv->embed);
gtk_box_pack_start (GTK_BOX (self), self->priv->embed, TRUE, TRUE, 0);
}
static void
gth_map_view_gth_property_view_interface_init (GthPropertyViewInterface *iface)
{
iface->get_name = gth_map_view_real_get_name;
iface->get_icon = gth_map_view_real_get_icon;
iface->can_view = gth_map_view_real_can_view;
iface->set_file = gth_map_view_real_set_file;
}