]> git.street.me.uk Git - andy/viking.git/blob - src/vikgeoreflayer.c
Fix right click on a selected waypoint image starts to move it.
[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 },
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 },
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   }
224   return TRUE;
225 }
226
227 static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
228 {
229   VikLayerParamData rv;
230   switch ( id )
231   {
232     case PARAM_IMAGE: {
233       gboolean set = FALSE;
234       if ( is_file_operation ) {
235         if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
236           gchar *cwd = g_get_current_dir();
237           if ( cwd ) {
238             rv.s = file_GetRelativeFilename ( cwd, vgl->image );
239             if ( !rv.s ) rv.s = "";
240             set = TRUE;
241           }
242         }
243       }
244       if ( !set )
245         rv.s = vgl->image ? vgl->image : "";
246       break;
247     }
248     case PARAM_CN: rv.d = vgl->corner.northing; break;
249     case PARAM_CE: rv.d = vgl->corner.easting; break;
250     case PARAM_MN: rv.d = vgl->mpp_northing; break;
251     case PARAM_ME: rv.d = vgl->mpp_easting; break;
252   }
253   return rv;
254 }
255
256 static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
257 {
258   VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
259   vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
260
261   // Since GeoRef layer doesn't use uibuilder
262   //  initializing this way won't do anything yet..
263   vik_layer_set_defaults ( VIK_LAYER(vgl), vvp );
264
265   // Make these defaults based on the current view
266   vgl->mpp_northing = vik_viewport_get_ympp ( vvp );
267   vgl->mpp_easting = vik_viewport_get_xmpp ( vvp );
268   vik_coord_to_utm ( vik_viewport_get_center ( vvp ), &(vgl->corner) );
269
270   vgl->image = NULL;
271   vgl->pixbuf = NULL;
272   vgl->click_x = -1;
273   vgl->click_y = -1;
274   vgl->scaled = NULL;
275   vgl->scaled_width = 0;
276   vgl->scaled_height = 0;
277   return vgl;
278 }
279
280 static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
281 {
282   if ( vik_viewport_get_drawmode(vp) != VIK_VIEWPORT_DRAWMODE_UTM )
283     return;
284
285   if ( vgl->pixbuf )
286   {
287     struct UTM utm_middle;
288     gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
289     GdkPixbuf *pixbuf = vgl->pixbuf;
290     guint layer_width = vgl->width;
291     guint layer_height = vgl->height;
292
293     vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm_middle );
294
295     guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
296     gint32 x, y;
297     vgl->corner.zone = utm_middle.zone;
298     vgl->corner.letter = utm_middle.letter;
299     VikCoord corner_coord;
300     vik_coord_load_from_utm ( &corner_coord, vik_viewport_get_coord_mode(vp), &(vgl->corner) );
301     vik_viewport_coord_to_screen ( vp, &corner_coord, &x, &y );
302
303     /* mark to scale the pixbuf if it doesn't match our dimensions */
304     gboolean scale = FALSE;
305     if ( xmpp != vgl->mpp_easting || ympp != vgl->mpp_northing )
306     {
307       scale = TRUE;
308       layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
309       layer_height = round(vgl->height * vgl->mpp_northing / ympp);
310     }
311
312     // If image not in viewport bounds - no need to draw it (or bother with any scaling)
313     if ( (x < 0 || x < width) && (y < 0 || y < height) && x+layer_width > 0 && y+layer_height > 0 ) {
314
315       if ( scale )
316       {
317         /* rescale if necessary */
318         if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
319           pixbuf = vgl->scaled;
320         else
321         {
322           pixbuf = gdk_pixbuf_scale_simple(
323             vgl->pixbuf,
324             layer_width,
325             layer_height,
326             GDK_INTERP_BILINEAR
327           );
328
329           if (vgl->scaled != NULL)
330             g_object_unref(vgl->scaled);
331
332           vgl->scaled = pixbuf;
333           vgl->scaled_width = layer_width;
334           vgl->scaled_height = layer_height;
335         }
336       }
337       vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
338     }
339   }
340 }
341
342 static void georef_layer_free ( VikGeorefLayer *vgl )
343 {
344   if ( vgl->image != NULL )
345     g_free ( vgl->image );
346   if ( vgl->scaled != NULL )
347     g_object_unref ( vgl->scaled );
348 }
349
350 static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
351 {
352   return georef_layer_new ( vp );
353 }
354
355 static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
356 {
357   return georef_layer_dialog ( &vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
358 }
359
360 static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
361 {
362   GError *gx = NULL;
363   if ( vgl->image == NULL )
364     return;
365
366   if ( vgl->pixbuf )
367     g_object_unref ( G_OBJECT(vgl->pixbuf) );
368   if ( vgl->scaled )
369   {
370     g_object_unref ( G_OBJECT(vgl->scaled) );
371     vgl->scaled = NULL;
372   }
373
374   vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
375
376   if (gx)
377   {
378     if ( !from_file )
379       a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
380     g_error_free ( gx );
381   }
382   else
383   {
384     vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
385     vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
386   }
387
388   if ( !from_file )
389   {
390     if ( vik_viewport_get_drawmode(vp) != VIK_VIEWPORT_DRAWMODE_UTM )
391     {
392       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
393                              _("GeoRef map cannot be displayed in the current drawmode.\nSelect \"UTM Mode\" from View menu to view it.") );
394     }
395   }
396   /* should find length and width here too */
397 }
398
399 static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
400 {
401   if ( vgl->image )
402     g_free ( vgl->image );
403   if ( vgl->scaled )
404   {
405     g_object_unref ( vgl->scaled );
406     vgl->scaled = NULL;
407   }
408   if ( image == NULL )
409     vgl->image = NULL;
410
411   if ( g_strcmp0 (image, "") != 0 )
412     vgl->image = vu_get_canonical_filename ( VIK_LAYER(vgl), image );
413   else
414     vgl->image = g_strdup (image);
415 }
416
417 static gboolean world_file_read_line ( gchar *buffer, gint size, FILE *f, GtkWidget *widget, gboolean use_value )
418 {
419   if (!fgets ( buffer, 1024, f ))
420   {
421     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(widget), _("Unexpected end of file reading World file.") );
422     g_free ( buffer );
423     fclose ( f );
424     f = NULL;
425     return FALSE;
426   }
427   if ( use_value )
428   {
429     gdouble val = g_strtod ( buffer, NULL );
430     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
431   }
432   return TRUE;
433 }
434
435 static void georef_layer_dialog_load ( GtkWidget *pass_along[4] )
436 {
437   GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
438                                       NULL,
439                                       GTK_FILE_CHOOSER_ACTION_OPEN,
440                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
441                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
442                                       NULL);
443
444   if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
445   {
446     FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "r" );
447     gtk_widget_destroy ( file_selector ); 
448     if ( !f )
449     {
450       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The World file you requested could not be opened for reading.") );
451       return;
452     }
453     else
454     {
455       gchar *buffer = g_malloc ( 1024 * sizeof(gchar) );
456       if ( world_file_read_line ( buffer, 1024, f, pass_along[0], TRUE ) && world_file_read_line ( buffer, 1024, f, pass_along[0], FALSE)
457         && world_file_read_line ( buffer, 1024, f, pass_along[0], FALSE ) && world_file_read_line ( buffer, 1024, f, pass_along[1], TRUE)
458         && world_file_read_line ( buffer, 1024, f, pass_along[2], TRUE ) && world_file_read_line ( buffer, 1024, f, pass_along[3], TRUE ) )
459       {
460         g_free ( buffer );
461         fclose ( f );
462         f = NULL;
463       }
464     }
465   }
466   else
467     gtk_widget_destroy ( file_selector ); 
468 /* do your jazz
469 We need a
470   file selection dialog
471   file opener for reading, if NULL, send error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]) )
472   does that catch directories too?
473   read lines -- if not enough lines, give error.
474   if anything outside, give error. define range with #define CONSTANTS
475   put 'em in thar widgets, and that's it.
476 */
477 }
478
479 static void georef_layer_export_params ( gpointer *pass_along[2] )
480 {
481   VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
482   GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
483                                       NULL,
484                                       GTK_FILE_CHOOSER_ACTION_SAVE,
485                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
486                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
487                                       NULL);
488   if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
489   {
490     FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
491     
492     gtk_widget_destroy ( file_selector ); 
493     if ( !f )
494     {
495       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
496       return;
497     }
498     else
499     {
500       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 );
501       fclose ( f );
502       f = NULL;
503     }
504   }
505   else
506    gtk_widget_destroy ( file_selector ); 
507 }
508
509 /* returns TRUE if OK was pressed. */
510 static gboolean georef_layer_dialog ( VikGeorefLayer **vgl, gpointer vp, GtkWindow *w )
511 {
512   GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
513                                                   w,
514                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
515                                                   GTK_STOCK_CANCEL,
516                                                   GTK_RESPONSE_REJECT,
517                                                   GTK_STOCK_OK,
518                                                   GTK_RESPONSE_ACCEPT,
519                                                   NULL );
520   /* Default to reject as user really needs to specify map file first */
521   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
522   GtkWidget *response_w = NULL;
523 #if GTK_CHECK_VERSION (2, 20, 0)
524   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
525 #endif
526   GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *ce_spin, *cn_label, *cn_spin, *xlabel, *xspin, *ylabel, *yspin, *imagelabel, *imageentry;
527
528   GtkWidget *pass_along[4];
529
530   table = gtk_table_new ( 6, 2, FALSE );
531   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
532
533   wfp_hbox = gtk_hbox_new ( FALSE, 0 );
534   wfp_label = gtk_label_new ( _("World File Parameters:") );
535   wfp_button = gtk_button_new_with_label ( _("Load From File...") );
536
537   gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_label, TRUE, TRUE, 0 );
538   gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_button, FALSE, FALSE, 3 );
539
540   ce_label = gtk_label_new ( _("Corner pixel easting:") );
541   ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
542   gtk_widget_set_tooltip_text ( GTK_WIDGET(ce_spin), _("the UTM \"easting\" value of the upper-left corner pixel of the map") );
543
544   cn_label = gtk_label_new ( _("Corner pixel northing:") );
545   cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
546   gtk_widget_set_tooltip_text ( GTK_WIDGET(cn_spin), _("the UTM \"northing\" value of the upper-left corner pixel of the map") );
547
548   xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
549   ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
550
551   xspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
552   gtk_widget_set_tooltip_text ( GTK_WIDGET(xspin), _("the scale of the map in the X direction (meters per pixel)") );
553   yspin = 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(yspin), _("the scale of the map in the Y direction (meters per pixel)") );
555
556   imagelabel = gtk_label_new ( _("Map Image:") );
557   imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE);
558
559   if (*vgl)
560   {
561     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(ce_spin), (*vgl)->corner.easting );
562     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cn_spin), (*vgl)->corner.northing );
563     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(xspin), (*vgl)->mpp_easting );
564     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(yspin), (*vgl)->mpp_northing );
565     if ( (*vgl)->image )
566     vik_file_entry_set_filename ( VIK_FILE_ENTRY(imageentry), (*vgl)->image );
567   }
568   else
569   {
570     VikCoord corner_coord;
571     struct UTM utm;
572     vik_viewport_screen_to_coord ( VIK_VIEWPORT(vp), 0, 0, &corner_coord );
573     vik_coord_to_utm ( &corner_coord, &utm );
574     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(ce_spin), utm.easting );
575     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cn_spin), utm.northing );
576     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(xspin), vik_viewport_get_xmpp ( VIK_VIEWPORT(vp) ) );
577     gtk_spin_button_set_value ( GTK_SPIN_BUTTON(yspin), vik_viewport_get_ympp ( VIK_VIEWPORT(vp) ) );
578   }
579
580   gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
581   gtk_table_attach_defaults ( GTK_TABLE(table), imageentry, 1, 2, 0, 1 );
582   gtk_table_attach_defaults ( GTK_TABLE(table), wfp_hbox, 0, 2, 1, 2 );
583   gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 2, 3 );
584   gtk_table_attach_defaults ( GTK_TABLE(table), xspin, 1, 2, 2, 3 );
585   gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
586   gtk_table_attach_defaults ( GTK_TABLE(table), yspin, 1, 2, 3, 4 );
587   gtk_table_attach_defaults ( GTK_TABLE(table), ce_label, 0, 1, 4, 5 );
588   gtk_table_attach_defaults ( GTK_TABLE(table), ce_spin, 1, 2, 4, 5 );
589   gtk_table_attach_defaults ( GTK_TABLE(table), cn_label, 0, 1, 5, 6 );
590   gtk_table_attach_defaults ( GTK_TABLE(table), cn_spin, 1, 2, 5, 6 );
591
592   pass_along[0] = xspin;
593   pass_along[1] = yspin;
594   pass_along[2] = ce_spin;
595   pass_along[3] = cn_spin;
596   g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), pass_along );
597
598   if ( response_w )
599     gtk_widget_grab_focus ( response_w );
600
601   gtk_widget_show_all ( table );
602
603   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
604   {
605     if (! *vgl)
606     {
607       *vgl = georef_layer_new ( VIK_VIEWPORT(vp) );
608        vik_layer_rename ( VIK_LAYER(*vgl), vik_georef_layer_interface.name );
609     }
610     (*vgl)->corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(ce_spin) );
611     (*vgl)->corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cn_spin) );
612     (*vgl)->mpp_easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(xspin) );
613     (*vgl)->mpp_northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(yspin) );
614     if ( (!(*vgl)->image) || strcmp( (*vgl)->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(imageentry)) ) != 0 )
615     {
616       georef_layer_set_image ( *vgl, vik_file_entry_get_filename(VIK_FILE_ENTRY(imageentry)) );
617       georef_layer_load_image ( *vgl, VIK_VIEWPORT(vp), FALSE );
618     }
619
620     gtk_widget_destroy ( GTK_WIDGET(dialog) );
621     return TRUE;
622   }
623   gtk_widget_destroy ( GTK_WIDGET(dialog) );
624   return FALSE;
625 }
626
627 static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
628 {
629   vik_viewport_set_xmpp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_easting );
630   vik_viewport_set_ympp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_northing );
631   vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
632 }
633
634 static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
635 {
636   VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
637   VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
638   struct UTM utm;
639   VikCoord coord;
640
641   vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
642
643   utm.easting = vgl->corner.easting + (vgl->width * vgl->mpp_easting / 2); /* only an approximation */
644   utm.northing = vgl->corner.northing - (vgl->height * vgl->mpp_northing / 2);
645
646   vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
647   vik_viewport_set_center_coord ( vp, &coord, TRUE );
648
649   vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
650 }
651
652 static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
653 {
654   static gpointer pass_along[2];
655   GtkWidget *item;
656   pass_along[0] = vgl;
657   pass_along[1] = vlp;
658
659   item = gtk_menu_item_new();
660   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
661   gtk_widget_show ( item );
662
663   /* Now with icons */
664   item = gtk_image_menu_item_new_with_mnemonic ( _("_Zoom to Fit Map") );
665   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
666   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_zoom_to_fit), pass_along );
667   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
668   gtk_widget_show ( item );
669
670   item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Map Center") );
671   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
672   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_goto_center), pass_along );
673   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
674   gtk_widget_show ( item );
675
676   item = gtk_image_menu_item_new_with_mnemonic ( _("_Export to World File") );
677   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
678   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_export_params), pass_along );
679   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
680   gtk_widget_show ( item );
681 }
682
683
684 static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
685 {
686   return vvp;
687 }
688
689 static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
690 {
691   if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
692     return FALSE;
693
694   if ( vgl->click_x != -1 )
695   {
696     vgl->corner.easting += (event->x - vgl->click_x) * vik_viewport_get_xmpp (vvp);
697     vgl->corner.northing -= (event->y - vgl->click_y) * vik_viewport_get_ympp (vvp);
698     vik_layer_emit_update ( VIK_LAYER(vgl) );
699     return TRUE;
700   }
701   return FALSE; /* I didn't move anything on this layer! */
702 }
703
704 static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
705 {
706   return vvp;
707 }
708
709 static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
710 {
711   if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
712     return FALSE;
713   if ( event->button == 1 )
714   {
715     if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
716     {
717       vgl->mpp_easting *= 1.01;
718       vgl->mpp_northing *= 1.01;
719     }
720   }
721   else
722   {
723     if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
724     {
725       vgl->mpp_easting /= 1.01;
726       vgl->mpp_northing /= 1.01;
727     }
728   }
729   vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
730   vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
731   vik_layer_emit_update ( VIK_LAYER(vgl) );
732   return TRUE;
733 }
734
735 static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
736 {
737   if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
738     return FALSE;
739   vgl->click_x = event->x;
740   vgl->click_y = event->y;
741   return TRUE;
742 }