]> git.street.me.uk Git - andy/viking.git/blame - src/vikgeoreflayer.c
Ensure highlight for a single track or waypoint is always shown on top.
[andy/viking.git] / src / vikgeoreflayer.c
CommitLineData
50a14534
EB
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
4c77d5e0
GB
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
50a14534 26#include "viking.h"
1b14d0d2 27#include "vikutils.h"
a0008235 28#include <glib.h>
6af463da 29#include <glib/gstdio.h>
4c77d5e0 30#include <glib/gi18n.h>
7960e897 31#include <string.h>
be75ec20
MR
32#include <math.h>
33#include <stdlib.h>
50a14534 34
bce3a7b0 35#include "icons/icons.h"
a7023a1b 36/*
a7023a1b
RN
37static VikLayerParamData image_default ( void )
38{
39 VikLayerParamData data;
40 data.s = g_strdup ("");
41 return data;
42}
a7023a1b 43*/
bce3a7b0 44
50a14534 45VikLayerParam georef_layer_params[] = {
a87f8fa1
RN
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 },
50a14534
EB
51};
52
53enum { PARAM_IMAGE = 0, PARAM_CE, PARAM_CN, PARAM_ME, PARAM_MN, NUM_PARAMS };
54
e6b64c5d 55static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
0a6cab71
AF
56static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
57static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
58static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
59static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
a7023a1b 60static VikGeorefLayer *georef_layer_new ( VikViewport *vvp );
a6b90ba4 61static VikGeorefLayer *georef_layer_create ( VikViewport *vp );
50a14534 62static void georef_layer_free ( VikGeorefLayer *vgl );
a6b90ba4 63static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
fd22ce3e 64static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp );
50a14534
EB
65static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
66static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
67static gboolean georef_layer_dialog ( VikGeorefLayer **vgl, gpointer vp, GtkWindow *w );
fd22ce3e 68static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file );
941aa6e9
AF
69
70/* tools */
71static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
72static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
73static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
941aa6e9 74static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
75static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
76
79dce0cb 77// See comment in viktrwlayer.c for advice on values used
50a14534 78static VikToolInterface georef_tools[] = {
79dce0cb
RN
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,
bce3a7b0 81 (VikToolMouseFunc) georef_layer_move_press, NULL, (VikToolMouseFunc) georef_layer_move_release,
ef5e8132
RN
82 (VikToolKeyFunc) NULL,
83 FALSE,
84 GDK_CURSOR_IS_PIXMAP, &cursor_geomove_pixbuf },
941aa6e9 85
79dce0cb
RN
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,
bce3a7b0 88 (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
ef5e8132
RN
89 (VikToolKeyFunc) NULL,
90 FALSE,
91 GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf },
50a14534
EB
92};
93
94VikLayerInterface vik_georef_layer_interface = {
db386630 95 "GeoRef Map",
affcc0f2 96 N_("GeoRef Map"),
75078768 97 NULL,
5bfafde9 98 &vikgeoreflayer_pixbuf, /*icon */
50a14534
EB
99
100 georef_tools,
101 sizeof(georef_tools) / sizeof(VikToolInterface),
102
103 georef_layer_params,
104 NUM_PARAMS,
105 NULL,
106 0,
107
5a4a28bf
QT
108 VIK_MENU_ITEM_ALL,
109
50a14534
EB
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
20c7a3a0
QT
119 (VikLayerFuncSetMenuItemsSelection) NULL,
120 (VikLayerFuncGetMenuItemsSelection) NULL,
121
50a14534
EB
122 (VikLayerFuncAddMenuItems) georef_layer_add_menu_items,
123 (VikLayerFuncSublayerAddMenuItems) NULL,
124
125 (VikLayerFuncSublayerRenameRequest) NULL,
126 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 127 (VikLayerFuncSublayerTooltip) NULL,
e6b64c5d 128 (VikLayerFuncLayerTooltip) georef_layer_tooltip,
a5dcfdb7 129 (VikLayerFuncLayerSelected) NULL,
50a14534 130
0a6cab71
AF
131 (VikLayerFuncMarshall) georef_layer_marshall,
132 (VikLayerFuncUnmarshall) georef_layer_unmarshall,
50a14534
EB
133
134 (VikLayerFuncSetParam) georef_layer_set_param,
135 (VikLayerFuncGetParam) georef_layer_get_param,
db43cfa4 136 (VikLayerFuncChangeParam) NULL,
50a14534
EB
137
138 (VikLayerFuncReadFileData) NULL,
139 (VikLayerFuncWriteFileData) NULL,
140
33534cd8 141 (VikLayerFuncDeleteItem) NULL,
d5874ef9 142 (VikLayerFuncCutItem) NULL,
50a14534
EB
143 (VikLayerFuncCopyItem) NULL,
144 (VikLayerFuncPasteItem) NULL,
145 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 146 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
147
148 (VikLayerFuncSelectClick) NULL,
08f14055
RN
149 (VikLayerFuncSelectMove) NULL,
150 (VikLayerFuncSelectRelease) NULL,
e46f259a 151 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
152};
153
154struct _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
f3505ea3
MR
162 GdkPixbuf *scaled;
163 guint32 scaled_width, scaled_height;
164
50a14534
EB
165 gint click_x, click_y;
166};
167
168
169
170GType 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
e6b64c5d
RN
194static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
195{
196 return vgl->image;
197}
198
0a6cab71
AF
199static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
200{
201 vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
202}
203
204static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
205{
a7023a1b 206 VikGeorefLayer *rv = georef_layer_new ( vvp );
0a6cab71
AF
207 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
208 if (rv->image) {
fd22ce3e 209 georef_layer_load_image ( rv, vvp, TRUE );
0a6cab71
AF
210 }
211 return rv;
212}
213
158b3642 214static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
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
158b3642 227static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
50a14534
EB
228{
229 VikLayerParamData rv;
230 switch ( id )
231 {
88542aa9
RN
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 }
50a14534
EB
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
a7023a1b 256static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
50a14534
EB
257{
258 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
a0c65899 259 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
50a14534 260
a7023a1b
RN
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
26342bd8
RN
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
50a14534
EB
270 vgl->image = NULL;
271 vgl->pixbuf = NULL;
272 vgl->click_x = -1;
273 vgl->click_y = -1;
f3505ea3
MR
274 vgl->scaled = NULL;
275 vgl->scaled_width = 0;
276 vgl->scaled_height = 0;
50a14534
EB
277 return vgl;
278}
279
fd22ce3e 280static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
50a14534 281{
fd22ce3e
RN
282 if ( vik_viewport_get_drawmode(vp) != VIK_VIEWPORT_DRAWMODE_UTM )
283 return;
284
50a14534
EB
285 if ( vgl->pixbuf )
286 {
50a14534
EB
287 struct UTM utm_middle;
288 gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
be75ec20
MR
289 GdkPixbuf *pixbuf = vgl->pixbuf;
290 guint layer_width = vgl->width;
291 guint layer_height = vgl->height;
292
50a14534
EB
293 vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm_middle );
294
be75ec20
MR
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 );
1b4b9e3b
RN
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 }
be75ec20 337 vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
1b4b9e3b 338 }
50a14534
EB
339 }
340}
341
342static void georef_layer_free ( VikGeorefLayer *vgl )
343{
344 if ( vgl->image != NULL )
345 g_free ( vgl->image );
f3505ea3
MR
346 if ( vgl->scaled != NULL )
347 g_object_unref ( vgl->scaled );
50a14534
EB
348}
349
a6b90ba4 350static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
50a14534 351{
a7023a1b 352 return georef_layer_new ( vp );
50a14534
EB
353}
354
a6b90ba4 355static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
50a14534
EB
356{
357 return georef_layer_dialog ( &vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
358}
359
fd22ce3e 360static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
50a14534
EB
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) );
f3505ea3
MR
368 if ( vgl->scaled )
369 {
370 g_object_unref ( G_OBJECT(vgl->scaled) );
371 vgl->scaled = NULL;
372 }
50a14534
EB
373
374 vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
375
376 if (gx)
377 {
28424566
RN
378 if ( !from_file )
379 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
50a14534
EB
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
fd22ce3e
RN
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 }
50a14534
EB
396 /* should find length and width here too */
397}
398
399static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
400{
401 if ( vgl->image )
402 g_free ( vgl->image );
f3505ea3
MR
403 if ( vgl->scaled )
404 {
405 g_object_unref ( vgl->scaled );
406 vgl->scaled = NULL;
407 }
50a14534
EB
408 if ( image == NULL )
409 vgl->image = NULL;
1b14d0d2
RN
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);
50a14534
EB
415}
416
417static gboolean world_file_read_line ( gchar *buffer, gint size, FILE *f, GtkWidget *widget, gboolean use_value )
418{
419 if (!fgets ( buffer, 1024, f ))
420 {
4c77d5e0 421 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(widget), _("Unexpected end of file reading World file.") );
50a14534
EB
422 g_free ( buffer );
423 fclose ( f );
8c060406 424 f = NULL;
50a14534
EB
425 return FALSE;
426 }
427 if ( use_value )
428 {
a0008235 429 gdouble val = g_strtod ( buffer, NULL );
50a14534
EB
430 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
431 }
432 return TRUE;
433}
434
435static void georef_layer_dialog_load ( GtkWidget *pass_along[4] )
436{
6e4a49aa
MA
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 )
50a14534 445 {
8c060406 446 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "r" );
50a14534
EB
447 gtk_widget_destroy ( file_selector );
448 if ( !f )
449 {
4c77d5e0 450 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The World file you requested could not be opened for reading.") );
50a14534
EB
451 return;
452 }
453 else
454 {
455 gchar *buffer = g_malloc ( 1024 * sizeof(gchar) );
0b647b0b
MA
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)
50a14534
EB
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 );
8c060406 462 f = NULL;
50a14534
EB
463 }
464 }
465 }
466 else
467 gtk_widget_destroy ( file_selector );
468/* do your jazz
469We 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
479static void georef_layer_export_params ( gpointer *pass_along[2] )
480{
481 VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
6e4a49aa
MA
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 )
50a14534 489 {
8c060406 490 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
6e4a49aa 491
50a14534
EB
492 gtk_widget_destroy ( file_selector );
493 if ( !f )
494 {
4c77d5e0 495 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
50a14534
EB
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 );
8c060406 502 f = NULL;
50a14534
EB
503 }
504 }
505 else
506 gtk_widget_destroy ( file_selector );
507}
508
509/* returns TRUE if OK was pressed. */
510static gboolean georef_layer_dialog ( VikGeorefLayer **vgl, gpointer vp, GtkWindow *w )
511{
4c77d5e0 512 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
50a14534
EB
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,
10888930 519 NULL );
535747e9
RN
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
50a14534
EB
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 );
9b082b39 531 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
50a14534
EB
532
533 wfp_hbox = gtk_hbox_new ( FALSE, 0 );
4c77d5e0
GB
534 wfp_label = gtk_label_new ( _("World File Parameters:") );
535 wfp_button = gtk_button_new_with_label ( _("Load From File...") );
50a14534
EB
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
4c77d5e0 540 ce_label = gtk_label_new ( _("Corner pixel easting:") );
ac33062d 541 ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
09b2a3c9 542 gtk_widget_set_tooltip_text ( GTK_WIDGET(ce_spin), _("the UTM \"easting\" value of the upper-left corner pixel of the map") );
50a14534 543
4c77d5e0 544 cn_label = gtk_label_new ( _("Corner pixel northing:") );
ac33062d 545 cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
09b2a3c9 546 gtk_widget_set_tooltip_text ( GTK_WIDGET(cn_spin), _("the UTM \"northing\" value of the upper-left corner pixel of the map") );
50a14534 547
4c77d5e0
GB
548 xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
549 ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
50a14534 550
ac33062d 551 xspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
79a9a44f 552 gtk_widget_set_tooltip_text ( GTK_WIDGET(xspin), _("the scale of the map in the X direction (meters per pixel)") );
ac33062d 553 yspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
79a9a44f 554 gtk_widget_set_tooltip_text ( GTK_WIDGET(yspin), _("the scale of the map in the Y direction (meters per pixel)") );
50a14534 555
4c77d5e0 556 imagelabel = gtk_label_new ( _("Map Image:") );
857baaa3 557 imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE);
50a14534
EB
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
535747e9
RN
598 if ( response_w )
599 gtk_widget_grab_focus ( response_w );
600
50a14534
EB
601 gtk_widget_show_all ( table );
602
603 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
604 {
605 if (! *vgl)
606 {
a7023a1b 607 *vgl = georef_layer_new ( VIK_VIEWPORT(vp) );
50a14534
EB
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)) );
fd22ce3e 617 georef_layer_load_image ( *vgl, VIK_VIEWPORT(vp), FALSE );
50a14534
EB
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
627static 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
634static 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 );
648
649 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
650}
651
652static 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
d6de71f9
RN
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) );
50a14534
EB
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
d6de71f9
RN
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) );
50a14534
EB
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
d6de71f9
RN
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) );
50a14534
EB
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
941aa6e9
AF
683
684static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
685{
686 return vvp;
687}
688
50a14534
EB
689static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
690{
941aa6e9
AF
691 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
692 return FALSE;
693
50a14534
EB
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);
da121f9b 698 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
699 return TRUE;
700 }
701 return FALSE; /* I didn't move anything on this layer! */
702}
703
941aa6e9
AF
704static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
705{
706 return vvp;
707}
708
50a14534
EB
709static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
710{
941aa6e9
AF
711 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
712 return FALSE;
50a14534
EB
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 );
da121f9b 731 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
732 return TRUE;
733}
734
735static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
736{
941aa6e9
AF
737 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
738 return FALSE;
50a14534
EB
739 vgl->click_x = event->x;
740 vgl->click_y = event->y;
741 return TRUE;
742}