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