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