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