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