~cjwatson/ubiquity/new-partitioner

« back to all changes in this revision

Viewing changes to src/cut-and-paste/e-map/e-map.c

  • Committer: Colin Watson
  • Date: 2006-02-22 15:22:10 UTC
  • mto: This revision was merged to the branch mainline in revision 783.
  • Revision ID: colin.watson@canonical.com-20060222152210-79c487063e89beba
* Add e-map widget, cut-and-pasted from evolution via gnome-system-tools
  (ugh).
* Basic autoconfiscation for the above.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/* Map widget.
 
3
 *
 
4
 * Copyright (C) 2000-2001 Ximian, Inc.
 
5
 *
 
6
 * Authors: Hans Petter Jansson <hpj@ximian.com>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
21
 */
 
22
 
 
23
#include <config.h>
 
24
#include <math.h>
 
25
#include <stdlib.h>
 
26
#include <gdk/gdkkeysyms.h>
 
27
#include <gtk/gtksignal.h>
 
28
#include <gdk-pixbuf/gdk-pixbuf.h>
 
29
#include <libart_lgpl/art_filterlevel.h>
 
30
 
 
31
#include "e-map.h"
 
32
#include "e-map-marshal.h"
 
33
 
 
34
/* Scroll step increment */
 
35
 
 
36
#define SCROLL_STEP_SIZE 32
 
37
 
 
38
 
 
39
/* */
 
40
 
 
41
#define E_MAP_GET_WIDTH(map) gdk_pixbuf_get_width(((EMapPrivate *) E_MAP(map)->priv)->map_render_pixbuf)
 
42
#define E_MAP_GET_HEIGHT(map) gdk_pixbuf_get_height(((EMapPrivate *) E_MAP(map)->priv)->map_render_pixbuf)
 
43
 
 
44
 
 
45
/* Zoom state - keeps track of animation hacks */
 
46
 
 
47
typedef enum
 
48
{
 
49
        E_MAP_ZOOMED_IN,
 
50
        E_MAP_ZOOMED_OUT,
 
51
        E_MAP_ZOOMING_IN,
 
52
        E_MAP_ZOOMING_OUT
 
53
}
 
54
EMapZoomState;
 
55
 
 
56
 
 
57
/* Private part of the EMap structure */
 
58
 
 
59
typedef struct
 
60
{
 
61
        /* Pointer to map image */
 
62
        GdkPixbuf *map_pixbuf, *map_render_pixbuf;
 
63
 
 
64
        /* Settings */
 
65
        gboolean frozen, smooth_zoom;
 
66
 
 
67
        /* Adjustments for scrolling */
 
68
        GtkAdjustment *hadj;
 
69
        GtkAdjustment *vadj;
 
70
 
 
71
        /* Signal ids for adjustments */
 
72
        gulong hadj_signal_id;
 
73
        gulong vadj_signal_id;
 
74
 
 
75
        /* Current scrolling offsets */
 
76
        int xofs, yofs;
 
77
 
 
78
        /* Realtime zoom data */
 
79
        EMapZoomState zoom_state;
 
80
        double zoom_target_long, zoom_target_lat;
 
81
 
 
82
        /* Dots */
 
83
        GPtrArray *points;
 
84
}
 
85
EMapPrivate;
 
86
 
 
87
 
 
88
/* Signal IDs */
 
89
 
 
90
enum
 
91
{
 
92
        BOGUS,
 
93
        LAST_SIGNAL
 
94
};
 
95
 
 
96
static guint e_map_signals[LAST_SIGNAL];
 
97
 
 
98
 
 
99
/* Internal prototypes */
 
100
 
 
101
static void e_map_class_init (EMapClass *class);
 
102
static void e_map_init (EMap *view);
 
103
static void e_map_destroy (GtkObject *object);
 
104
static void e_map_finalize (GObject *object);
 
105
static void e_map_unmap (GtkWidget *widget);
 
106
static void e_map_realize (GtkWidget *widget);
 
107
static void e_map_unrealize (GtkWidget *widget);
 
108
static void e_map_size_request (GtkWidget *widget, GtkRequisition *requisition);
 
109
static void e_map_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
 
110
static gint e_map_button_press (GtkWidget *widget, GdkEventButton *event);
 
111
static gint e_map_button_release (GtkWidget *widget, GdkEventButton *event);
 
112
static gint e_map_motion (GtkWidget *widget, GdkEventMotion *event);
 
113
static gint e_map_expose (GtkWidget *widget, GdkEventExpose *event);
 
114
static gint e_map_key_press (GtkWidget *widget, GdkEventKey *event);
 
115
static void e_map_set_scroll_adjustments (GtkWidget *widget, GtkAdjustment *hadj, GtkAdjustment *vadj);
 
116
 
 
117
static void update_render_pixbuf (EMap *map, ArtFilterLevel interp, gboolean render_overlays);
 
118
static void set_scroll_area (EMap *view);
 
119
static void request_paint_area (EMap *view, GdkRectangle *area);
 
120
static void center_at (EMap *map, int x, int y, gboolean scroll);
 
121
static void smooth_center_at (EMap *map, int x, int y);
 
122
static void scroll_to (EMap *view, int x, int y);
 
123
static void zoom_do (EMap *map);
 
124
static gint load_map_background (EMap *view, gchar *name);
 
125
static void adjustment_changed_cb (GtkAdjustment *adj, gpointer data);
 
126
static void update_and_paint (EMap *map);
 
127
static void update_render_point (EMap *map, EMapPoint *point);
 
128
static void repaint_point (EMap *map, EMapPoint *point);
 
129
 
 
130
static GtkWidgetClass *parent_class;
 
131
 
 
132
 
 
133
/* ----------------- *
 
134
 * Widget management *
 
135
 * ----------------- */
 
136
 
 
137
 
 
138
/**
 
139
 * e_map_get_type:
 
140
 * @void: 
 
141
 * 
 
142
 * Registers the #EMap class if necessary, and returns the type ID
 
143
 * associated to it.
 
144
 * 
 
145
 * Return value: The type ID of the #EMap class.
 
146
 **/
 
147
 
 
148
GtkType
 
149
e_map_get_type (void)
 
150
{
 
151
        static GtkType e_map_type = 0;
 
152
 
 
153
        if (!e_map_type)
 
154
        {
 
155
                static const GTypeInfo e_map_info =
 
156
                {
 
157
                        sizeof (EMapClass),
 
158
                        NULL, /* base init */
 
159
                        NULL, /* base finalize */
 
160
                        (GClassInitFunc) e_map_class_init,
 
161
                        NULL, /* class finalize */
 
162
                        NULL, /* class data */
 
163
                        sizeof (EMap),
 
164
                        0,
 
165
                        (GInstanceInitFunc) e_map_init,
 
166
                        NULL, /* value table */
 
167
                };
 
168
 
 
169
                e_map_type = g_type_register_static (GTK_TYPE_WIDGET,
 
170
                                                     "EMap",
 
171
                                                     &e_map_info, 0);
 
172
        }
 
173
 
 
174
        return e_map_type;
 
175
}
 
176
 
 
177
/* Class initialization function for the map view */
 
178
 
 
179
static void
 
180
e_map_class_init (EMapClass *class)
 
181
{
 
182
        GObjectClass *g_object_class;
 
183
        GtkObjectClass *object_class;
 
184
        GtkWidgetClass *widget_class;
 
185
 
 
186
        g_object_class = (GObjectClass*) class;
 
187
        object_class = (GtkObjectClass *) class;
 
188
        widget_class = (GtkWidgetClass *) class;
 
189
 
 
190
        parent_class = gtk_type_class (GTK_TYPE_WIDGET);
 
191
 
 
192
        object_class->destroy = e_map_destroy;
 
193
        
 
194
        g_object_class->finalize = e_map_finalize;
 
195
 
 
196
        class->set_scroll_adjustments = e_map_set_scroll_adjustments;
 
197
        widget_class->set_scroll_adjustments_signal =
 
198
                g_signal_new ("set_scroll_adjustments",
 
199
                              G_OBJECT_CLASS_TYPE (object_class),
 
200
                              G_SIGNAL_RUN_LAST,
 
201
                              G_STRUCT_OFFSET (EMapClass, set_scroll_adjustments),
 
202
                              NULL, NULL,
 
203
                              g_cclosure_user_marshal_VOID__OBJECT_OBJECT,
 
204
                              G_TYPE_NONE, 2,
 
205
                              GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
 
206
/*      
 
207
                g_signal_new ("set_scroll_adjustments",
 
208
                              G_OBJECT_CLASS_TYPE (object_class),
 
209
                              G_SIGNAL_RUN_LAST,
 
210
                              G_STRUCT_OFFSET (EMapClass, set_scroll_adjustments),
 
211
                              NULL, NULL,
 
212
                              _gtk_marshal_VOID__OBJECT_OBJECT,
 
213
                              G_TYPE_NONE, 2,
 
214
                              GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
 
215
*/
 
216
        widget_class->unmap = e_map_unmap;
 
217
        widget_class->realize = e_map_realize;
 
218
        widget_class->unrealize = e_map_unrealize;
 
219
        widget_class->size_request = e_map_size_request;
 
220
        widget_class->size_allocate = e_map_size_allocate;
 
221
        widget_class->button_press_event = e_map_button_press;
 
222
        widget_class->button_release_event = e_map_button_release;
 
223
        widget_class->motion_notify_event = e_map_motion;
 
224
        widget_class->expose_event = e_map_expose;
 
225
        widget_class->key_press_event = e_map_key_press;
 
226
}
 
227
 
 
228
 
 
229
/* Object initialization function for the map view */
 
230
 
 
231
static void
 
232
e_map_init (EMap *view)
 
233
{
 
234
        EMapPrivate *priv;
 
235
 
 
236
        priv = g_new0 (EMapPrivate, 1);
 
237
        view->priv = priv;
 
238
 
 
239
        load_map_background (view, MAP_DIR"/world_map-960.png");
 
240
        priv->frozen = FALSE;
 
241
        priv->smooth_zoom = TRUE;
 
242
        priv->zoom_state = E_MAP_ZOOMED_OUT;
 
243
        priv->points = g_ptr_array_new ();
 
244
 
 
245
        GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
 
246
        GTK_WIDGET_UNSET_FLAGS (view, GTK_NO_WINDOW);
 
247
}
 
248
 
 
249
 
 
250
/* Destroy handler for the map view */
 
251
 
 
252
static void
 
253
e_map_destroy (GtkObject *object)
 
254
{
 
255
        EMap *view;
 
256
        EMapPrivate *priv;
 
257
 
 
258
        g_return_if_fail (object != NULL);
 
259
        g_return_if_fail (IS_E_MAP (object));
 
260
 
 
261
        view = E_MAP (object);
 
262
        priv = view->priv;
 
263
 
 
264
        g_signal_handler_disconnect (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
265
        g_signal_handler_disconnect (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
266
 
 
267
        if (GTK_OBJECT_CLASS (parent_class)->destroy)
 
268
                (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 
269
}
 
270
 
 
271
 
 
272
/* Finalize handler for the map view */
 
273
 
 
274
static void
 
275
e_map_finalize (GObject *object)
 
276
{
 
277
        EMap *view;
 
278
        EMapPrivate *priv;
 
279
 
 
280
        g_return_if_fail (object != NULL);
 
281
        g_return_if_fail (IS_E_MAP (object));
 
282
 
 
283
        view = E_MAP (object);
 
284
        priv = view->priv;
 
285
 
 
286
        gtk_object_unref (GTK_OBJECT (priv->hadj));
 
287
        priv->hadj = NULL;
 
288
 
 
289
        gtk_object_unref (GTK_OBJECT (priv->vadj));
 
290
        priv->vadj = NULL;
 
291
 
 
292
        if (priv->map_pixbuf)
 
293
        {
 
294
                gdk_pixbuf_unref (priv->map_pixbuf);
 
295
                priv->map_pixbuf = NULL;
 
296
        }
 
297
 
 
298
        if (priv->map_render_pixbuf)
 
299
        {
 
300
                gdk_pixbuf_unref (priv->map_render_pixbuf);
 
301
                priv->map_render_pixbuf = NULL;
 
302
        }
 
303
 
 
304
        g_free (priv);
 
305
        view->priv = NULL;
 
306
 
 
307
        if (G_OBJECT_CLASS (parent_class)->finalize)
 
308
                G_OBJECT_CLASS (parent_class)->finalize (object);
 
309
}
 
310
 
 
311
 
 
312
/* Unmap handler for the map view */
 
313
 
 
314
static void
 
315
e_map_unmap (GtkWidget *widget)
 
316
{
 
317
        g_return_if_fail (widget != NULL);
 
318
        g_return_if_fail (IS_E_MAP (widget));
 
319
 
 
320
        if (GTK_WIDGET_CLASS (parent_class)->unmap)
 
321
                (*GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
 
322
}
 
323
 
 
324
 
 
325
/* Realize handler for the map view */
 
326
 
 
327
static void
 
328
e_map_realize (GtkWidget *widget)
 
329
{
 
330
        GdkWindowAttr attr;
 
331
        int attr_mask;
 
332
 
 
333
        g_return_if_fail (widget != NULL);
 
334
        g_return_if_fail (IS_E_MAP (widget));
 
335
 
 
336
        GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
337
 
 
338
        attr.window_type = GDK_WINDOW_CHILD;
 
339
        attr.x = widget->allocation.x;
 
340
        attr.y = widget->allocation.y;
 
341
        attr.width = widget->allocation.width;
 
342
        attr.height = widget->allocation.height;
 
343
        attr.wclass = GDK_INPUT_OUTPUT;
 
344
        attr.visual = gdk_rgb_get_visual ();
 
345
        attr.colormap = gdk_rgb_get_colormap ();
 
346
        attr.event_mask = gtk_widget_get_events (widget) |
 
347
          GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK |
 
348
          GDK_POINTER_MOTION_MASK;
 
349
 
 
350
        attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
 
351
 
 
352
        widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attr, attr_mask);
 
353
        gdk_window_set_user_data (widget->window, widget);
 
354
 
 
355
        widget->style = gtk_style_attach (widget->style, widget->window);
 
356
 
 
357
        gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
 
358
        update_render_pixbuf (E_MAP (widget), GDK_INTERP_BILINEAR, TRUE);
 
359
}
 
360
 
 
361
 
 
362
/* Unrealize handler for the map view */
 
363
 
 
364
static void
 
365
e_map_unrealize (GtkWidget *widget)
 
366
{
 
367
        g_return_if_fail (widget != NULL);
 
368
        g_return_if_fail (IS_E_MAP (widget));
 
369
 
 
370
        if (GTK_WIDGET_CLASS (parent_class)->unrealize)
 
371
                (*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 
372
}
 
373
 
 
374
 
 
375
/* Size_request handler for the map view */
 
376
 
 
377
static void
 
378
e_map_size_request (GtkWidget *widget, GtkRequisition *requisition)
 
379
{
 
380
        EMap *view;
 
381
        EMapPrivate *priv;
 
382
 
 
383
        g_return_if_fail (widget != NULL);
 
384
        g_return_if_fail (IS_E_MAP (widget));
 
385
        g_return_if_fail (requisition != NULL);
 
386
 
 
387
        view = E_MAP (widget);
 
388
        priv = view->priv;
 
389
 
 
390
        /* TODO: Put real sizes here. */
 
391
 
 
392
        requisition->width = gdk_pixbuf_get_width (priv->map_pixbuf);
 
393
        requisition->height = gdk_pixbuf_get_height (priv->map_pixbuf);
 
394
}
 
395
 
 
396
 
 
397
/* Size_allocate handler for the map view */
 
398
 
 
399
static void
 
400
e_map_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
 
401
{
 
402
        EMap *view;
 
403
        EMapPrivate *priv;
 
404
        int xofs, yofs;
 
405
        GdkRectangle area;
 
406
 
 
407
        g_return_if_fail (widget != NULL);
 
408
        g_return_if_fail (IS_E_MAP (widget));
 
409
        g_return_if_fail (allocation != NULL);
 
410
 
 
411
        view = E_MAP (widget);
 
412
        priv = view->priv;
 
413
 
 
414
        xofs = priv->xofs;
 
415
        yofs = priv->yofs;
 
416
 
 
417
        /* Resize the window */
 
418
 
 
419
        widget->allocation = *allocation;
 
420
 
 
421
        if (GTK_WIDGET_REALIZED (widget))
 
422
        {
 
423
                gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
 
424
 
 
425
                area.x = 0;
 
426
                area.y = 0;
 
427
                area.width = allocation->width;
 
428
                area.height = allocation->height;
 
429
                request_paint_area (E_MAP (widget), &area);
 
430
        }
 
431
 
 
432
        update_render_pixbuf (view, GDK_INTERP_BILINEAR, TRUE);
 
433
}
 
434
 
 
435
 
 
436
/* Button press handler for the map view */
 
437
 
 
438
static gint
 
439
e_map_button_press (GtkWidget *widget, GdkEventButton *event)
 
440
{
 
441
        EMap *view;
 
442
        EMapPrivate *priv;
 
443
 
 
444
        view = E_MAP (widget);
 
445
        priv = view->priv;
 
446
 
 
447
        if (!GTK_WIDGET_HAS_FOCUS (widget)) gtk_widget_grab_focus (widget);
 
448
        return TRUE;
 
449
}
 
450
 
 
451
 
 
452
/* Button release handler for the map view */
 
453
 
 
454
static gint
 
455
e_map_button_release (GtkWidget *widget, GdkEventButton *event)
 
456
{
 
457
        EMap *view;
 
458
        EMapPrivate *priv;
 
459
 
 
460
        view = E_MAP (widget);
 
461
        priv = view->priv;
 
462
 
 
463
        if (event->button != 1) return FALSE;
 
464
 
 
465
        gdk_pointer_ungrab (event->time);
 
466
        return TRUE;
 
467
}
 
468
 
 
469
 
 
470
/* Motion handler for the map view */
 
471
 
 
472
static gint
 
473
e_map_motion (GtkWidget *widget, GdkEventMotion *event)
 
474
{
 
475
        EMap *view;
 
476
        EMapPrivate *priv;
 
477
 
 
478
        view = E_MAP (widget);
 
479
        priv = view->priv;
 
480
 
 
481
        return FALSE;
 
482
 
 
483
/*
 
484
 * if (event->is_hint)
 
485
 *   gdk_window_get_pointer(widget->window, &x, &y, &mods);
 
486
 * else
 
487
 * {
 
488
 *   x = event->x;
 
489
 *   y = event->y;
 
490
 * }
 
491
 *
 
492
 * return TRUE;
 
493
 */
 
494
}
 
495
 
 
496
 
 
497
/* Expose handler for the map view */
 
498
 
 
499
static gint
 
500
e_map_expose (GtkWidget *widget, GdkEventExpose *event)
 
501
{
 
502
        EMap *view;
 
503
 
 
504
        g_return_val_if_fail (widget != NULL, FALSE);
 
505
        g_return_val_if_fail (IS_E_MAP (widget), FALSE);
 
506
        g_return_val_if_fail (event != NULL, FALSE);
 
507
 
 
508
        view = E_MAP (widget);
 
509
 
 
510
        request_paint_area (view, &event->area);
 
511
        return TRUE;
 
512
}
 
513
 
 
514
 
 
515
/* Set_scroll_adjustments handler for the map view */
 
516
 
 
517
static void
 
518
e_map_set_scroll_adjustments (GtkWidget *widget, GtkAdjustment *hadj, GtkAdjustment *vadj)
 
519
{
 
520
        EMap *view;
 
521
        EMapPrivate *priv;
 
522
        gboolean need_adjust;
 
523
 
 
524
        g_return_if_fail (widget != NULL);
 
525
        g_return_if_fail (IS_E_MAP (widget));
 
526
 
 
527
        view = E_MAP (widget);
 
528
        priv = view->priv;
 
529
 
 
530
        if (hadj) g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
 
531
        else hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
 
532
 
 
533
        if (vadj) g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
 
534
        else vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
 
535
 
 
536
        if (priv->hadj && priv->hadj != hadj)
 
537
        {
 
538
                g_signal_handler_disconnect (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
539
                g_object_unref (G_OBJECT (priv->hadj));
 
540
        }
 
541
 
 
542
        if (priv->vadj && priv->vadj != vadj)
 
543
        {
 
544
                g_signal_handler_disconnect (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
545
                g_object_unref (G_OBJECT (priv->vadj));
 
546
        }
 
547
 
 
548
        need_adjust = FALSE;
 
549
 
 
550
        if (priv->hadj != hadj)
 
551
        {
 
552
                priv->hadj = hadj;
 
553
                g_object_ref (G_OBJECT (priv->hadj));
 
554
                gtk_object_sink (GTK_OBJECT (priv->hadj));
 
555
 
 
556
                priv->hadj_signal_id = g_signal_connect (G_OBJECT (priv->hadj),
 
557
                                                         "value_changed",
 
558
                                                         G_CALLBACK (adjustment_changed_cb),
 
559
                                                         view);
 
560
 
 
561
                need_adjust = TRUE;
 
562
        }
 
563
 
 
564
        if (priv->vadj != vadj)
 
565
        {
 
566
                priv->vadj = vadj;
 
567
                g_object_ref (G_OBJECT (priv->vadj));
 
568
                gtk_object_sink (GTK_OBJECT (priv->vadj));
 
569
 
 
570
                priv->vadj_signal_id = g_signal_connect (G_OBJECT (priv->vadj),
 
571
                                                         "value_changed",
 
572
                                                         G_CALLBACK (adjustment_changed_cb),
 
573
                                                         view);
 
574
 
 
575
                need_adjust = TRUE;
 
576
        }
 
577
 
 
578
        if (need_adjust) adjustment_changed_cb (NULL, view);
 
579
}
 
580
 
 
581
 
 
582
/* Key press handler for the map view */
 
583
 
 
584
static gint
 
585
e_map_key_press (GtkWidget *widget, GdkEventKey *event)
 
586
{
 
587
        EMap *view;
 
588
        EMapPrivate *priv;
 
589
        gboolean do_scroll;
 
590
        int xofs, yofs;
 
591
 
 
592
        view = E_MAP (widget);
 
593
        priv = view->priv;
 
594
 
 
595
        do_scroll = FALSE;
 
596
        xofs = yofs = 0;
 
597
 
 
598
        switch (event->keyval)
 
599
        {
 
600
                case GDK_Up:
 
601
                        do_scroll = TRUE;
 
602
                        xofs = 0;
 
603
                        yofs = -SCROLL_STEP_SIZE;
 
604
                        break;
 
605
 
 
606
                case GDK_Down:
 
607
                        do_scroll = TRUE;
 
608
                        xofs = 0;
 
609
                        yofs = SCROLL_STEP_SIZE;
 
610
                        break;
 
611
 
 
612
                case GDK_Left:
 
613
                        do_scroll = TRUE;
 
614
                        xofs = -SCROLL_STEP_SIZE;
 
615
                        yofs = 0;
 
616
                        break;
 
617
 
 
618
                case GDK_Right:
 
619
                        do_scroll = TRUE;
 
620
                        xofs = SCROLL_STEP_SIZE;
 
621
                        yofs = 0;
 
622
                        break;
 
623
 
 
624
                default:
 
625
                        return FALSE;
 
626
        }
 
627
 
 
628
        if (do_scroll)
 
629
        {
 
630
                int x, y;
 
631
 
 
632
                x = CLAMP (priv->xofs + xofs, 0, priv->hadj->upper - priv->hadj->page_size);
 
633
                y = CLAMP (priv->yofs + yofs, 0, priv->vadj->upper - priv->vadj->page_size);
 
634
 
 
635
                scroll_to (view, x, y);
 
636
 
 
637
                g_signal_handler_block (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
638
                g_signal_handler_block (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
639
 
 
640
                priv->hadj->value = x;
 
641
                priv->vadj->value = y;
 
642
 
 
643
                g_signal_emit_by_name (GTK_OBJECT (priv->hadj), "value_changed");
 
644
                g_signal_emit_by_name (GTK_OBJECT (priv->vadj), "value_changed");
 
645
 
 
646
                g_signal_handler_unblock (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
647
                g_signal_handler_unblock (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
648
        }
 
649
 
 
650
        return TRUE;
 
651
}
 
652
 
 
653
 
 
654
/* ---------------- *
 
655
 * Widget interface *
 
656
 * ---------------- */
 
657
 
 
658
 
 
659
/**
 
660
 * e_map_new:
 
661
 * @void: 
 
662
 * 
 
663
 * Creates a new empty map widget.
 
664
 * 
 
665
 * Return value: A newly-created map widget.
 
666
 **/
 
667
 
 
668
EMap *
 
669
e_map_new ()
 
670
{
 
671
        GtkWidget *widget;
 
672
 
 
673
        widget = GTK_WIDGET (g_type_create_instance (TYPE_E_MAP));
 
674
        return (E_MAP (widget));
 
675
}
 
676
 
 
677
 
 
678
/* --- Coordinate translation --- */
 
679
 
 
680
 
 
681
/* These functions translate coordinates between longitude/latitude and
 
682
 * the image x/y offsets, using the equidistant cylindrical projection.
 
683
 * 
 
684
 * Longitude E <-180, 180]
 
685
 * Latitude  E <-90, 90]   */
 
686
 
 
687
void
 
688
e_map_window_to_world (EMap *map, double win_x, double win_y, double *world_longitude, double *world_latitude)
 
689
{
 
690
        EMapPrivate *priv;
 
691
        int width, height;
 
692
 
 
693
        g_return_if_fail (map);
 
694
 
 
695
        priv = map->priv;
 
696
        g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (map)));
 
697
 
 
698
        width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
 
699
        height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
 
700
 
 
701
        *world_longitude = (win_x + priv->xofs - (double) width / 2.0) /
 
702
                ((double) width / 2.0) * 180.0;
 
703
        *world_latitude = ((double) height / 2.0 - win_y - priv->yofs) /
 
704
                ((double) height / 2.0) * 90.0;
 
705
}
 
706
 
 
707
 
 
708
void
 
709
e_map_world_to_window (EMap *map, double world_longitude, double world_latitude, double *win_x, double *win_y)
 
710
{
 
711
        EMapPrivate *priv;
 
712
        int width, height;
 
713
 
 
714
        g_return_if_fail (map);
 
715
 
 
716
        priv = map->priv;
 
717
        g_return_if_fail (priv->map_render_pixbuf);
 
718
        g_return_if_fail (world_longitude >= -180.0 && world_longitude <= 180.0);
 
719
        g_return_if_fail (world_latitude >= -90.0 && world_latitude <= 90.0);
 
720
 
 
721
        width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
 
722
        height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
 
723
 
 
724
        *win_x = (width / 2.0 + (width / 2.0) * world_longitude / 180.0) - priv->xofs;
 
725
        *win_y = (height / 2.0 - (height / 2.0) * world_latitude / 90.0) - priv->yofs;
 
726
 
 
727
#ifdef DEBUG
 
728
        printf ("Map size: (%d, %d)\nCoords: (%.1f, %.1f) -> (%.1f, %.1f)\n---\n", width, height, world_longitude, world_latitude, *win_x, *win_y);
 
729
#endif
 
730
}
 
731
 
 
732
 
 
733
/* --- Zoom --- */
 
734
 
 
735
 
 
736
double
 
737
e_map_get_magnification (EMap *map)
 
738
{
 
739
        EMapPrivate *priv;
 
740
        
 
741
        priv = map->priv;
 
742
        if (priv->zoom_state == E_MAP_ZOOMED_IN) return 2.0;
 
743
        else return 1.0;
 
744
}
 
745
 
 
746
 
 
747
void
 
748
e_map_zoom_to_location (EMap *map, double longitude, double latitude)
 
749
{
 
750
        EMapPrivate *priv;
 
751
        int width, height;
 
752
 
 
753
        g_return_if_fail (map);
 
754
        g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (map)));
 
755
 
 
756
        priv = map->priv;
 
757
 
 
758
        if (priv->zoom_state == E_MAP_ZOOMED_IN) e_map_zoom_out (map);
 
759
        else if (priv->zoom_state != E_MAP_ZOOMED_OUT) return;
 
760
 
 
761
        width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
 
762
        height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
 
763
 
 
764
        priv->zoom_state = E_MAP_ZOOMING_IN;
 
765
        priv->zoom_target_long = longitude;
 
766
        priv->zoom_target_lat = latitude;
 
767
 
 
768
        zoom_do (map);
 
769
}
 
770
 
 
771
 
 
772
void
 
773
e_map_zoom_out (EMap *map)
 
774
{
 
775
        EMapPrivate *priv;
 
776
        int width, height;
 
777
 
 
778
        g_return_if_fail (map);
 
779
        g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (map)));
 
780
 
 
781
        priv = map->priv;
 
782
 
 
783
        if (priv->zoom_state != E_MAP_ZOOMED_IN) return;
 
784
 
 
785
        width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
 
786
        height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
 
787
 
 
788
        priv->zoom_state = E_MAP_ZOOMING_OUT;
 
789
        zoom_do (map);
 
790
        priv->zoom_state = E_MAP_ZOOMED_OUT;
 
791
}
 
792
 
 
793
 
 
794
void
 
795
e_map_set_smooth_zoom (EMap *map, gboolean state)
 
796
{
 
797
        ((EMapPrivate *) map->priv)->smooth_zoom = state;
 
798
}
 
799
 
 
800
 
 
801
gboolean
 
802
e_map_get_smooth_zoom (EMap *map)
 
803
{
 
804
        return (((EMapPrivate *) map->priv)->smooth_zoom);
 
805
}
 
806
 
 
807
 
 
808
void
 
809
e_map_freeze (EMap *map)
 
810
{
 
811
        ((EMapPrivate *) map->priv)->frozen = TRUE;
 
812
}
 
813
 
 
814
 
 
815
void
 
816
e_map_thaw (EMap *map)
 
817
{
 
818
        ((EMapPrivate *) map->priv)->frozen = FALSE;
 
819
        update_and_paint (map);
 
820
}
 
821
 
 
822
 
 
823
/* --- Point manipulation --- */
 
824
 
 
825
 
 
826
EMapPoint *
 
827
e_map_add_point (EMap *map, gchar *name, double longitude, double latitude, guint32 color_rgba)
 
828
{
 
829
        EMapPrivate *priv;
 
830
        EMapPoint *point;
 
831
 
 
832
        priv = map->priv;
 
833
        point = g_new0 (EMapPoint, 1);
 
834
 
 
835
        point->name = name;  /* Can be NULL */
 
836
        point->longitude = longitude;
 
837
        point->latitude = latitude;
 
838
        point->rgba = color_rgba;
 
839
 
 
840
        g_ptr_array_add (priv->points, (gpointer) point);
 
841
 
 
842
        if (!priv->frozen)
 
843
        {
 
844
                update_render_point (map, point);
 
845
                repaint_point (map, point);
 
846
        }
 
847
 
 
848
        return point;
 
849
}
 
850
 
 
851
 
 
852
void
 
853
e_map_remove_point (EMap *map, EMapPoint *point)
 
854
{
 
855
        EMapPrivate *priv;
 
856
 
 
857
        priv = map->priv;
 
858
        g_ptr_array_remove (priv->points, point);
 
859
 
 
860
        if (!((EMapPrivate *) map->priv)->frozen)
 
861
        {
 
862
                /* FIXME: Re-scaling the whole pixbuf is more than a little
 
863
                 * overkill when just one point is removed */
 
864
 
 
865
                update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
 
866
                repaint_point (map, point);
 
867
        }
 
868
        
 
869
        g_free (point);
 
870
}
 
871
 
 
872
 
 
873
void
 
874
e_map_point_get_location (EMapPoint *point, double *longitude, double *latitude)
 
875
{
 
876
        *longitude = point->longitude;
 
877
        *latitude = point->latitude;
 
878
}
 
879
 
 
880
 
 
881
gchar *
 
882
e_map_point_get_name (EMapPoint *point)
 
883
{
 
884
        return point->name;
 
885
}
 
886
 
 
887
 
 
888
guint32
 
889
e_map_point_get_color_rgba (EMapPoint *point)
 
890
{
 
891
        return point->rgba;
 
892
}
 
893
 
 
894
 
 
895
void
 
896
e_map_point_set_color_rgba (EMap *map, EMapPoint *point, guint32 color_rgba)
 
897
{
 
898
        point->rgba = color_rgba;
 
899
 
 
900
        if (!((EMapPrivate *) map->priv)->frozen)
 
901
        {
 
902
                /* TODO: Redraw area around point only */
 
903
 
 
904
                update_render_point (map, point);
 
905
                repaint_point (map, point);
 
906
        }
 
907
}
 
908
 
 
909
 
 
910
void
 
911
e_map_point_set_data (EMapPoint *point, gpointer data)
 
912
{
 
913
        point->user_data = data;
 
914
}
 
915
 
 
916
 
 
917
gpointer
 
918
e_map_point_get_data (EMapPoint *point)
 
919
{
 
920
        return point->user_data;
 
921
}
 
922
 
 
923
 
 
924
gboolean
 
925
e_map_point_is_in_view (EMap *map, EMapPoint *point)
 
926
{
 
927
        EMapPrivate *priv;
 
928
        double x, y;
 
929
 
 
930
        priv = map->priv;
 
931
        if (!priv->map_render_pixbuf) return FALSE;
 
932
 
 
933
        e_map_world_to_window (map, point->longitude, point->latitude, &x, &y);
 
934
        
 
935
        if (x >= 0 && x < GTK_WIDGET (map)->allocation.width &&
 
936
            y >= 0 && y < GTK_WIDGET (map)->allocation.height)
 
937
                return TRUE;
 
938
        
 
939
        return FALSE;
 
940
}
 
941
 
 
942
 
 
943
EMapPoint *
 
944
e_map_get_closest_point (EMap *map, double longitude, double latitude, gboolean in_view)
 
945
{
 
946
        EMapPrivate *priv;
 
947
        EMapPoint *point_chosen = NULL, *point;
 
948
        double min_dist = 0.0, dist;
 
949
        double dx, dy;
 
950
        int i;
 
951
 
 
952
        priv = map->priv;
 
953
 
 
954
        for (i = 0; i < priv->points->len; i++)
 
955
        {
 
956
                point = g_ptr_array_index (priv->points, i);
 
957
                if (in_view && !e_map_point_is_in_view (map, point)) continue;
 
958
 
 
959
                dx = point->longitude - longitude;
 
960
                dy = point->latitude - latitude;
 
961
                dist = dx * dx + dy * dy;
 
962
 
 
963
                if (!point_chosen || dist < min_dist)
 
964
                {
 
965
                        min_dist = dist;
 
966
                        point_chosen = point;
 
967
                }
 
968
        }
 
969
 
 
970
        return point_chosen;
 
971
}
 
972
 
 
973
 
 
974
/* ------------------ *
 
975
 * Internal functions *
 
976
 * ------------------ */
 
977
 
 
978
 
 
979
static void
 
980
repaint_visible (EMap *map)
 
981
{
 
982
        GdkRectangle area;
 
983
 
 
984
        area.x = 0;
 
985
        area.y = 0;
 
986
        area.width = GTK_WIDGET (map)->allocation.width;
 
987
        area.height = GTK_WIDGET (map)->allocation.height;
 
988
        
 
989
        request_paint_area (map, &area);
 
990
}
 
991
 
 
992
 
 
993
static void
 
994
update_and_paint (EMap *map)
 
995
{
 
996
        update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
 
997
        repaint_visible (map);
 
998
}
 
999
 
 
1000
 
 
1001
static gint
 
1002
load_map_background (EMap *view, gchar *name)
 
1003
{
 
1004
        EMapPrivate *priv;
 
1005
        GdkPixbuf *pb0;
 
1006
 
 
1007
        priv = view->priv;
 
1008
 
 
1009
        pb0 = gdk_pixbuf_new_from_file (name, NULL);
 
1010
/*      pb0 = tool_load_image (name);*/
 
1011
        if (!pb0) return (FALSE);
 
1012
 
 
1013
        if (priv->map_pixbuf) gdk_pixbuf_unref (priv->map_pixbuf);
 
1014
        priv->map_pixbuf = pb0;
 
1015
        update_render_pixbuf (view, GDK_INTERP_BILINEAR, TRUE);
 
1016
 
 
1017
        return (TRUE);
 
1018
}
 
1019
 
 
1020
 
 
1021
static void
 
1022
update_render_pixbuf (EMap *map, ArtFilterLevel interp, gboolean render_overlays)
 
1023
{
 
1024
        EMapPrivate *priv;
 
1025
        EMapPoint *point;
 
1026
        int width, height, orig_width, orig_height;
 
1027
        double zoom;
 
1028
        int i;
 
1029
 
 
1030
        if (!GTK_WIDGET_REALIZED (GTK_WIDGET (map))) return;
 
1031
 
 
1032
        /* Set up value shortcuts */
 
1033
 
 
1034
        priv = map->priv;
 
1035
        width = GTK_WIDGET (map)->allocation.width;
 
1036
        height = GTK_WIDGET (map)->allocation.height;
 
1037
        orig_width = gdk_pixbuf_get_width (priv->map_pixbuf);
 
1038
        orig_height = gdk_pixbuf_get_height (priv->map_pixbuf);
 
1039
 
 
1040
        /* Compute scaled width and height based on the extreme dimension */
 
1041
 
 
1042
        if ((double) width / orig_width > (double) height / orig_height)
 
1043
        {
 
1044
                zoom = (double) width / (double) orig_width;
 
1045
        }
 
1046
        else
 
1047
        {
 
1048
                zoom = (double) height / (double) orig_height;
 
1049
        }
 
1050
 
 
1051
        if (priv->zoom_state == E_MAP_ZOOMED_IN) zoom *= 2.0;
 
1052
        height = (orig_height * zoom) + 0.5;
 
1053
        width = (orig_width * zoom) + 0.5;
 
1054
 
 
1055
        /* Reallocate the pixbuf */
 
1056
 
 
1057
        if (priv->map_render_pixbuf) gdk_pixbuf_unref (priv->map_render_pixbuf);
 
1058
        priv->map_render_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,    /* No alpha */
 
1059
                                                  8, width, height);
 
1060
 
 
1061
        /* Scale the original map into the rendering pixbuf */
 
1062
 
 
1063
        if (width > 1 && height > 1)
 
1064
        {
 
1065
                gdk_pixbuf_scale (priv->map_pixbuf, priv->map_render_pixbuf, 0, 0,  /* Dest (x, y) */
 
1066
                                  width, height, 0, 0,                              /* Offset (x, y) */
 
1067
                                  zoom, zoom,                                       /* Scale (x, y) */
 
1068
                                  interp);
 
1069
        }
 
1070
        
 
1071
        if (render_overlays)
 
1072
        {
 
1073
                /* Add points */
 
1074
 
 
1075
                for (i = 0; i < priv->points->len; i++)
 
1076
                {
 
1077
                        point = g_ptr_array_index (priv->points, i);
 
1078
                        update_render_point (map, point);
 
1079
                }
 
1080
        }
 
1081
 
 
1082
        /* Compute image offsets with respect to window */
 
1083
 
 
1084
        set_scroll_area (map);
 
1085
}
 
1086
 
 
1087
 
 
1088
/* Queues a repaint of the specified area in window coordinates */
 
1089
 
 
1090
static void
 
1091
request_paint_area (EMap *view, GdkRectangle *area)
 
1092
{
 
1093
        EMapPrivate *priv;
 
1094
        int width, height;
 
1095
 
 
1096
        if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (view)) ||
 
1097
            !GTK_WIDGET_REALIZED (GTK_WIDGET (view))) return;
 
1098
 
 
1099
        priv = view->priv;
 
1100
        if (!priv->map_render_pixbuf) return;
 
1101
 
 
1102
        width = MIN (area->width, E_MAP_GET_WIDTH (view));
 
1103
        height = MIN (area->height, E_MAP_GET_HEIGHT (view));
 
1104
 
 
1105
        /* This satisfies paranoia. To be removed */
 
1106
 
 
1107
        if (priv->xofs + width > gdk_pixbuf_get_width (priv->map_render_pixbuf))
 
1108
                width = gdk_pixbuf_get_width (priv->map_render_pixbuf) - priv->xofs;
 
1109
 
 
1110
        if (priv->yofs + height > gdk_pixbuf_get_height (priv->map_render_pixbuf))
 
1111
                height = gdk_pixbuf_get_height (priv->map_render_pixbuf) - priv->yofs;
 
1112
  
 
1113
        /* We rely on the fast case always being the case, since we load and
 
1114
   * preprocess the source pixbuf ourselves */
 
1115
 
 
1116
        if (gdk_pixbuf_get_colorspace (priv->map_render_pixbuf) == GDK_COLORSPACE_RGB && !gdk_pixbuf_get_has_alpha (priv->map_render_pixbuf) &&
 
1117
            gdk_pixbuf_get_bits_per_sample (priv->map_render_pixbuf) == 8)
 
1118
        {
 
1119
                guchar *pixels;
 
1120
                int rowstride;
 
1121
 
 
1122
                rowstride = gdk_pixbuf_get_rowstride (priv->map_render_pixbuf);
 
1123
                pixels = gdk_pixbuf_get_pixels (priv->map_render_pixbuf) + (area->y + priv->yofs) * rowstride + 3 * (area->x + priv->xofs);
 
1124
                gdk_draw_rgb_image_dithalign (GTK_WIDGET (view)->window, GTK_WIDGET (view)->style->black_gc, area->x, area->y, width, height, GDK_RGB_DITHER_NORMAL, pixels, rowstride, 0, 0);
 
1125
                return;
 
1126
        }
 
1127
 
 
1128
#ifdef DEBUG
 
1129
        g_print ("Doing hard redraw.\n");
 
1130
#endif
 
1131
}
 
1132
 
 
1133
static void
 
1134
put_pixel_with_clipping (GdkPixbuf *pixbuf, gint x, gint y, guint rgba)
 
1135
{
 
1136
        gint    width, height;
 
1137
        gint    rowstride, n_channels;
 
1138
        guchar *pixels, *pixel;
 
1139
 
 
1140
        width      = gdk_pixbuf_get_width      (pixbuf);
 
1141
        height     = gdk_pixbuf_get_height     (pixbuf);
 
1142
        rowstride  = gdk_pixbuf_get_rowstride  (pixbuf);
 
1143
        n_channels = gdk_pixbuf_get_n_channels (pixbuf);
 
1144
        pixels     = gdk_pixbuf_get_pixels     (pixbuf);
 
1145
 
 
1146
        if (x < 0 || x >= width || y < 0 || y >= height)
 
1147
                return;
 
1148
 
 
1149
        pixel = pixels + (y * rowstride) + (x * n_channels);
 
1150
 
 
1151
        *pixel       = (rgba >> 24);
 
1152
        *(pixel + 1) = (rgba >> 16) & 0x000000ff;
 
1153
        *(pixel + 2) = (rgba >>  8) & 0x000000ff;
 
1154
 
 
1155
        if (n_channels > 3)
 
1156
        {
 
1157
                *(pixel + 3) = rgba & 0x000000ff;
 
1158
        }
 
1159
}
 
1160
 
 
1161
 
 
1162
/* Redraw point in client pixbuf */
 
1163
 
 
1164
static void
 
1165
update_render_point (EMap *map, EMapPoint *point)
 
1166
{
 
1167
        EMapPrivate *priv;
 
1168
        GdkPixbuf *pb;
 
1169
        int width, height;
 
1170
        double px, py;
 
1171
 
 
1172
        priv = map->priv;
 
1173
        pb = priv->map_render_pixbuf;
 
1174
        if (!pb) return;
 
1175
 
 
1176
        width  = gdk_pixbuf_get_width (pb);
 
1177
        height = gdk_pixbuf_get_height (pb);
 
1178
 
 
1179
        e_map_world_to_window (map, point->longitude, point->latitude, &px, &py);
 
1180
        px += priv->xofs;
 
1181
        py += priv->yofs;
 
1182
 
 
1183
        put_pixel_with_clipping (pb, px,     py,     point->rgba);
 
1184
        put_pixel_with_clipping (pb, px - 1, py,     point->rgba);
 
1185
        put_pixel_with_clipping (pb, px + 1, py,     point->rgba);
 
1186
        put_pixel_with_clipping (pb, px,     py - 1, point->rgba);
 
1187
        put_pixel_with_clipping (pb, px,     py + 1, point->rgba);
 
1188
 
 
1189
        put_pixel_with_clipping (pb, px - 2, py,     0x000000ff);
 
1190
        put_pixel_with_clipping (pb, px + 2, py,     0x000000ff);
 
1191
        put_pixel_with_clipping (pb, px,     py - 2, 0x000000ff);
 
1192
        put_pixel_with_clipping (pb, px,     py + 2, 0x000000ff);
 
1193
        put_pixel_with_clipping (pb, px - 1, py - 1, 0x000000ff);
 
1194
        put_pixel_with_clipping (pb, px - 1, py + 1, 0x000000ff);
 
1195
        put_pixel_with_clipping (pb, px + 1, py - 1, 0x000000ff);
 
1196
        put_pixel_with_clipping (pb, px + 1, py + 1, 0x000000ff);
 
1197
}
 
1198
 
 
1199
 
 
1200
/* Repaint point on X server */
 
1201
 
 
1202
static void
 
1203
repaint_point (EMap *map, EMapPoint *point)
 
1204
{
 
1205
        EMapPrivate *priv;
 
1206
        GdkRectangle area;
 
1207
        double px, py;
 
1208
 
 
1209
        if (!e_map_point_is_in_view (map, point)) return; 
 
1210
        priv = map->priv;
 
1211
 
 
1212
        e_map_world_to_window (map, point->longitude, point->latitude, &px, &py);
 
1213
 
 
1214
        area.x = (int) px - 2;
 
1215
        area.y = (int) py - 2;
 
1216
        area.width = 5;
 
1217
        area.height = 5;
 
1218
        request_paint_area (map, &area);
 
1219
}
 
1220
 
 
1221
 
 
1222
static void
 
1223
center_at (EMap *map, int x, int y, gboolean scroll)
 
1224
{
 
1225
        EMapPrivate *priv;
 
1226
        int pb_width, pb_height,
 
1227
            view_width, view_height;
 
1228
 
 
1229
        priv = map->priv;
 
1230
 
 
1231
        pb_width = E_MAP_GET_WIDTH (map);
 
1232
        pb_height = E_MAP_GET_HEIGHT (map);
 
1233
 
 
1234
        view_width = GTK_WIDGET (map)->allocation.width;
 
1235
        view_height = GTK_WIDGET (map)->allocation.height;
 
1236
 
 
1237
        x = CLAMP (x - (view_width / 2), 0, pb_width - view_width);
 
1238
        y = CLAMP (y - (view_height / 2), 0, pb_height - view_height);
 
1239
 
 
1240
        if (scroll) scroll_to (map, x, y);
 
1241
        else
 
1242
        {
 
1243
                priv->xofs = x;
 
1244
                priv->yofs = y;
 
1245
        }
 
1246
}
 
1247
 
 
1248
 
 
1249
static void
 
1250
smooth_center_at (EMap *map, int x, int y)
 
1251
{
 
1252
        EMapPrivate *priv;
 
1253
        int pb_width, pb_height,
 
1254
            view_width, view_height;
 
1255
        int dx, dy;
 
1256
 
 
1257
        priv = map->priv;
 
1258
 
 
1259
        pb_width = E_MAP_GET_WIDTH (map);
 
1260
        pb_height = E_MAP_GET_HEIGHT (map);
 
1261
 
 
1262
        view_width = GTK_WIDGET (map)->allocation.width;
 
1263
        view_height = GTK_WIDGET (map)->allocation.height;
 
1264
 
 
1265
        x = CLAMP (x - (view_width / 2), 0, pb_width - view_width);
 
1266
        y = CLAMP (y - (view_height / 2), 0, pb_height - view_height);
 
1267
 
 
1268
        for (;;)
 
1269
        {
 
1270
                if (priv->xofs == x && priv->yofs == y) break;
 
1271
 
 
1272
                dx = (x < priv->xofs) ? -1 : (x > priv->xofs) ? 1 : 0;
 
1273
                dy = (y < priv->yofs) ? -1 : (y > priv->yofs) ? 1 : 0;
 
1274
    
 
1275
                scroll_to (map, priv->xofs + dx, priv->yofs + dy);
 
1276
        }
 
1277
}
 
1278
 
 
1279
 
 
1280
/* Scrolls the view to the specified offsets.  Does not perform range checking!  */
 
1281
 
 
1282
static void
 
1283
scroll_to (EMap *view, int x, int y)
 
1284
{
 
1285
        EMapPrivate *priv;
 
1286
        int xofs, yofs;
 
1287
        GdkWindow *window;
 
1288
        GdkGC *gc;
 
1289
        int width, height;
 
1290
        int src_x, src_y;
 
1291
        int dest_x, dest_y;
 
1292
        GdkEvent *event;
 
1293
 
 
1294
        priv = view->priv;
 
1295
 
 
1296
        /* Compute offsets and check bounds */
 
1297
 
 
1298
        xofs = x - priv->xofs;
 
1299
        yofs = y - priv->yofs;
 
1300
 
 
1301
        if (xofs == 0 && yofs == 0) return;
 
1302
 
 
1303
        priv->xofs = x;
 
1304
        priv->yofs = y;
 
1305
 
 
1306
        if (!GTK_WIDGET_DRAWABLE (view)) return;
 
1307
 
 
1308
        width = GTK_WIDGET (view)->allocation.width;
 
1309
        height = GTK_WIDGET (view)->allocation.height;
 
1310
 
 
1311
        if (abs (xofs) >= width || abs (yofs) >= height)
 
1312
        {
 
1313
                GdkRectangle area;
 
1314
 
 
1315
                area.x = 0;
 
1316
                area.y = 0;
 
1317
                area.width = width;
 
1318
                area.height = height;
 
1319
 
 
1320
                request_paint_area (view, &area);
 
1321
                return;
 
1322
        }
 
1323
 
 
1324
        window = GTK_WIDGET (view)->window;
 
1325
 
 
1326
        /* Copy the window area */
 
1327
 
 
1328
        src_x = xofs < 0 ? 0 : xofs;
 
1329
        src_y = yofs < 0 ? 0 : yofs;
 
1330
        dest_x = xofs < 0 ? -xofs : 0;
 
1331
        dest_y = yofs < 0 ? -yofs : 0;
 
1332
 
 
1333
        gc = gdk_gc_new (window);
 
1334
        gdk_gc_set_exposures (gc, TRUE);
 
1335
 
 
1336
        gdk_draw_drawable (window, gc, window, src_x, src_y, dest_x, dest_y, width - abs (xofs), height - abs (yofs));
 
1337
 
 
1338
        gdk_gc_unref (gc);
 
1339
 
 
1340
        /* Add the scrolled-in region */
 
1341
 
 
1342
        if (xofs)
 
1343
        {
 
1344
                GdkRectangle r;
 
1345
 
 
1346
                r.x = xofs < 0 ? 0 : width - xofs;
 
1347
                r.y = 0;
 
1348
                r.width = abs (xofs);
 
1349
                r.height = height;
 
1350
 
 
1351
                request_paint_area (view, &r);
 
1352
        }
 
1353
 
 
1354
        if (yofs)
 
1355
        {
 
1356
                GdkRectangle r;
 
1357
 
 
1358
                r.x = 0;
 
1359
                r.y = yofs < 0 ? 0 : height - yofs;
 
1360
                r.width = width;
 
1361
                r.height = abs (yofs);
 
1362
 
 
1363
                request_paint_area (view, &r);
 
1364
        }
 
1365
 
 
1366
        /* Process graphics exposures */
 
1367
 
 
1368
        while ((event = gdk_event_get_graphics_expose (window)) != NULL)
 
1369
        {
 
1370
                gtk_widget_event (GTK_WIDGET (view), event);
 
1371
 
 
1372
                if (event->expose.count == 0)
 
1373
                {
 
1374
                        gdk_event_free (event);
 
1375
                        break;
 
1376
                }
 
1377
 
 
1378
                gdk_event_free (event);
 
1379
        }
 
1380
}
 
1381
 
 
1382
 
 
1383
static int divide_seq[] =
 
1384
{
 
1385
        /* Dividends for divisor of 2 */
 
1386
 
 
1387
        -2,
 
1388
 
 
1389
        1,
 
1390
 
 
1391
        /* Dividends for divisor of 4 */
 
1392
 
 
1393
        -4,
 
1394
 
 
1395
        1, 3,
 
1396
 
 
1397
        /* Dividends for divisor of 8 */
 
1398
 
 
1399
        -8,
 
1400
 
 
1401
        1, 5, 3, 7,
 
1402
 
 
1403
        /* Dividends for divisor of 16 */
 
1404
 
 
1405
        -16,
 
1406
 
 
1407
        1, 9, 5, 13, 3, 11, 7, 15,
 
1408
 
 
1409
        /* Dividends for divisor of 32 */
 
1410
 
 
1411
        -32,
 
1412
 
 
1413
        1, 17, 9, 25, 5, 21, 13, 29, 3, 19,
 
1414
        11, 27, 7, 23, 15, 31,
 
1415
 
 
1416
        /* Dividends for divisor of 64 */
 
1417
 
 
1418
        -64,
 
1419
 
 
1420
        1, 33, 17, 49, 9, 41, 25, 57, 5, 37,
 
1421
        21, 53, 13, 45, 29, 61, 3, 35, 19, 51,
 
1422
        11, 43, 27, 59, 7, 39, 23, 55, 15, 47,
 
1423
        31, 63,
 
1424
 
 
1425
        /* Dividends for divisor of 128 */
 
1426
 
 
1427
        -128,
 
1428
 
 
1429
        1, 65, 33, 97, 17, 81, 49, 113, 9, 73,
 
1430
        41, 105, 25, 89, 57, 121, 5, 69, 37, 101,
 
1431
        21, 85, 53, 117, 13, 77, 45, 109, 29, 93,
 
1432
        61, 125, 3, 67, 35, 99, 19, 83, 51, 115,
 
1433
        11, 75, 43, 107, 27, 91, 59, 123, 7, 71,
 
1434
        39, 103, 23, 87, 55, 119, 15, 79, 47, 111,
 
1435
        31, 95, 63, 127,
 
1436
 
 
1437
        /* Dividends for divisor of 256 */
 
1438
 
 
1439
        -256,
 
1440
 
 
1441
        1, 129, 65, 193, 33, 161, 97, 225, 17, 145,
 
1442
        81, 209, 49, 177, 113, 241, 9, 137, 73, 201,
 
1443
        41, 169, 105, 233, 25, 153, 89, 217, 57, 185,
 
1444
        121, 249, 5, 133, 69, 197, 37, 165, 101, 229,
 
1445
        21, 149, 85, 213, 53, 181, 117, 245, 13, 141,
 
1446
        77, 205, 45, 173, 109, 237, 29, 157, 93, 221,
 
1447
        61, 189, 125, 253, 3, 131, 67, 195, 35, 163,
 
1448
        99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
 
1449
        11, 139, 75, 203, 43, 171, 107, 235, 27, 155,
 
1450
        91, 219, 59, 187, 123, 251, 7, 135, 71, 199,
 
1451
        39, 167, 103, 231, 23, 151, 87, 215, 55, 183,
 
1452
        119, 247, 15, 143, 79, 207, 47, 175, 111, 239,
 
1453
        31, 159, 95, 223, 63, 191, 127, 255,
 
1454
 
 
1455
        0
 
1456
};
 
1457
 
 
1458
 
 
1459
typedef enum
 
1460
{
 
1461
        AXIS_X,
 
1462
        AXIS_Y
 
1463
}
 
1464
AxisType;
 
1465
 
 
1466
 
 
1467
static void
 
1468
blowup_window_area (GdkWindow *window, gint area_x, gint area_y, gint target_x, gint target_y, gint total_width, gint total_height, gfloat zoom_factor)
 
1469
{
 
1470
        GdkGC *gc;
 
1471
        AxisType strong_axis;
 
1472
        gfloat axis_factor, axis_counter;
 
1473
        gint zoom_chunk;
 
1474
        gint divisor_width = 0, divisor_height = 0;
 
1475
        gint divide_width_index, divide_height_index;
 
1476
        gint area_width, area_height;
 
1477
        gint i, j;
 
1478
        int line;
 
1479
 
 
1480
 
 
1481
        /* Set up the GC we'll be using */
 
1482
 
 
1483
        gc = gdk_gc_new (window);
 
1484
        gdk_gc_set_exposures (gc, FALSE);
 
1485
 
 
1486
        /* Get area constraints */
 
1487
 
 
1488
        gdk_drawable_get_size (window, &area_width, &area_height);
 
1489
 
 
1490
        /* Initialize area division array indexes */
 
1491
 
 
1492
        divide_width_index = divide_height_index = 0;
 
1493
 
 
1494
        /* Initialize axis counter */
 
1495
 
 
1496
        axis_counter = 0.0;
 
1497
 
 
1498
        /* Find the strong axis (which is the basis for iteration) and the ratio
 
1499
         * at which the other axis will be scaled.
 
1500
         *
 
1501
         * Also determine how many lines to expand in one fell swoop, and store
 
1502
         * this figure in zoom_chunk. */
 
1503
 
 
1504
        if (area_width > area_height)
 
1505
        {
 
1506
                strong_axis = AXIS_X;
 
1507
                axis_factor = (double) area_height / (double) area_width;
 
1508
                zoom_chunk = MAX (1, area_width / 250);
 
1509
                i = (area_width * (zoom_factor - 1.0)) / zoom_chunk;
 
1510
        }
 
1511
        else
 
1512
        {
 
1513
                strong_axis = AXIS_Y;
 
1514
                axis_factor = (double) area_width / (double) area_height;
 
1515
                zoom_chunk = MAX (1, area_height / 250);
 
1516
                i = (area_height * (zoom_factor - 1.0)) / zoom_chunk;
 
1517
        }
 
1518
 
 
1519
        /* Go, go, devil bunnies! Gogo devil bunnies! */
 
1520
 
 
1521
        for (; i > 0; i--)
 
1522
        {
 
1523
                /* Reset division sequence table indexes as necessary */
 
1524
 
 
1525
                if (!divide_seq[divide_width_index]) divide_width_index = 0;
 
1526
                if (!divide_seq[divide_height_index]) divide_height_index = 0;
 
1527
 
 
1528
                /* Set new divisor if found in table */
 
1529
 
 
1530
                if (divide_seq[divide_width_index] < 0)
 
1531
                        divisor_width = abs (divide_seq[divide_width_index++]);
 
1532
                if (divide_seq[divide_height_index] < 0)
 
1533
                        divisor_height = abs (divide_seq[divide_height_index++]);
 
1534
 
 
1535
                /* Widen */
 
1536
 
 
1537
                if (strong_axis == AXIS_X || axis_counter >= 1.0)
 
1538
                {
 
1539
                        line = ((divide_seq[divide_width_index] * area_width) / divisor_width) + 0.5;
 
1540
 
 
1541
                        if ((line < target_x && target_x > area_width / 2) || (line > target_x && target_x > (area_width / 2) + zoom_chunk))
 
1542
                        {
 
1543
                                /* Push left */
 
1544
 
 
1545
                                for (j = 0; j < zoom_chunk - 1; j++)
 
1546
                                        gdk_draw_drawable (window, gc, window, line, 0, line + j +1, 0, 1, area_height);
 
1547
 
 
1548
                                gdk_draw_drawable (window, gc, window, zoom_chunk, 0, 0, 0, line, area_height);
 
1549
                                if (line > target_x) target_x -= zoom_chunk;
 
1550
                        }
 
1551
                        else
 
1552
                        {
 
1553
                                /* Push right */
 
1554
 
 
1555
                                for (j = 0; j < zoom_chunk - 1; j++)
 
1556
                                        gdk_draw_drawable (window, gc, window, line - zoom_chunk, 0, line + j - (zoom_chunk - 1), 0, 1, area_height);
 
1557
 
 
1558
                                gdk_draw_drawable (window, gc, window, line - zoom_chunk, 0, line, 0, area_width - line, area_height);
 
1559
                                if (line < target_x) target_x += zoom_chunk;
 
1560
                        }
 
1561
                }
 
1562
 
 
1563
                if (strong_axis == AXIS_Y || axis_counter >= 1.0)
 
1564
                {
 
1565
                        /* Heighten */
 
1566
 
 
1567
                        line = ((divide_seq[divide_height_index] * area_height) / divisor_height) + 0.5;
 
1568
 
 
1569
                        if ((line < target_y && target_y > area_height / 2) || (line > target_y && target_y > (area_height / 2) + zoom_chunk))
 
1570
                        {
 
1571
                                /* Push up */
 
1572
 
 
1573
                                for (j = 0; j < zoom_chunk - 1; j++)
 
1574
                                        gdk_draw_drawable (window, gc, window, 0, line, 0, line + j + 1, area_width, 1);
 
1575
 
 
1576
                                gdk_draw_drawable (window, gc, window, 0, zoom_chunk, 0, 0, area_width, line);
 
1577
                                if (line > target_y) target_y -= zoom_chunk;
 
1578
                        }
 
1579
                        else
 
1580
                        {
 
1581
                                /* Push down */
 
1582
 
 
1583
                                for (j = 0; j < zoom_chunk - 1; j++)
 
1584
                                        gdk_draw_drawable (window, gc, window, 0, line - zoom_chunk, 0, line + j - (zoom_chunk - 1), area_width, 1);
 
1585
 
 
1586
                                gdk_draw_drawable (window, gc, window, 0, line - zoom_chunk, 0, line, area_width, area_height - line);
 
1587
                                if (line < target_y) target_y += zoom_chunk;
 
1588
                        }
 
1589
                }
 
1590
 
 
1591
                divide_width_index++;
 
1592
                divide_height_index++;
 
1593
                if (axis_counter >= 1.0) axis_counter -= 1.0;
 
1594
                axis_counter += axis_factor;
 
1595
        }
 
1596
 
 
1597
        /* Free our GC */
 
1598
 
 
1599
        gdk_gc_unref (gc);
 
1600
}
 
1601
 
 
1602
 
 
1603
static void
 
1604
zoom_in_smooth (EMap *map)
 
1605
{
 
1606
        GdkRectangle area;
 
1607
        EMapPrivate *priv;
 
1608
        GdkWindow *window;
 
1609
        int width, height;
 
1610
        int win_width, win_height;
 
1611
        int target_width, target_height;
 
1612
        double x, y;
 
1613
 
 
1614
        g_return_if_fail (map);
 
1615
        g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (map)));
 
1616
 
 
1617
        area.x = 0;
 
1618
        area.y = 0;
 
1619
        area.width = GTK_WIDGET (map)->allocation.width;
 
1620
        area.height = GTK_WIDGET (map)->allocation.height;
 
1621
 
 
1622
        priv = map->priv;
 
1623
        window = GTK_WIDGET (map)->window;
 
1624
        width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
 
1625
        height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
 
1626
        win_width = GTK_WIDGET (map)->allocation.width;
 
1627
        win_height = GTK_WIDGET (map)->allocation.height;
 
1628
        target_width = win_width / 4;
 
1629
        target_height = win_height / 4;
 
1630
 
 
1631
        /* Center the target point as much as possible */
 
1632
  
 
1633
        e_map_world_to_window (map, priv->zoom_target_long, priv->zoom_target_lat, &x, &y);
 
1634
        smooth_center_at (map, x + priv->xofs, y + priv->yofs);
 
1635
 
 
1636
        /* Render and paint a temporary map without overlays, so they don't get in
 
1637
         * the way (look ugly) while zooming */
 
1638
  
 
1639
        update_render_pixbuf (map, GDK_INTERP_BILINEAR, FALSE);
 
1640
        request_paint_area (map, &area);
 
1641
  
 
1642
        /* Find out where in the area we're going to zoom to */
 
1643
 
 
1644
        e_map_world_to_window (map, priv->zoom_target_long, priv->zoom_target_lat, &x, &y);
 
1645
  
 
1646
        /* Pre-render the zoomed-in map, so we can put it there quickly when the
 
1647
         * blowup sequence ends */
 
1648
  
 
1649
        priv->zoom_state = E_MAP_ZOOMED_IN;
 
1650
        update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
 
1651
  
 
1652
        /* Do the blowup */
 
1653
  
 
1654
        blowup_window_area (window, priv->xofs, priv->yofs, x, y, width, height, 1.68);
 
1655
 
 
1656
        /* Set new scroll offsets and paint the zoomed map */
 
1657
  
 
1658
        e_map_world_to_window (map, priv->zoom_target_long, priv->zoom_target_lat, &x, &y);
 
1659
        priv->xofs = CLAMP (priv->xofs + x - area.width / 2.0, 0, E_MAP_GET_WIDTH (map) - area.width);
 
1660
        priv->yofs = CLAMP (priv->yofs + y - area.height / 2.0, 0, E_MAP_GET_HEIGHT (map) - area.height);
 
1661
 
 
1662
        request_paint_area (map, &area);
 
1663
}
 
1664
 
 
1665
 
 
1666
static void
 
1667
zoom_in (EMap *map)
 
1668
{
 
1669
        GdkRectangle area;
 
1670
        EMapPrivate *priv;
 
1671
        double x, y;
 
1672
 
 
1673
        priv = map->priv;
 
1674
 
 
1675
        area.x = 0;
 
1676
        area.y = 0;
 
1677
        area.width = GTK_WIDGET (map)->allocation.width;
 
1678
        area.height = GTK_WIDGET (map)->allocation.height;
 
1679
 
 
1680
        priv->zoom_state = E_MAP_ZOOMED_IN;
 
1681
 
 
1682
        update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
 
1683
 
 
1684
        e_map_world_to_window (map, priv->zoom_target_long, priv->zoom_target_lat, &x, &y);
 
1685
        priv->xofs = CLAMP (priv->xofs + x - area.width / 2.0, 0, E_MAP_GET_WIDTH (map) - area.width);
 
1686
        priv->yofs = CLAMP (priv->yofs + y - area.height / 2.0, 0, E_MAP_GET_HEIGHT (map) - area.height);
 
1687
 
 
1688
        request_paint_area (map, &area);
 
1689
}
 
1690
 
 
1691
 
 
1692
static void
 
1693
zoom_out (EMap *map)
 
1694
{
 
1695
        GdkRectangle area;
 
1696
        EMapPrivate *priv;
 
1697
        double longitude, latitude;
 
1698
        double x, y;
 
1699
 
 
1700
        priv = map->priv;
 
1701
 
 
1702
        area.x = 0;
 
1703
        area.y = 0;
 
1704
        area.width = GTK_WIDGET (map)->allocation.width;
 
1705
        area.height = GTK_WIDGET (map)->allocation.height;
 
1706
 
 
1707
        /* Must be done before update_render_pixbuf() */
 
1708
 
 
1709
        e_map_window_to_world (map, area.width / 2, area.height / 2,
 
1710
                               &longitude, &latitude);
 
1711
 
 
1712
        priv->zoom_state = E_MAP_ZOOMED_OUT;
 
1713
        update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
 
1714
 
 
1715
        e_map_world_to_window (map, longitude, latitude, &x, &y);
 
1716
        center_at (map, x + priv->xofs, y + priv->yofs, FALSE);
 
1717
/*      request_paint_area (map, &area); */
 
1718
        repaint_visible (map);
 
1719
}
 
1720
 
 
1721
 
 
1722
static void
 
1723
zoom_do (EMap *map)
 
1724
{
 
1725
        EMapPrivate *priv;
 
1726
 
 
1727
        priv = map->priv;
 
1728
 
 
1729
        g_signal_handler_block (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
1730
        g_signal_handler_block (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
1731
 
 
1732
        if (priv->zoom_state == E_MAP_ZOOMING_IN)
 
1733
        {
 
1734
                if (e_map_get_smooth_zoom (map)) zoom_in_smooth (map);
 
1735
                else zoom_in (map);
 
1736
        }
 
1737
        else if (priv->zoom_state == E_MAP_ZOOMING_OUT)
 
1738
        {
 
1739
                /* if (e_map_get_smooth_zoom(map)) zoom_out_smooth(map); */
 
1740
                zoom_out (map);
 
1741
        }
 
1742
 
 
1743
        g_signal_handler_unblock (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
1744
        g_signal_handler_unblock (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
1745
 
 
1746
        set_scroll_area(map);
 
1747
}
 
1748
 
 
1749
 
 
1750
/* Callback used when an adjustment is changed */
 
1751
 
 
1752
static void
 
1753
adjustment_changed_cb (GtkAdjustment *adj, gpointer data)
 
1754
{
 
1755
        EMap *view;
 
1756
        EMapPrivate *priv;
 
1757
 
 
1758
        view = E_MAP (data);
 
1759
        priv = view->priv;
 
1760
 
 
1761
        scroll_to (view, priv->hadj->value, priv->vadj->value);
 
1762
}
 
1763
 
 
1764
 
 
1765
static void
 
1766
set_scroll_area (EMap *view)
 
1767
{
 
1768
        EMapPrivate *priv;
 
1769
 
 
1770
        priv = view->priv;
 
1771
 
 
1772
        if (!GTK_WIDGET_REALIZED (GTK_WIDGET (view))) return;
 
1773
        if (!priv->hadj || !priv->vadj) return;
 
1774
 
 
1775
        /* Set scroll increments */
 
1776
 
 
1777
        priv->hadj->page_size = GTK_WIDGET (view)->allocation.width;
 
1778
        priv->hadj->page_increment = GTK_WIDGET (view)->allocation.width / 2;
 
1779
        priv->hadj->step_increment = SCROLL_STEP_SIZE;
 
1780
 
 
1781
        priv->vadj->page_size = GTK_WIDGET (view)->allocation.height;
 
1782
        priv->vadj->page_increment = GTK_WIDGET (view)->allocation.height / 2;
 
1783
        priv->vadj->step_increment = SCROLL_STEP_SIZE;
 
1784
 
 
1785
        /* Set scroll bounds and new offsets */
 
1786
 
 
1787
        priv->hadj->lower = 0;
 
1788
        if (priv->map_render_pixbuf)
 
1789
                priv->hadj->upper = gdk_pixbuf_get_width (priv->map_render_pixbuf);
 
1790
 
 
1791
        priv->vadj->lower = 0;
 
1792
        if (priv->map_render_pixbuf)
 
1793
                priv->vadj->upper = gdk_pixbuf_get_height (priv->map_render_pixbuf);
 
1794
 
 
1795
        gtk_signal_emit_by_name (GTK_OBJECT (priv->hadj), "changed");
 
1796
        gtk_signal_emit_by_name (GTK_OBJECT (priv->vadj), "changed");
 
1797
 
 
1798
        priv->xofs = CLAMP (priv->xofs, 0, priv->hadj->upper - priv->hadj->page_size);
 
1799
        priv->yofs = CLAMP (priv->yofs, 0, priv->vadj->upper - priv->vadj->page_size);
 
1800
 
 
1801
        if (priv->hadj->value != priv->xofs)
 
1802
        {
 
1803
                priv->hadj->value = priv->xofs;
 
1804
 
 
1805
                g_signal_handler_block (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
1806
                g_signal_emit_by_name (GTK_OBJECT (priv->hadj), "value_changed");
 
1807
                g_signal_handler_unblock (G_OBJECT (priv->hadj), priv->hadj_signal_id);
 
1808
        }
 
1809
 
 
1810
        if (priv->vadj->value != priv->yofs)
 
1811
        {
 
1812
                priv->vadj->value = priv->yofs;
 
1813
 
 
1814
                g_signal_handler_block (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
1815
                g_signal_emit_by_name (GTK_OBJECT (priv->vadj), "value_changed");
 
1816
                g_signal_handler_unblock (G_OBJECT (priv->vadj), priv->vadj_signal_id);
 
1817
        }
 
1818
}