]> git.street.me.uk Git - andy/viking.git/blob - src/vikgeoreflayer.c
SF#356778: Download Map Tiles using F5
[andy/viking.git] / src / vikgeoreflayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "viking.h"
27 #include <glib.h>
28 #include <glib/gstdio.h>
29 #include <glib/gi18n.h>
30 #include <string.h>
31 #include <math.h>
32 #include <stdlib.h>
33
34 #include "icons/icons.h"
35
36 VikLayerParam georef_layer_params[] = {
37   { "image", VIK_LAYER_PARAM_STRING, VIK_LAYER_NOT_IN_PROPERTIES },
38   { "corner_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES },
39   { "corner_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES },
40   { "mpp_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES },
41   { "mpp_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES },
42 };
43
44 enum { PARAM_IMAGE = 0, PARAM_CE, PARAM_CN, PARAM_ME, PARAM_MN, NUM_PARAMS };
45
46 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
47 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
48 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
49 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
50 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
51 VikGeorefLayer *georef_layer_new ( );
52 VikGeorefLayer *georef_layer_create ( VikViewport *vp );
53 static void georef_layer_free ( VikGeorefLayer *vgl );
54 gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
55 static void georef_layer_draw ( VikGeorefLayer *vgl, gpointer data );
56 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
57 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
58 static gboolean georef_layer_dialog ( VikGeorefLayer **vgl, gpointer vp, GtkWindow *w );
59 static void georef_layer_load_image ( VikGeorefLayer *vgl );
60
61 /* tools */
62 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
63 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
64 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
65 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
66 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
67
68 // See comment in viktrwlayer.c for advice on values used
69 static VikToolInterface georef_tools[] = {
70   { { "GeorefMoveMap", "vik-icon-Georef Move Map",  N_("_Georef Move Map"), NULL,  N_("Georef Move Map"), 0 },
71     (VikToolConstructorFunc) georef_layer_move_create, NULL, NULL, NULL,
72     (VikToolMouseFunc) georef_layer_move_press, NULL, (VikToolMouseFunc) georef_layer_move_release,
73     (VikToolKeyFunc) NULL,
74     FALSE,
75     GDK_CURSOR_IS_PIXMAP, &cursor_geomove_pixbuf },
76
77   { { "GeorefZoomTool", "vik-icon-Georef Zoom Tool",  N_("Georef Z_oom Tool"), NULL,  N_("Georef Zoom Tool"), 0 },
78     (VikToolConstructorFunc) georef_layer_zoom_create, NULL, NULL, NULL,
79     (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
80     (VikToolKeyFunc) NULL,
81     FALSE,
82     GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf },
83 };
84
85 VikLayerInterface vik_georef_layer_interface = {
86   N_("GeoRef Map"),
87   NULL,
88   &vikgeoreflayer_pixbuf, /*icon */
89
90   georef_tools,
91   sizeof(georef_tools) / sizeof(VikToolInterface),
92
93   georef_layer_params,
94   NUM_PARAMS,
95   NULL,
96   0,
97
98   VIK_MENU_ITEM_ALL,
99
100   (VikLayerFuncCreate)                  georef_layer_create,
101   (VikLayerFuncRealize)                 NULL,
102   (VikLayerFuncPostRead)                georef_layer_load_image,
103   (VikLayerFuncFree)                    georef_layer_free,
104
105   (VikLayerFuncProperties)              georef_layer_properties,
106   (VikLayerFuncDraw)                    georef_layer_draw,
107   (VikLayerFuncChangeCoordMode)         NULL,
108
109   (VikLayerFuncSetMenuItemsSelection)   NULL,
110   (VikLayerFuncGetMenuItemsSelection)   NULL,
111
112   (VikLayerFuncAddMenuItems)            georef_layer_add_menu_items,
113   (VikLayerFuncSublayerAddMenuItems)    NULL,
114
115   (VikLayerFuncSublayerRenameRequest)   NULL,
116   (VikLayerFuncSublayerToggleVisible)   NULL,
117   (VikLayerFuncSublayerTooltip)         NULL,
118   (VikLayerFuncLayerTooltip)            georef_layer_tooltip,
119   (VikLayerFuncLayerSelected)           NULL,
120
121   (VikLayerFuncMarshall)                georef_layer_marshall,
122   (VikLayerFuncUnmarshall)              georef_layer_unmarshall,
123
124   (VikLayerFuncSetParam)                georef_layer_set_param,
125   (VikLayerFuncGetParam)                georef_layer_get_param,
126
127   (VikLayerFuncReadFileData)            NULL,
128   (VikLayerFuncWriteFileData)           NULL,
129
130   (VikLayerFuncDeleteItem)              NULL,
131   (VikLayerFuncCutItem)                 NULL,
132   (VikLayerFuncCopyItem)                NULL,
133   (VikLayerFuncPasteItem)               NULL,
134   (VikLayerFuncFreeCopiedItem)          NULL,
135   (VikLayerFuncDragDropRequest)         NULL,
136
137   (VikLayerFuncSelectClick)             NULL,
138   (VikLayerFuncSelectMove)              NULL,
139   (VikLayerFuncSelectRelease)           NULL,
140   (VikLayerFuncSelectedViewportMenu)    NULL,
141 };
142
143 struct _VikGeorefLayer {
144   VikLayer vl;
145   gchar *image;
146   GdkPixbuf *pixbuf;
147   struct UTM corner;
148   gdouble mpp_easting, mpp_northing;
149   guint width, height;
150
151   GdkPixbuf *scaled;
152   guint32 scaled_width, scaled_height;
153
154   gint click_x, click_y;
155 };
156
157
158
159 GType vik_georef_layer_get_type ()
160 {
161   static GType vgl_type = 0;
162
163   if (!vgl_type)
164   {
165     static const GTypeInfo vgl_info =
166     {
167       sizeof (VikGeorefLayerClass),
168       NULL, /* base_init */
169       NULL, /* base_finalize */
170       NULL, /* class init */
171       NULL, /* class_finalize */
172       NULL, /* class_data */
173       sizeof (VikGeorefLayer),
174       0,
175       NULL /* instance init */
176     };
177     vgl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGeorefLayer", &vgl_info, 0 );
178   }
179
180   return vgl_type;
181 }
182
183 static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
184 {
185   return vgl->image;
186 }
187
188 static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
189 {
190   vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
191 }
192
193 static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
194 {
195   VikGeorefLayer *rv = georef_layer_new ();
196   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
197   if (rv->image) {
198     georef_layer_load_image ( rv );
199   }
200   return rv;
201 }
202
203 static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
204 {
205   switch ( id )
206   {
207     case PARAM_IMAGE: georef_layer_set_image ( vgl, data.s ); break;
208     case PARAM_CN: vgl->corner.northing = data.d; break;
209     case PARAM_CE: vgl->corner.easting = data.d; break;
210     case PARAM_MN: vgl->mpp_northing = data.d; break;
211     case PARAM_ME:  vgl->mpp_easting = data.d; break;
212   }
213   return TRUE;
214 }
215
216 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
217 {
218   VikLayerParamData rv;
219   switch ( id )
220   {
221     case PARAM_IMAGE: rv.s = vgl->image ? vgl->image : ""; break;
222     case PARAM_CN: rv.d = vgl->corner.northing; break;
223     case PARAM_CE: rv.d = vgl->corner.easting; break;
224     case PARAM_MN: rv.d = vgl->mpp_northing; break;
225     case PARAM_ME: rv.d = vgl->mpp_easting; break;
226   }
227   return rv;
228 }
229
230 VikGeorefLayer *georef_layer_new ( )
231 {
232   VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
233   vik_layer_init ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
234
235   vgl->image = NULL;
236   vgl->pixbuf = NULL;
237   vgl->click_x = -1;
238   vgl->click_y = -1;
239   vgl->scaled = NULL;
240   vgl->scaled_width = 0;
241   vgl->scaled_height = 0;
242   return vgl;
243 }
244
245 static void georef_layer_draw ( VikGeorefLayer *vgl, gpointer data )
246 {
247 /* bla, bla */
248   if ( vgl->pixbuf )
249   {
250     VikViewport *vp = VIK_VIEWPORT(data);
251     struct UTM utm_middle;
252     gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
253     GdkPixbuf *pixbuf = vgl->pixbuf;
254     guint layer_width = vgl->width;
255     guint layer_height = vgl->height;
256
257     vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm_middle );
258
259     /* scale the pixbuf if it doesn't match our dimensions */
260     if ( xmpp != vgl->mpp_easting || ympp != vgl->mpp_northing )
261     {
262       layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
263       layer_height = round(vgl->height * vgl->mpp_northing / ympp);
264
265       /* rescale if necessary */
266       if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
267         pixbuf = vgl->scaled;
268       else
269       {
270         pixbuf = gdk_pixbuf_scale_simple(
271           vgl->pixbuf, 
272           layer_width,
273           layer_height,
274           GDK_INTERP_BILINEAR
275         );
276
277         if (vgl->scaled != NULL)
278           g_object_unref(vgl->scaled);
279
280         vgl->scaled = pixbuf;
281         vgl->scaled_width = layer_width;
282         vgl->scaled_height = layer_height;
283       }
284     }
285
286     guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
287     gint32 x, y;
288     vgl->corner.zone = utm_middle.zone;
289     vgl->corner.letter = utm_middle.letter;
290     VikCoord corner_coord;
291     vik_coord_load_from_utm ( &corner_coord, vik_viewport_get_coord_mode(vp), &(vgl->corner) );
292     vik_viewport_coord_to_screen ( vp, &corner_coord, &x, &y );
293     if ( (x < 0 || x < width) && (y < 0 || y < height) && x+layer_width > 0 && y+layer_height > 0 )
294       vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
295   }
296 }
297
298 static void georef_layer_free ( VikGeorefLayer *vgl )
299 {
300   if ( vgl->image != NULL )
301     g_free ( vgl->image );
302   if ( vgl->scaled != NULL )
303     g_object_unref ( vgl->scaled );
304 }
305
306 VikGeorefLayer *georef_layer_create ( VikViewport *vp )
307 {
308   return georef_layer_new ();
309 }
310
311 gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
312 {
313   return georef_layer_dialog ( &vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
314 }
315
316 static void georef_layer_load_image ( VikGeorefLayer *vgl )
317 {
318   GError *gx = NULL;
319   if ( vgl->image == NULL )
320     return;
321
322   if ( vgl->pixbuf )
323     g_object_unref ( G_OBJECT(vgl->pixbuf) );
324   if ( vgl->scaled )
325   {
326     g_object_unref ( G_OBJECT(vgl->scaled) );
327     vgl->scaled = NULL;
328   }
329
330   vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
331
332   if (gx)
333   {
334     g_warning ( _("Couldn't open image file: %s"), gx->message );
335     g_error_free ( gx );
336   }
337   else
338   {
339     vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
340     vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
341   }
342
343   /* should find length and width here too */
344 }
345
346 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
347 {
348   if ( vgl->image )
349     g_free ( vgl->image );
350   if ( vgl->scaled )
351   {
352     g_object_unref ( vgl->scaled );
353     vgl->scaled = NULL;
354   }
355   if ( image == NULL )
356     vgl->image = NULL;
357   vgl->image = g_strdup ( image );
358 }
359
360 static gboolean world_file_read_line ( gchar *buffer, gint size, FILE *f, GtkWidget *widget, gboolean use_value )
361 {
362   if (!fgets ( buffer, 1024, f ))
363   {
364     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(widget), _("Unexpected end of file reading World file.") );
365     g_free ( buffer );
366     fclose ( f );
367     f = NULL;
368     return FALSE;
369   }
370   if ( use_value )
371   {
372     gdouble val = g_strtod ( buffer, NULL );
373     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
374   }
375   return TRUE;
376 }
377
378 static void georef_layer_dialog_load ( GtkWidget *pass_along[4] )
379 {
380   GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
381                                       NULL,
382                                       GTK_FILE_CHOOSER_ACTION_OPEN,
383                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
384                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
385                                       NULL);
386
387   if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
388   {
389     FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "r" );
390     gtk_widget_destroy ( file_selector ); 
391     if ( !f )
392     {
393       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The World file you requested could not be opened for reading.") );
394       return;
395     }
396     else
397     {
398       gchar *buffer = g_malloc ( 1024 * sizeof(gchar) );
399       if ( world_file_read_line ( buffer, 1024, f, pass_along[0], TRUE ) && world_file_read_line ( buffer, 1024, f, pass_along[0], FALSE)
400         && world_file_read_line ( buffer, 1024, f, pass_along[0], FALSE ) && world_file_read_line ( buffer, 1024, f, pass_along[1], TRUE)
401         && world_file_read_line ( buffer, 1024, f, pass_along[2], TRUE ) && world_file_read_line ( buffer, 1024, f, pass_along[3], TRUE ) )
402       {
403         g_free ( buffer );
404         fclose ( f );
405         f = NULL;
406       }
407     }
408   }
409   else
410     gtk_widget_destroy ( file_selector ); 
411 /* do your jazz
412 We need a
413   file selection dialog
414   file opener for reading, if NULL, send error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]) )
415   does that catch directories too?
416   read lines -- if not enough lines, give error.
417   if anything outside, give error. define range with #define CONSTANTS
418   put 'em in thar widgets, and that's it.
419 */
420 }
421
422 static void georef_layer_export_params ( gpointer *pass_along[2] )
423 {
424   VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
425   GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
426                                       NULL,
427                                       GTK_FILE_CHOOSER_ACTION_SAVE,
428                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
429                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
430                                       NULL);
431   if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
432   {
433     FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
434     
435     gtk_widget_destroy ( file_selector ); 
436     if ( !f )
437     {
438       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
439       return;
440     }
441     else
442     {
443       fprintf ( f, "%f\n%f\n%f\n%f\n%f\n%f\n", vgl->mpp_easting, vgl->mpp_northing, 0.0, 0.0, vgl->corner.easting, vgl->corner.northing );
444       fclose ( f );
445       f = NULL;
446     }
447   }
448   else
449    gtk_widget_destroy ( file_selector ); 
450 }
451
452 /* returns TRUE if OK was pressed. */
453 static gboolean georef_layer_dialog ( VikGeorefLayer **vgl, gpointer vp, GtkWindow *w )
454 {
455   GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
456                                                   w,
457                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
458                                                   GTK_STOCK_CANCEL,
459                                                   GTK_RESPONSE_REJECT,
460                                                   GTK_STOCK_OK,
461                                                   GTK_RESPONSE_ACCEPT,
462                                                   NULL );
463   /* Default to reject as user really needs to specify map file first */
464   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
465   GtkWidget *response_w = NULL;
466 #if GTK_CHECK_VERSION (2, 20, 0)
467   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
468 #endif
469   GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *ce_spin, *cn_label, *cn_spin, *xlabel, *xspin, *ylabel, *yspin, *imagelabel, *imageentry;
470
471   GtkWidget *pass_along[4];
472
473   table = gtk_table_new ( 6, 2, FALSE );
474   gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0 );
475
476   wfp_hbox = gtk_hbox_new ( FALSE, 0 );
477   wfp_label = gtk_label_new ( _("World File Parameters:") );
478   wfp_button = gtk_button_new_with_label ( _("Load From File...") );
479
480   gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_label, TRUE, TRUE, 0 );
481   gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_button, FALSE, FALSE, 3 );
482
483   ce_label = gtk_label_new ( _("Corner pixel easting:") );
484   ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
485   gtk_widget_set_tooltip_text ( GTK_WIDGET(ce_spin), _("the UTM \"easting\" value of the upper-right corner pixel of the map") );
486
487   cn_label = gtk_label_new ( _("Corner pixel northing:") );
488   cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
489   gtk_widget_set_tooltip_text ( GTK_WIDGET(cn_spin), _("the UTM \"northing\" value of the upper-right corner pixel of the map") );
490
491   xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
492   ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
493
494   xspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
495   gtk_widget_set_tooltip_text ( GTK_WIDGET(xspin), _("the scale of the map in the X direction (meters per pixel)") );
496   yspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
497   gtk_widget_set_tooltip_text ( GTK_WIDGET(yspin), _("the scale of the map in the Y direction (meters per pixel)") );
498
499   imagelabel = gtk_label_new ( _("Map Image:") );
500   imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN);
501
502   if (*vgl)
503   {
504     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(ce_spin), (*vgl)->corner.easting );
505     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cn_spin), (*vgl)->corner.northing );
506     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(xspin), (*vgl)->mpp_easting );
507     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(yspin), (*vgl)->mpp_northing );
508     if ( (*vgl)->image )
509     vik_file_entry_set_filename ( VIK_FILE_ENTRY(imageentry), (*vgl)->image );
510   }
511   else
512   {
513     VikCoord corner_coord;
514     struct UTM utm;
515     vik_viewport_screen_to_coord ( VIK_VIEWPORT(vp), 0, 0, &corner_coord );
516     vik_coord_to_utm ( &corner_coord, &utm );
517     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(ce_spin), utm.easting );
518     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cn_spin), utm.northing );
519     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(xspin), vik_viewport_get_xmpp ( VIK_VIEWPORT(vp) ) );
520     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(yspin), vik_viewport_get_ympp ( VIK_VIEWPORT(vp) ) );
521   }
522
523   gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
524   gtk_table_attach_defaults ( GTK_TABLE(table), imageentry, 1, 2, 0, 1 );
525   gtk_table_attach_defaults ( GTK_TABLE(table), wfp_hbox, 0, 2, 1, 2 );
526   gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 2, 3 );
527   gtk_table_attach_defaults ( GTK_TABLE(table), xspin, 1, 2, 2, 3 );
528   gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
529   gtk_table_attach_defaults ( GTK_TABLE(table), yspin, 1, 2, 3, 4 );
530   gtk_table_attach_defaults ( GTK_TABLE(table), ce_label, 0, 1, 4, 5 );
531   gtk_table_attach_defaults ( GTK_TABLE(table), ce_spin, 1, 2, 4, 5 );
532   gtk_table_attach_defaults ( GTK_TABLE(table), cn_label, 0, 1, 5, 6 );
533   gtk_table_attach_defaults ( GTK_TABLE(table), cn_spin, 1, 2, 5, 6 );
534
535   pass_along[0] = xspin;
536   pass_along[1] = yspin;
537   pass_along[2] = ce_spin;
538   pass_along[3] = cn_spin;
539   g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), pass_along );
540
541   if ( response_w )
542     gtk_widget_grab_focus ( response_w );
543
544   gtk_widget_show_all ( table );
545
546   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
547   {
548     if (! *vgl)
549     {
550       *vgl = georef_layer_new ();
551        vik_layer_rename ( VIK_LAYER(*vgl), vik_georef_layer_interface.name );
552     }
553     (*vgl)->corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(ce_spin) );
554     (*vgl)->corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cn_spin) );
555     (*vgl)->mpp_easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(xspin) );
556     (*vgl)->mpp_northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(yspin) );
557     if ( (!(*vgl)->image) || strcmp( (*vgl)->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(imageentry)) ) != 0 )
558     {
559       georef_layer_set_image ( *vgl, vik_file_entry_get_filename(VIK_FILE_ENTRY(imageentry)) );
560       georef_layer_load_image ( *vgl );
561     }
562
563     gtk_widget_destroy ( GTK_WIDGET(dialog) );
564     return TRUE;
565   }
566   gtk_widget_destroy ( GTK_WIDGET(dialog) );
567   return FALSE;
568 }
569
570 static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
571 {
572   vik_viewport_set_xmpp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_easting );
573   vik_viewport_set_ympp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_northing );
574   vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
575 }
576
577 static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
578 {
579   VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
580   VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
581   struct UTM utm;
582   VikCoord coord;
583
584   vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
585
586   utm.easting = vgl->corner.easting + (vgl->width * vgl->mpp_easting / 2); /* only an approximation */
587   utm.northing = vgl->corner.northing - (vgl->height * vgl->mpp_northing / 2);
588
589   vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
590   vik_viewport_set_center_coord ( vp, &coord );
591
592   vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
593 }
594
595 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
596 {
597   static gpointer pass_along[2];
598   GtkWidget *item;
599   pass_along[0] = vgl;
600   pass_along[1] = vlp;
601
602   item = gtk_menu_item_new();
603   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
604   gtk_widget_show ( item );
605
606   /* Now with icons */
607   item = gtk_image_menu_item_new_with_mnemonic ( _("_Zoom to Fit Map") );
608   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
609   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_zoom_to_fit), pass_along );
610   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
611   gtk_widget_show ( item );
612
613   item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Map Center") );
614   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
615   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_goto_center), pass_along );
616   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
617   gtk_widget_show ( item );
618
619   item = gtk_image_menu_item_new_with_mnemonic ( _("_Export to World File") );
620   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
621   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_export_params), pass_along );
622   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
623   gtk_widget_show ( item );
624 }
625
626
627 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
628 {
629   return vvp;
630 }
631
632 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
633 {
634   if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
635     return FALSE;
636
637   if ( vgl->click_x != -1 )
638   {
639     vgl->corner.easting += (event->x - vgl->click_x) * vik_viewport_get_xmpp (vvp);
640     vgl->corner.northing -= (event->y - vgl->click_y) * vik_viewport_get_ympp (vvp);
641     vik_layer_emit_update ( VIK_LAYER(vgl), FALSE );
642     return TRUE;
643   }
644   return FALSE; /* I didn't move anything on this layer! */
645 }
646
647 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
648 {
649   return vvp;
650 }
651
652 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
653 {
654   if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
655     return FALSE;
656   if ( event->button == 1 )
657   {
658     if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
659     {
660       vgl->mpp_easting *= 1.01;
661       vgl->mpp_northing *= 1.01;
662     }
663   }
664   else
665   {
666     if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
667     {
668       vgl->mpp_easting /= 1.01;
669       vgl->mpp_northing /= 1.01;
670     }
671   }
672   vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
673   vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
674   vik_layer_emit_update ( VIK_LAYER(vgl), FALSE );
675   return TRUE;
676 }
677
678 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
679 {
680   if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
681     return FALSE;
682   vgl->click_x = event->x;
683   vgl->click_y = event->y;
684   return TRUE;
685 }