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