diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2012-12-10 21:09:59 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2012-12-13 03:33:43 +0800 |
commit | d09d8de870b6697c8a8b262e7e077b871a69b315 (patch) | |
tree | 3b718882e7a0bb0a996daf2967a033d91714c9b5 /widgets/misc/e-map.c | |
parent | b61331ed03ac1c7a9b8614e25510040b9c60ae02 (diff) | |
download | gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.gz gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.bz2 gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.lz gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.xz gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.zst gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.zip |
Consolidate base utility libraries into libeutil.
Evolution consists of entirely too many small utility libraries, which
increases linking and loading time, places a burden on higher layers of
the application (e.g. modules) which has to remember to link to all the
small in-tree utility libraries, and makes it difficult to generate API
documentation for these utility libraries in one Gtk-Doc module.
Merge the following utility libraries under the umbrella of libeutil,
and enforce a single-include policy on libeutil so we can reorganize
the files as desired without disrupting its pseudo-public API.
libemail-utils/libemail-utils.la
libevolution-utils/libevolution-utils.la
filter/libfilter.la
widgets/e-timezone-dialog/libetimezonedialog.la
widgets/menus/libmenus.la
widgets/misc/libemiscwidgets.la
widgets/table/libetable.la
widgets/text/libetext.la
This also merges libedataserverui from the Evolution-Data-Server module,
since Evolution is its only consumer nowadays, and I'd like to make some
improvements to those APIs without concern for backward-compatibility.
And finally, start a Gtk-Doc module for libeutil. It's going to be a
project just getting all the symbols _listed_ much less _documented_.
But the skeletal structure is in place and I'm off to a good start.
Diffstat (limited to 'widgets/misc/e-map.c')
-rw-r--r-- | widgets/misc/e-map.c | 1430 |
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, ¤t_longitude, ¤t_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)); -} |