aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc/e-map.c
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/misc/e-map.c')
-rw-r--r--widgets/misc/e-map.c1430
1 files changed, 0 insertions, 1430 deletions
diff --git a/widgets/misc/e-map.c b/widgets/misc/e-map.c
deleted file mode 100644
index b9f83d811d..0000000000
--- a/widgets/misc/e-map.c
+++ /dev/null
@@ -1,1430 +0,0 @@
-/*
- * Map widget.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) version 3.
- *
- * 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
- *
- *
- * Authors:
- * Hans Petter Jansson <hpj@ximian.com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <math.h>
-#include <stdlib.h>
-#include <gdk/gdkkeysyms.h>
-#include <glib/gi18n.h>
-
-#include "e-util/e-util-private.h"
-#include "e-util/e-util.h"
-
-#include "e-map.h"
-
-#define E_MAP_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_MAP, EMapPrivate))
-
-#define E_MAP_TWEEN_TIMEOUT_MSECS 25
-#define E_MAP_TWEEN_DURATION_MSECS 150
-
-/* Scroll step increment */
-
-#define SCROLL_STEP_SIZE 32
-
-/* */
-
-#define E_MAP_GET_WIDTH(map) gtk_adjustment_get_upper((map)->priv->hadjustment)
-#define E_MAP_GET_HEIGHT(map) gtk_adjustment_get_upper((map)->priv->vadjustment)
-
-/* Zoom state - keeps track of animation hacks */
-
-typedef enum
-{
- E_MAP_ZOOMED_IN,
- E_MAP_ZOOMED_OUT,
- E_MAP_ZOOMING_IN,
- E_MAP_ZOOMING_OUT
-}
-EMapZoomState;
-
-/* The Tween struct used for zooming */
-
-typedef struct _EMapTween EMapTween;
-
-struct _EMapTween {
- guint start_time;
- guint end_time;
- gdouble longitude_offset;
- gdouble latitude_offset;
- gdouble zoom_factor;
-};
-
-/* Private part of the EMap structure */
-
-struct _EMapPrivate {
- /* Pointer to map image */
- GdkPixbuf *map_pixbuf;
- cairo_surface_t *map_render_surface;
-
- /* Settings */
- gboolean frozen, smooth_zoom;
-
- /* Adjustments for scrolling */
- GtkAdjustment *hadjustment;
- GtkAdjustment *vadjustment;
-
- /* GtkScrollablePolicy needs to be checked when
- * driving the scrollable adjustment values */
- guint hscroll_policy : 1;
- guint vscroll_policy : 1;
-
- /* Current scrolling offsets */
- gint xofs, yofs;
-
- /* Realtime zoom data */
- EMapZoomState zoom_state;
- gdouble zoom_target_long, zoom_target_lat;
-
- /* Dots */
- GPtrArray *points;
-
- /* Tweens */
- GSList *tweens;
- GTimer *timer;
- guint timer_current_ms;
- guint tween_id;
-};
-
-/* Properties */
-
-enum {
- PROP_0,
-
- /* For scrollable interface */
- PROP_HADJUSTMENT,
- PROP_VADJUSTMENT,
- PROP_HSCROLL_POLICY,
- PROP_VSCROLL_POLICY
-};
-
-/* Internal prototypes */
-
-static void update_render_surface (EMap *map, gboolean render_overlays);
-static void set_scroll_area (EMap *map, gint width, gint height);
-static void center_at (EMap *map, gdouble longitude, gdouble latitude);
-static void scroll_to (EMap *map, gint x, gint y);
-static gint load_map_background (EMap *map, gchar *name);
-static void update_and_paint (EMap *map);
-static void update_render_point (EMap *map, EMapPoint *point);
-static void repaint_point (EMap *map, EMapPoint *point);
-
-/* ------ *
- * Tweens *
- * ------ */
-
-static gboolean
-e_map_is_tweening (EMap *map)
-{
- return map->priv->timer != NULL;
-}
-
-static void
-e_map_stop_tweening (EMap *map)
-{
- g_assert (map->priv->tweens == NULL);
-
- if (!e_map_is_tweening (map))
- return;
-
- g_timer_destroy (map->priv->timer);
- map->priv->timer = NULL;
- g_source_remove (map->priv->tween_id);
- map->priv->tween_id = 0;
-}
-
-static void
-e_map_tween_destroy (EMap *map,
- EMapTween *tween)
-{
- map->priv->tweens = g_slist_remove (map->priv->tweens, tween);
- g_slice_free (EMapTween, tween);
-
- if (map->priv->tweens == NULL)
- e_map_stop_tweening (map);
-}
-
-static gboolean
-e_map_do_tween_cb (gpointer data)
-{
- EMap *map = data;
- GSList *walk;
-
- map->priv->timer_current_ms =
- g_timer_elapsed (map->priv->timer, NULL) * 1000;
- gtk_widget_queue_draw (GTK_WIDGET (map));
-
- /* Can't use for loop here, because we need to advance
- * the list before deleting.
- */
- walk = map->priv->tweens;
- while (walk)
- {
- EMapTween *tween = walk->data;
-
- walk = walk->next;
-
- if (tween->end_time <= map->priv->timer_current_ms)
- e_map_tween_destroy (map, tween);
- }
-
- return TRUE;
-}
-
-static void
-e_map_start_tweening (EMap *map)
-{
- if (e_map_is_tweening (map))
- return;
-
- map->priv->timer = g_timer_new ();
- map->priv->timer_current_ms = 0;
- map->priv->tween_id = g_timeout_add (
- E_MAP_TWEEN_TIMEOUT_MSECS, e_map_do_tween_cb, map);
- g_timer_start (map->priv->timer);
-}
-
-static void
-e_map_tween_new (EMap *map,
- guint msecs,
- gdouble longitude_offset,
- gdouble latitude_offset,
- gdouble zoom_factor)
-{
- EMapTween *tween;
-
- if (!map->priv->smooth_zoom)
- return;
-
- e_map_start_tweening (map);
-
- tween = g_slice_new (EMapTween);
-
- tween->start_time = map->priv->timer_current_ms;
- tween->end_time = tween->start_time + msecs;
- tween->longitude_offset = longitude_offset;
- tween->latitude_offset = latitude_offset;
- tween->zoom_factor = zoom_factor;
-
- map->priv->tweens = g_slist_prepend (map->priv->tweens, tween);
-
- gtk_widget_queue_draw (GTK_WIDGET (map));
-}
-
-G_DEFINE_TYPE_WITH_CODE (
- EMap,
- e_map,
- GTK_TYPE_WIDGET,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
-
-static void
-e_map_get_current_location (EMap *map,
- gdouble *longitude,
- gdouble *latitude)
-{
- GtkAllocation allocation;
-
- gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
-
- e_map_window_to_world (
- map, allocation.width / 2.0,
- allocation.height / 2.0,
- longitude, latitude);
-}
-
-static void
-e_map_world_to_render_surface (EMap *map,
- gdouble world_longitude,
- gdouble world_latitude,
- gdouble *win_x,
- gdouble *win_y)
-{
- gint width, height;
-
- width = E_MAP_GET_WIDTH (map);
- height = E_MAP_GET_HEIGHT (map);
-
- *win_x = (width / 2.0 + (width / 2.0) * world_longitude / 180.0);
- *win_y = (height / 2.0 - (height / 2.0) * world_latitude / 90.0);
-}
-
-static void
-e_map_tween_new_from (EMap *map,
- guint msecs,
- gdouble longitude,
- gdouble latitude,
- gdouble zoom)
-{
- gdouble current_longitude, current_latitude;
-
- e_map_get_current_location (
- map, &current_longitude, &current_latitude);
-
- e_map_tween_new (
- map, msecs,
- longitude - current_longitude,
- latitude - current_latitude,
- zoom / e_map_get_magnification (map));
-}
-
-static gdouble
-e_map_get_tween_effect (EMap *map,
- EMapTween *tween)
-{
- gdouble elapsed;
-
- elapsed = (gdouble)
- (map->priv->timer_current_ms - tween->start_time) /
- tween->end_time;
-
- return MAX (0.0, 1.0 - elapsed);
-}
-
-static void
-e_map_apply_tween (EMapTween *tween,
- gdouble effect,
- gdouble *longitude,
- gdouble *latitude,
- gdouble *zoom)
-{
- *zoom *= pow (tween->zoom_factor, effect);
- *longitude += tween->longitude_offset * effect;
- *latitude += tween->latitude_offset * effect;
-}
-
-static void
-e_map_tweens_compute_matrix (EMap *map,
- cairo_matrix_t *matrix)
-{
- GSList *walk;
- gdouble zoom, x, y, latitude, longitude, effect;
- GtkAllocation allocation;
-
- if (!e_map_is_tweening (map)) {
- cairo_matrix_init_translate (
- matrix, -map->priv->xofs, -map->priv->yofs);
- return;
- }
-
- e_map_get_current_location (map, &longitude, &latitude);
- zoom = 1.0;
-
- for (walk = map->priv->tweens; walk; walk = walk->next) {
- EMapTween *tween = walk->data;
-
- effect = e_map_get_tween_effect (map, tween);
- e_map_apply_tween (tween, effect, &longitude, &latitude, &zoom);
- }
-
- gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
- cairo_matrix_init_translate (
- matrix,
- allocation.width / 2.0,
- allocation.height / 2.0);
-
- e_map_world_to_render_surface (map, longitude, latitude, &x, &y);
- cairo_matrix_scale (matrix, zoom, zoom);
- cairo_matrix_translate (matrix, -x, -y);
-}
-
-/* GtkScrollable implementation */
-
-static void
-e_map_adjustment_changed (GtkAdjustment *adjustment,
- EMap *map)
-{
- EMapPrivate *priv = map->priv;
-
- if (gtk_widget_get_realized (GTK_WIDGET (map))) {
- gint hadj_value;
- gint vadj_value;
-
- hadj_value = gtk_adjustment_get_value (priv->hadjustment);
- vadj_value = gtk_adjustment_get_value (priv->vadjustment);
-
- scroll_to (map, hadj_value, vadj_value);
- }
-}
-
-static void
-e_map_set_hadjustment_values (EMap *map)
-{
- GtkAllocation allocation;
- EMapPrivate *priv = map->priv;
- GtkAdjustment *adj = priv->hadjustment;
- gdouble old_value;
- gdouble new_value;
- gdouble new_upper;
-
- gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
-
- old_value = gtk_adjustment_get_value (adj);
- new_upper = MAX (allocation.width, gdk_pixbuf_get_width (priv->map_pixbuf));
-
- g_object_set (
- adj,
- "lower", 0.0,
- "upper", new_upper,
- "page-size", (gdouble) allocation.height,
- "step-increment", allocation.height * 0.1,
- "page-increment", allocation.height * 0.9,
- NULL);
-
- new_value = CLAMP (old_value, 0, new_upper - allocation.width);
- if (new_value != old_value)
- gtk_adjustment_set_value (adj, new_value);
-}
-
-static void
-e_map_set_vadjustment_values (EMap *map)
-{
- GtkAllocation allocation;
- EMapPrivate *priv = map->priv;
- GtkAdjustment *adj = priv->vadjustment;
- gdouble old_value;
- gdouble new_value;
- gdouble new_upper;
-
- gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
-
- old_value = gtk_adjustment_get_value (adj);
- new_upper = MAX (allocation.height, gdk_pixbuf_get_height (priv->map_pixbuf));
-
- g_object_set (
- adj,
- "lower", 0.0,
- "upper", new_upper,
- "page-size", (gdouble) allocation.height,
- "step-increment", allocation.height * 0.1,
- "page-increment", allocation.height * 0.9,
- NULL);
-
- new_value = CLAMP (old_value, 0, new_upper - allocation.height);
- if (new_value != old_value)
- gtk_adjustment_set_value (adj, new_value);
-}
-
-static void
-e_map_set_hadjustment (EMap *map,
- GtkAdjustment *adjustment)
-{
- EMapPrivate *priv = map->priv;
-
- if (adjustment && priv->hadjustment == adjustment)
- return;
-
- if (priv->hadjustment != NULL) {
- g_signal_handlers_disconnect_matched (
- priv->hadjustment, G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, map);
- g_object_unref (priv->hadjustment);
- }
-
- if (!adjustment)
- adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- g_signal_connect (
- adjustment, "value-changed",
- G_CALLBACK (e_map_adjustment_changed), map);
- priv->hadjustment = g_object_ref_sink (adjustment);
- e_map_set_hadjustment_values (map);
-
- g_object_notify (G_OBJECT (map), "hadjustment");
-}
-
-static void
-e_map_set_vadjustment (EMap *map,
- GtkAdjustment *adjustment)
-{
- EMapPrivate *priv = map->priv;
-
- if (adjustment && priv->vadjustment == adjustment)
- return;
-
- if (priv->vadjustment != NULL) {
- g_signal_handlers_disconnect_matched (
- priv->vadjustment, G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, map);
- g_object_unref (priv->vadjustment);
- }
-
- if (!adjustment)
- adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- g_signal_connect (
- adjustment, "value-changed",
- G_CALLBACK (e_map_adjustment_changed), map);
- priv->vadjustment = g_object_ref_sink (adjustment);
- e_map_set_vadjustment_values (map);
-
- g_object_notify (G_OBJECT (map), "vadjustment");
-}
-
-/* ----------------- *
- * Widget management *
- * ----------------- */
-
-static void
-e_map_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- EMap *map;
-
- map = E_MAP (object);
-
- switch (property_id) {
- case PROP_HADJUSTMENT:
- e_map_set_hadjustment (map, g_value_get_object (value));
- break;
- case PROP_VADJUSTMENT:
- e_map_set_vadjustment (map, g_value_get_object (value));
- break;
- case PROP_HSCROLL_POLICY:
- map->priv->hscroll_policy = g_value_get_enum (value);
- gtk_widget_queue_resize (GTK_WIDGET (map));
- break;
- case PROP_VSCROLL_POLICY:
- map->priv->vscroll_policy = g_value_get_enum (value);
- gtk_widget_queue_resize (GTK_WIDGET (map));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static void
-e_map_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- EMap *map;
-
- map = E_MAP (object);
-
- switch (property_id) {
- case PROP_HADJUSTMENT:
- g_value_set_object (value, map->priv->hadjustment);
- break;
- case PROP_VADJUSTMENT:
- g_value_set_object (value, map->priv->vadjustment);
- break;
- case PROP_HSCROLL_POLICY:
- g_value_set_enum (value, map->priv->hscroll_policy);
- break;
- case PROP_VSCROLL_POLICY:
- g_value_set_enum (value, map->priv->vscroll_policy);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static void
-e_map_finalize (GObject *object)
-{
- EMap *map;
-
- map = E_MAP (object);
-
- while (map->priv->tweens)
- e_map_tween_destroy (map, map->priv->tweens->data);
- e_map_stop_tweening (map);
-
- if (map->priv->map_pixbuf) {
- g_object_unref (map->priv->map_pixbuf);
- map->priv->map_pixbuf = NULL;
- }
-
- /* gone in unrealize */
- g_assert (map->priv->map_render_surface == NULL);
-
- G_OBJECT_CLASS (e_map_parent_class)->finalize (object);
-}
-
-static void
-e_map_realize (GtkWidget *widget)
-{
- GtkAllocation allocation;
- GdkWindowAttr attr;
- GdkWindow *window;
- gint attr_mask;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_MAP (widget));
-
- gtk_widget_set_realized (widget, TRUE);
-
- gtk_widget_get_allocation (widget, &allocation);
-
- attr.window_type = GDK_WINDOW_CHILD;
- attr.x = allocation.x;
- attr.y = allocation.y;
- attr.width = allocation.width;
- attr.height = allocation.height;
- attr.wclass = GDK_INPUT_OUTPUT;
- attr.visual = gtk_widget_get_visual (widget);
- attr.event_mask = gtk_widget_get_events (widget) |
- GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK |
- GDK_POINTER_MOTION_MASK;
-
- attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
-
- window = gdk_window_new (
- gtk_widget_get_parent_window (widget), &attr, attr_mask);
- gtk_widget_set_window (widget, window);
- gdk_window_set_user_data (window, widget);
-
- update_render_surface (E_MAP (widget), TRUE);
-}
-
-static void
-e_map_unrealize (GtkWidget *widget)
-{
- EMap *map = E_MAP (widget);
-
- cairo_surface_destroy (map->priv->map_render_surface);
- map->priv->map_render_surface = NULL;
-
- if (GTK_WIDGET_CLASS (e_map_parent_class)->unrealize)
- (*GTK_WIDGET_CLASS (e_map_parent_class)->unrealize) (widget);
-}
-
-static void
-e_map_get_preferred_width (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- EMap *map;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_MAP (widget));
-
- map = E_MAP (widget);
-
- /* TODO: Put real sizes here. */
-
- *minimum = *natural = gdk_pixbuf_get_width (map->priv->map_pixbuf);
-}
-
-static void
-e_map_get_preferred_height (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- EMap *view;
- EMapPrivate *priv;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_MAP (widget));
-
- view = E_MAP (widget);
- priv = view->priv;
-
- /* TODO: Put real sizes here. */
-
- *minimum = *natural = gdk_pixbuf_get_height (priv->map_pixbuf);
-}
-
-static void
-e_map_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
-{
- EMap *map;
-
- g_return_if_fail (widget != NULL);
- g_return_if_fail (E_IS_MAP (widget));
- g_return_if_fail (allocation != NULL);
-
- map = E_MAP (widget);
-
- /* Resize the window */
-
- gtk_widget_set_allocation (widget, allocation);
-
- if (gtk_widget_get_realized (widget)) {
- GdkWindow *window;
-
- window = gtk_widget_get_window (widget);
-
- gdk_window_move_resize (
- window, allocation->x, allocation->y,
- allocation->width, allocation->height);
-
- gtk_widget_queue_draw (widget);
- }
-
- update_render_surface (map, TRUE);
-}
-
-static gboolean
-e_map_draw (GtkWidget *widget,
- cairo_t *cr)
-{
- EMap *map;
- cairo_matrix_t matrix;
-
- if (!gtk_widget_is_drawable (widget))
- return FALSE;
-
- map = E_MAP (widget);
-
- cairo_save (cr);
-
- e_map_tweens_compute_matrix (map, &matrix);
- cairo_transform (cr, &matrix);
-
- cairo_set_source_surface (cr, map->priv->map_render_surface, 0, 0);
- cairo_paint (cr);
-
- cairo_restore (cr);
-
- return FALSE;
-}
-
-static gint
-e_map_button_press (GtkWidget *widget,
- GdkEventButton *event)
-{
- if (!gtk_widget_has_focus (widget))
- gtk_widget_grab_focus (widget);
-
- return TRUE;
-}
-
-static gint
-e_map_button_release (GtkWidget *widget,
- GdkEventButton *event)
-{
- if (event->button != 1)
- return FALSE;
-
- gdk_device_ungrab (event->device, event->time);
- return TRUE;
-}
-
-static gint
-e_map_motion (GtkWidget *widget,
- GdkEventMotion *event)
-{
- return FALSE;
-}
-
-static gint
-e_map_key_press (GtkWidget *widget,
- GdkEventKey *event)
-{
- EMap *map;
- gboolean do_scroll;
- gint xofs, yofs;
-
- map = E_MAP (widget);
-
- switch (event->keyval)
- {
- case GDK_KEY_Up:
- do_scroll = TRUE;
- xofs = 0;
- yofs = -SCROLL_STEP_SIZE;
- break;
-
- case GDK_KEY_Down:
- do_scroll = TRUE;
- xofs = 0;
- yofs = SCROLL_STEP_SIZE;
- break;
-
- case GDK_KEY_Left:
- do_scroll = TRUE;
- xofs = -SCROLL_STEP_SIZE;
- yofs = 0;
- break;
-
- case GDK_KEY_Right:
- do_scroll = TRUE;
- xofs = SCROLL_STEP_SIZE;
- yofs = 0;
- break;
-
- default:
- return FALSE;
- }
-
- if (do_scroll) {
- gint page_size;
- gint upper;
- gint x, y;
-
- page_size = gtk_adjustment_get_page_size (map->priv->hadjustment);
- upper = gtk_adjustment_get_upper (map->priv->hadjustment);
- x = CLAMP (map->priv->xofs + xofs, 0, upper - page_size);
-
- page_size = gtk_adjustment_get_page_size (map->priv->vadjustment);
- upper = gtk_adjustment_get_upper (map->priv->vadjustment);
- y = CLAMP (map->priv->yofs + yofs, 0, upper - page_size);
-
- scroll_to (map, x, y);
-
- gtk_adjustment_set_value (map->priv->hadjustment, x);
- gtk_adjustment_set_value (map->priv->vadjustment, y);
- }
-
- return TRUE;
-}
-
-static void
-e_map_class_init (EMapClass *class)
-{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
-
- g_type_class_add_private (class, sizeof (EMapPrivate));
-
- object_class = G_OBJECT_CLASS (class);
- object_class->set_property = e_map_set_property;
- object_class->get_property = e_map_get_property;
- object_class->finalize = e_map_finalize;
-
- /* Scrollable interface properties */
- g_object_class_override_property (
- object_class, PROP_HADJUSTMENT, "hadjustment");
- g_object_class_override_property (
- object_class, PROP_VADJUSTMENT, "vadjustment");
- g_object_class_override_property (
- object_class, PROP_HSCROLL_POLICY, "hscroll-policy");
- g_object_class_override_property (
- object_class, PROP_VSCROLL_POLICY, "vscroll-policy");
-
- widget_class = GTK_WIDGET_CLASS (class);
- widget_class->realize = e_map_realize;
- widget_class->unrealize = e_map_unrealize;
- widget_class->get_preferred_height = e_map_get_preferred_height;
- widget_class->get_preferred_width = e_map_get_preferred_width;
- widget_class->size_allocate = e_map_size_allocate;
- widget_class->draw = e_map_draw;
- widget_class->button_press_event = e_map_button_press;
- widget_class->button_release_event = e_map_button_release;
- widget_class->motion_notify_event = e_map_motion;
- widget_class->key_press_event = e_map_key_press;
-}
-
-static void
-e_map_init (EMap *map)
-{
- GtkWidget *widget;
- gchar *map_file_name;
-
- map_file_name = g_build_filename (
- EVOLUTION_IMAGESDIR, "world_map-960.png", NULL);
-
- widget = GTK_WIDGET (map);
-
- map->priv = E_MAP_GET_PRIVATE (map);
-
- load_map_background (map, map_file_name);
- g_free (map_file_name);
- map->priv->frozen = FALSE;
- map->priv->smooth_zoom = TRUE;
- map->priv->zoom_state = E_MAP_ZOOMED_OUT;
- map->priv->points = g_ptr_array_new ();
-
- gtk_widget_set_can_focus (widget, TRUE);
- gtk_widget_set_has_window (widget, TRUE);
-}
-
-/* ---------------- *
- * Widget interface *
- * ---------------- */
-
-/**
- * e_map_new:
- * @void:
- *
- * Creates a new empty map widget.
- *
- * Return value: A newly-created map widget.
- **/
-
-EMap *
-e_map_new (void)
-{
- GtkWidget *widget;
- AtkObject *a11y;
-
- widget = g_object_new (E_TYPE_MAP, NULL);
- a11y = gtk_widget_get_accessible (widget);
- atk_object_set_name (a11y, _("World Map"));
- atk_object_set_role (a11y, ATK_ROLE_IMAGE);
- atk_object_set_description (
- a11y, _("Mouse-based interactive map widget for selecting "
- "timezone. Keyboard users should instead select the timezone "
- "from the drop-down combination box below."));
- return (E_MAP (widget));
-}
-
-/* --- Coordinate translation --- */
-
-/* These functions translate coordinates between longitude/latitude and
- * the image x/y offsets, using the equidistant cylindrical projection.
- *
- * Longitude E <-180, 180]
- * Latitude E <-90, 90] */
-
-void
-e_map_window_to_world (EMap *map,
- gdouble win_x,
- gdouble win_y,
- gdouble *world_longitude,
- gdouble *world_latitude)
-{
- gint width, height;
-
- g_return_if_fail (map);
-
- g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (map)));
-
- width = E_MAP_GET_WIDTH (map);
- height = E_MAP_GET_HEIGHT (map);
-
- *world_longitude = (win_x + map->priv->xofs - (gdouble) width / 2.0) /
- ((gdouble) width / 2.0) * 180.0;
- *world_latitude = ((gdouble) height / 2.0 - win_y - map->priv->yofs) /
- ((gdouble) height / 2.0) * 90.0;
-}
-
-void
-e_map_world_to_window (EMap *map,
- gdouble world_longitude,
- gdouble world_latitude,
- gdouble *win_x,
- gdouble *win_y)
-{
- g_return_if_fail (E_IS_MAP (map));
- g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (map)));
- g_return_if_fail (world_longitude >= -180.0 && world_longitude <= 180.0);
- g_return_if_fail (world_latitude >= -90.0 && world_latitude <= 90.0);
-
- e_map_world_to_render_surface (
- map, world_longitude, world_latitude, win_x, win_y);
-
- *win_x -= map->priv->xofs;
- *win_y -= map->priv->yofs;
-}
-
-/* --- Zoom --- */
-
-gdouble
-e_map_get_magnification (EMap *map)
-{
- if (map->priv->zoom_state == E_MAP_ZOOMED_IN) return 2.0;
- else return 1.0;
-}
-
-static void
-e_map_set_zoom (EMap *map,
- EMapZoomState zoom)
-{
- if (map->priv->zoom_state == zoom)
- return;
-
- map->priv->zoom_state = zoom;
- update_render_surface (map, TRUE);
- gtk_widget_queue_draw (GTK_WIDGET (map));
-}
-
-void
-e_map_zoom_to_location (EMap *map,
- gdouble longitude,
- gdouble latitude)
-{
- gdouble prevlong, prevlat;
- gdouble prevzoom;
-
- g_return_if_fail (map);
- g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (map)));
-
- e_map_get_current_location (map, &prevlong, &prevlat);
- prevzoom = e_map_get_magnification (map);
-
- e_map_set_zoom (map, E_MAP_ZOOMED_IN);
- center_at (map, longitude, latitude);
-
- e_map_tween_new_from (
- map, E_MAP_TWEEN_DURATION_MSECS,
- prevlong, prevlat, prevzoom);
-}
-
-void
-e_map_zoom_out (EMap *map)
-{
- gdouble longitude, latitude;
- gdouble prevzoom;
-
- g_return_if_fail (map);
- g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (map)));
-
- e_map_get_current_location (map, &longitude, &latitude);
- prevzoom = e_map_get_magnification (map);
- e_map_set_zoom (map, E_MAP_ZOOMED_OUT);
- center_at (map, longitude, latitude);
-
- e_map_tween_new_from (
- map, E_MAP_TWEEN_DURATION_MSECS,
- longitude, latitude, prevzoom);
-}
-
-void
-e_map_set_smooth_zoom (EMap *map,
- gboolean state)
-{
- ((EMapPrivate *) map->priv)->smooth_zoom = state;
-}
-
-gboolean
-e_map_get_smooth_zoom (EMap *map)
-{
- return (((EMapPrivate *) map->priv)->smooth_zoom);
-}
-
-void
-e_map_freeze (EMap *map)
-{
- ((EMapPrivate *) map->priv)->frozen = TRUE;
-}
-
-void
-e_map_thaw (EMap *map)
-{
- ((EMapPrivate *) map->priv)->frozen = FALSE;
- update_and_paint (map);
-}
-
-/* --- Point manipulation --- */
-
-EMapPoint *
-e_map_add_point (EMap *map,
- gchar *name,
- gdouble longitude,
- gdouble latitude,
- guint32 color_rgba)
-{
- EMapPoint *point;
-
- point = g_new0 (EMapPoint, 1);
-
- point->name = name; /* Can be NULL */
- point->longitude = longitude;
- point->latitude = latitude;
- point->rgba = color_rgba;
-
- g_ptr_array_add (map->priv->points, (gpointer) point);
-
- if (!map->priv->frozen)
- {
- update_render_point (map, point);
- repaint_point (map, point);
- }
-
- return point;
-}
-
-void
-e_map_remove_point (EMap *map,
- EMapPoint *point)
-{
- g_ptr_array_remove (map->priv->points, point);
-
- if (!((EMapPrivate *) map->priv)->frozen)
- {
- /* FIXME: Re-scaling the whole pixbuf is more than a little
- * overkill when just one point is removed */
-
- update_render_surface (map, TRUE);
- repaint_point (map, point);
- }
-
- g_free (point);
-}
-
-void
-e_map_point_get_location (EMapPoint *point,
- gdouble *longitude,
- gdouble *latitude)
-{
- *longitude = point->longitude;
- *latitude = point->latitude;
-}
-
-gchar *
-e_map_point_get_name (EMapPoint *point)
-{
- return point->name;
-}
-
-guint32
-e_map_point_get_color_rgba (EMapPoint *point)
-{
- return point->rgba;
-}
-
-void
-e_map_point_set_color_rgba (EMap *map,
- EMapPoint *point,
- guint32 color_rgba)
-{
- point->rgba = color_rgba;
-
- if (!((EMapPrivate *) map->priv)->frozen)
- {
- /* TODO: Redraw area around point only */
-
- update_render_point (map, point);
- repaint_point (map, point);
- }
-}
-
-void
-e_map_point_set_data (EMapPoint *point,
- gpointer data)
-{
- point->user_data = data;
-}
-
-gpointer
-e_map_point_get_data (EMapPoint *point)
-{
- return point->user_data;
-}
-
-gboolean
-e_map_point_is_in_view (EMap *map,
- EMapPoint *point)
-{
- GtkAllocation allocation;
- gdouble x, y;
-
- if (!map->priv->map_render_surface) return FALSE;
-
- e_map_world_to_window (map, point->longitude, point->latitude, &x, &y);
- gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
-
- if (x >= 0 && x < allocation.width &&
- y >= 0 && y < allocation.height)
- return TRUE;
-
- return FALSE;
-}
-
-EMapPoint *
-e_map_get_closest_point (EMap *map,
- gdouble longitude,
- gdouble latitude,
- gboolean in_view)
-{
- EMapPoint *point_chosen = NULL, *point;
- gdouble min_dist = 0.0, dist;
- gdouble dx, dy;
- gint i;
-
- for (i = 0; i < map->priv->points->len; i++)
- {
- point = g_ptr_array_index (map->priv->points, i);
- if (in_view && !e_map_point_is_in_view (map, point)) continue;
-
- dx = point->longitude - longitude;
- dy = point->latitude - latitude;
- dist = dx * dx + dy * dy;
-
- if (!point_chosen || dist < min_dist)
- {
- min_dist = dist;
- point_chosen = point;
- }
- }
-
- return point_chosen;
-}
-
-/* ------------------ *
- * Internal functions *
- * ------------------ */
-
-static void
-update_and_paint (EMap *map)
-{
- update_render_surface (map, TRUE);
- gtk_widget_queue_draw (GTK_WIDGET (map));
-}
-
-static gint
-load_map_background (EMap *map,
- gchar *name)
-{
- GdkPixbuf *pb0;
-
- pb0 = gdk_pixbuf_new_from_file (name, NULL);
- if (!pb0)
- return FALSE;
-
- if (map->priv->map_pixbuf) g_object_unref (map->priv->map_pixbuf);
- map->priv->map_pixbuf = pb0;
- update_render_surface (map, TRUE);
-
- return TRUE;
-}
-
-static void
-update_render_surface (EMap *map,
- gboolean render_overlays)
-{
- EMapPoint *point;
- GtkAllocation allocation;
- gint width, height, orig_width, orig_height;
- gdouble zoom;
- gint i;
-
- if (!gtk_widget_get_realized (GTK_WIDGET (map)))
- return;
-
- gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
-
- /* Set up value shortcuts */
-
- width = allocation.width;
- height = allocation.height;
- orig_width = gdk_pixbuf_get_width (map->priv->map_pixbuf);
- orig_height = gdk_pixbuf_get_height (map->priv->map_pixbuf);
-
- /* Compute scaled width and height based on the extreme dimension */
-
- if ((gdouble) width / orig_width > (gdouble) height / orig_height)
- zoom = (gdouble) width / (gdouble) orig_width;
- else
- zoom = (gdouble) height / (gdouble) orig_height;
-
- if (map->priv->zoom_state == E_MAP_ZOOMED_IN)
- zoom *= 2.0;
- height = (orig_height * zoom) + 0.5;
- width = (orig_width * zoom) + 0.5;
-
- /* Reallocate the pixbuf */
-
- if (map->priv->map_render_surface)
- cairo_surface_destroy (map->priv->map_render_surface);
- map->priv->map_render_surface = gdk_window_create_similar_surface (
- gtk_widget_get_window (GTK_WIDGET (map)),
- CAIRO_CONTENT_COLOR, width, height);
-
- /* Scale the original map into the rendering pixbuf */
-
- if (width > 1 && height > 1) {
- cairo_t *cr = cairo_create (map->priv->map_render_surface);
- cairo_scale (
- cr,
- (gdouble) width / orig_width,
- (gdouble) height / orig_height);
- gdk_cairo_set_source_pixbuf (cr, map->priv->map_pixbuf, 0, 0);
- cairo_paint (cr);
- cairo_destroy (cr);
- }
-
- /* Compute image offsets with respect to window */
-
- set_scroll_area (map, width, height);
-
- if (render_overlays) {
- /* Add points */
-
- for (i = 0; i < map->priv->points->len; i++) {
- point = g_ptr_array_index (map->priv->points, i);
- update_render_point (map, point);
- }
- }
-}
-
-/* Redraw point in client surface */
-
-static void
-update_render_point (EMap *map,
- EMapPoint *point)
-{
- cairo_t *cr;
- gdouble px, py;
- static guchar mask1[] = { 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 };
- static guchar mask2[] = { 0x00, 0xff, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0x00,
- 0x00, 0xff, 0x00, 0x00 };
- cairo_surface_t *mask;
-
- if (map->priv->map_render_surface == NULL)
- return;
-
- cr = cairo_create (map->priv->map_render_surface);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-
- e_map_world_to_window (map, point->longitude, point->latitude, &px, &py);
- px = floor (px + map->priv->xofs);
- py = floor (py + map->priv->yofs);
-
- cairo_set_source_rgb (cr, 0, 0, 0);
- mask = cairo_image_surface_create_for_data (mask1, CAIRO_FORMAT_A8, 5, 5, 8);
- cairo_mask_surface (cr, mask, px - 2, py - 2);
- cairo_surface_destroy (mask);
-
- cairo_set_source_rgba (
- cr,
- ((point->rgba >> 24) & 0xff) / 255.0,
- ((point->rgba >> 16) & 0xff) / 255.0,
- ((point->rgba >> 8) & 0xff) / 255.0,
- ( point->rgba & 0xff) / 255.0);
- mask = cairo_image_surface_create_for_data (mask2, CAIRO_FORMAT_A8, 3, 3, 4);
- cairo_mask_surface (cr, mask, px - 1, py - 1);
- cairo_surface_destroy (mask);
-
- cairo_destroy (cr);
-}
-
-/* Repaint point on X server */
-
-static void
-repaint_point (EMap *map,
- EMapPoint *point)
-{
- gdouble px, py;
-
- if (!gtk_widget_is_drawable (GTK_WIDGET (map)))
- return;
-
- e_map_world_to_window (map, point->longitude, point->latitude, &px, &py);
-
- gtk_widget_queue_draw_area (
- GTK_WIDGET (map),
- (gint) px - 2, (gint) py - 2,
- 5, 5);
-}
-
-static void
-center_at (EMap *map,
- gdouble longitude,
- gdouble latitude)
-{
- GtkAllocation allocation;
- gint pb_width, pb_height;
- gdouble x, y;
-
- e_map_world_to_render_surface (map, longitude, latitude, &x, &y);
-
- pb_width = E_MAP_GET_WIDTH (map);
- pb_height = E_MAP_GET_HEIGHT (map);
-
- gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
-
- x = CLAMP (x - (allocation.width / 2), 0, pb_width - allocation.width);
- y = CLAMP (y - (allocation.height / 2), 0, pb_height - allocation.height);
-
- gtk_adjustment_set_value (map->priv->hadjustment, x);
- gtk_adjustment_set_value (map->priv->vadjustment, y);
-
- gtk_widget_queue_draw (GTK_WIDGET (map));
-}
-
-/* Scrolls the view to the specified offsets. Does not perform range checking! */
-
-static void
-scroll_to (EMap *map,
- gint x,
- gint y)
-{
- gint xofs, yofs;
-
- /* Compute offsets and check bounds */
-
- xofs = x - map->priv->xofs;
- yofs = y - map->priv->yofs;
-
- if (xofs == 0 && yofs == 0)
- return;
-
- map->priv->xofs = x;
- map->priv->yofs = y;
-
- gtk_widget_queue_draw (GTK_WIDGET (map));
-}
-
-static void
-set_scroll_area (EMap *view,
- gint width,
- gint height)
-{
- EMapPrivate *priv;
- GtkAllocation allocation;
-
- priv = view->priv;
-
- if (!gtk_widget_get_realized (GTK_WIDGET (view)))
- return;
-
- if (!priv->hadjustment || !priv->vadjustment)
- return;
-
- g_object_freeze_notify (G_OBJECT (priv->hadjustment));
- g_object_freeze_notify (G_OBJECT (priv->vadjustment));
-
- gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
-
- priv->xofs = CLAMP (priv->xofs, 0, width - allocation.width);
- priv->yofs = CLAMP (priv->yofs, 0, height - allocation.height);
-
- gtk_adjustment_configure (
- priv->hadjustment,
- priv->xofs,
- 0, width,
- SCROLL_STEP_SIZE,
- allocation.width / 2,
- allocation.width);
- gtk_adjustment_configure (
- priv->vadjustment,
- priv->yofs,
- 0, height,
- SCROLL_STEP_SIZE,
- allocation.height / 2,
- allocation.height);
-
- g_object_thaw_notify (G_OBJECT (priv->hadjustment));
- g_object_thaw_notify (G_OBJECT (priv->vadjustment));
-}