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