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