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