]> git.street.me.uk Git - andy/viking.git/blame - src/vikgeoreflayer.c
[QA] CID#101114+CID#101115: Result not floating point
[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>
69c4125a 5 * Copyright (c) 2014, Rob Norris <rw_norris@hotmail.com>
50a14534
EB
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
4c77d5e0
GB
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
50a14534 27#include "viking.h"
1b14d0d2 28#include "vikutils.h"
a0008235 29#include <glib.h>
6af463da 30#include <glib/gstdio.h>
4c77d5e0 31#include <glib/gi18n.h>
7960e897 32#include <string.h>
be75ec20
MR
33#include <math.h>
34#include <stdlib.h>
69c4125a 35#include <ctype.h>
50a14534 36
b7a0cc40 37#include "ui_util.h"
3bd57299 38#include "preferences.h"
bce3a7b0 39#include "icons/icons.h"
a7023a1b 40/*
a7023a1b
RN
41static VikLayerParamData image_default ( void )
42{
43 VikLayerParamData data;
44 data.s = g_strdup ("");
45 return data;
46}
a7023a1b 47*/
bce3a7b0 48
50a14534 49VikLayerParam georef_layer_params[] = {
a87f8fa1
RN
50 { VIK_LAYER_GEOREF, "image", VIK_LAYER_PARAM_STRING, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
51 { VIK_LAYER_GEOREF, "corner_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
52 { VIK_LAYER_GEOREF, "corner_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
53 { VIK_LAYER_GEOREF, "mpp_easting", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
54 { VIK_LAYER_GEOREF, "mpp_northing", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
69c4125a
RN
55 { VIK_LAYER_GEOREF, "corner_zone", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
56 { VIK_LAYER_GEOREF, "corner_letter_as_int", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
b7a0cc40 57 { VIK_LAYER_GEOREF, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL },
50a14534
EB
58};
59
69c4125a
RN
60enum {
61 PARAM_IMAGE = 0,
62 PARAM_CE,
63 PARAM_CN,
64 PARAM_ME,
65 PARAM_MN,
66 PARAM_CZ,
67 PARAM_CL,
b7a0cc40 68 PARAM_AA,
69c4125a 69 NUM_PARAMS };
50a14534 70
e6b64c5d 71static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl );
0a6cab71
AF
72static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len );
73static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
74static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
75static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation );
a7023a1b 76static VikGeorefLayer *georef_layer_new ( VikViewport *vvp );
a6b90ba4 77static VikGeorefLayer *georef_layer_create ( VikViewport *vp );
50a14534 78static void georef_layer_free ( VikGeorefLayer *vgl );
a6b90ba4 79static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp );
fd22ce3e 80static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp );
50a14534
EB
81static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp );
82static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image );
f6d4661b 83static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w );
fd22ce3e 84static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file );
941aa6e9
AF
85
86/* tools */
87static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
88static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
89static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
941aa6e9 90static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp);
50a14534
EB
91static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp );
92
79dce0cb 93// See comment in viktrwlayer.c for advice on values used
50a14534 94static VikToolInterface georef_tools[] = {
79dce0cb
RN
95 { { "GeorefMoveMap", "vik-icon-Georef Move Map", N_("_Georef Move Map"), NULL, N_("Georef Move Map"), 0 },
96 (VikToolConstructorFunc) georef_layer_move_create, NULL, NULL, NULL,
bce3a7b0 97 (VikToolMouseFunc) georef_layer_move_press, NULL, (VikToolMouseFunc) georef_layer_move_release,
ef5e8132
RN
98 (VikToolKeyFunc) NULL,
99 FALSE,
63959706 100 GDK_CURSOR_IS_PIXMAP, &cursor_geomove_pixbuf, NULL },
941aa6e9 101
79dce0cb
RN
102 { { "GeorefZoomTool", "vik-icon-Georef Zoom Tool", N_("Georef Z_oom Tool"), NULL, N_("Georef Zoom Tool"), 0 },
103 (VikToolConstructorFunc) georef_layer_zoom_create, NULL, NULL, NULL,
bce3a7b0 104 (VikToolMouseFunc) georef_layer_zoom_press, NULL, NULL,
ef5e8132
RN
105 (VikToolKeyFunc) NULL,
106 FALSE,
63959706 107 GDK_CURSOR_IS_PIXMAP, &cursor_geozoom_pixbuf, NULL },
50a14534
EB
108};
109
110VikLayerInterface vik_georef_layer_interface = {
db386630 111 "GeoRef Map",
affcc0f2 112 N_("GeoRef Map"),
75078768 113 NULL,
5bfafde9 114 &vikgeoreflayer_pixbuf, /*icon */
50a14534
EB
115
116 georef_tools,
117 sizeof(georef_tools) / sizeof(VikToolInterface),
118
119 georef_layer_params,
120 NUM_PARAMS,
121 NULL,
122 0,
123
5a4a28bf
QT
124 VIK_MENU_ITEM_ALL,
125
50a14534
EB
126 (VikLayerFuncCreate) georef_layer_create,
127 (VikLayerFuncRealize) NULL,
128 (VikLayerFuncPostRead) georef_layer_load_image,
129 (VikLayerFuncFree) georef_layer_free,
130
131 (VikLayerFuncProperties) georef_layer_properties,
132 (VikLayerFuncDraw) georef_layer_draw,
133 (VikLayerFuncChangeCoordMode) NULL,
134
03c97bc3
RN
135 (VikLayerFuncGetTimestamp) NULL,
136
20c7a3a0
QT
137 (VikLayerFuncSetMenuItemsSelection) NULL,
138 (VikLayerFuncGetMenuItemsSelection) NULL,
139
50a14534
EB
140 (VikLayerFuncAddMenuItems) georef_layer_add_menu_items,
141 (VikLayerFuncSublayerAddMenuItems) NULL,
142
143 (VikLayerFuncSublayerRenameRequest) NULL,
144 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 145 (VikLayerFuncSublayerTooltip) NULL,
e6b64c5d 146 (VikLayerFuncLayerTooltip) georef_layer_tooltip,
a5dcfdb7 147 (VikLayerFuncLayerSelected) NULL,
50a14534 148
0a6cab71
AF
149 (VikLayerFuncMarshall) georef_layer_marshall,
150 (VikLayerFuncUnmarshall) georef_layer_unmarshall,
50a14534
EB
151
152 (VikLayerFuncSetParam) georef_layer_set_param,
153 (VikLayerFuncGetParam) georef_layer_get_param,
db43cfa4 154 (VikLayerFuncChangeParam) NULL,
50a14534
EB
155
156 (VikLayerFuncReadFileData) NULL,
157 (VikLayerFuncWriteFileData) NULL,
158
33534cd8 159 (VikLayerFuncDeleteItem) NULL,
d5874ef9 160 (VikLayerFuncCutItem) NULL,
50a14534
EB
161 (VikLayerFuncCopyItem) NULL,
162 (VikLayerFuncPasteItem) NULL,
163 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 164 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
165
166 (VikLayerFuncSelectClick) NULL,
08f14055
RN
167 (VikLayerFuncSelectMove) NULL,
168 (VikLayerFuncSelectRelease) NULL,
e46f259a 169 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
170};
171
69c4125a
RN
172typedef struct {
173 GtkWidget *x_spin;
174 GtkWidget *y_spin;
175 // UTM widgets
176 GtkWidget *ce_spin; // top left
177 GtkWidget *cn_spin; // "
178 GtkWidget *utm_zone_spin;
179 GtkWidget *utm_letter_entry;
180
181 GtkWidget *lat_tl_spin;
182 GtkWidget *lon_tl_spin;
183 GtkWidget *lat_br_spin;
184 GtkWidget *lon_br_spin;
185 //
186 GtkWidget *tabs;
187 GtkWidget *imageentry;
188} changeable_widgets;
189
50a14534
EB
190struct _VikGeorefLayer {
191 VikLayer vl;
192 gchar *image;
193 GdkPixbuf *pixbuf;
b7a0cc40
RN
194 guint8 alpha;
195
69c4125a 196 struct UTM corner; // Top Left
50a14534 197 gdouble mpp_easting, mpp_northing;
69c4125a 198 struct LatLon ll_br; // Bottom Right
50a14534
EB
199 guint width, height;
200
f3505ea3
MR
201 GdkPixbuf *scaled;
202 guint32 scaled_width, scaled_height;
203
50a14534 204 gint click_x, click_y;
69c4125a 205 changeable_widgets cw;
50a14534
EB
206};
207
3bd57299
RN
208static VikLayerParam io_prefs[] = {
209 { VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_IO_NAMESPACE "georef_auto_read_world_file", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Auto Read World Files:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
210 N_("Automatically attempt to read associated world file of a new image for a GeoRef layer"), NULL, NULL, NULL}
211};
50a14534 212
3bd57299
RN
213void vik_georef_layer_init (void)
214{
215 VikLayerParamData tmp;
216 tmp.b = TRUE;
217 a_preferences_register(&io_prefs[0], tmp, VIKING_PREFERENCES_IO_GROUP_KEY);
218}
50a14534
EB
219
220GType vik_georef_layer_get_type ()
221{
222 static GType vgl_type = 0;
223
224 if (!vgl_type)
225 {
226 static const GTypeInfo vgl_info =
227 {
228 sizeof (VikGeorefLayerClass),
229 NULL, /* base_init */
230 NULL, /* base_finalize */
231 NULL, /* class init */
232 NULL, /* class_finalize */
233 NULL, /* class_data */
234 sizeof (VikGeorefLayer),
235 0,
236 NULL /* instance init */
237 };
238 vgl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikGeorefLayer", &vgl_info, 0 );
239 }
240
241 return vgl_type;
242}
243
e6b64c5d
RN
244static const gchar* georef_layer_tooltip ( VikGeorefLayer *vgl )
245{
246 return vgl->image;
247}
248
0a6cab71
AF
249static void georef_layer_marshall( VikGeorefLayer *vgl, guint8 **data, gint *len )
250{
251 vik_layer_marshall_params ( VIK_LAYER(vgl), data, len );
252}
253
254static VikGeorefLayer *georef_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
255{
a7023a1b 256 VikGeorefLayer *rv = georef_layer_new ( vvp );
0a6cab71
AF
257 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
258 if (rv->image) {
fd22ce3e 259 georef_layer_load_image ( rv, vvp, TRUE );
0a6cab71
AF
260 }
261 return rv;
262}
263
158b3642 264static gboolean georef_layer_set_param ( VikGeorefLayer *vgl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
50a14534
EB
265{
266 switch ( id )
267 {
268 case PARAM_IMAGE: georef_layer_set_image ( vgl, data.s ); break;
269 case PARAM_CN: vgl->corner.northing = data.d; break;
270 case PARAM_CE: vgl->corner.easting = data.d; break;
271 case PARAM_MN: vgl->mpp_northing = data.d; break;
69c4125a
RN
272 case PARAM_ME: vgl->mpp_easting = data.d; break;
273 case PARAM_CZ: if ( data.u <= 60 ) vgl->corner.zone = data.u; break;
274 case PARAM_CL: if ( data.u >= 65 || data.u <= 90 ) vgl->corner.letter = data.u; break;
b7a0cc40 275 case PARAM_AA: if ( data.u <= 255 ) vgl->alpha = data.u; break;
9351abc4 276 default: break;
50a14534
EB
277 }
278 return TRUE;
279}
280
158b3642 281static VikLayerParamData georef_layer_get_param ( VikGeorefLayer *vgl, guint16 id, gboolean is_file_operation )
50a14534
EB
282{
283 VikLayerParamData rv;
284 switch ( id )
285 {
88542aa9
RN
286 case PARAM_IMAGE: {
287 gboolean set = FALSE;
288 if ( is_file_operation ) {
289 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
290 gchar *cwd = g_get_current_dir();
291 if ( cwd ) {
292 rv.s = file_GetRelativeFilename ( cwd, vgl->image );
293 if ( !rv.s ) rv.s = "";
294 set = TRUE;
295 }
296 }
297 }
298 if ( !set )
299 rv.s = vgl->image ? vgl->image : "";
300 break;
301 }
50a14534
EB
302 case PARAM_CN: rv.d = vgl->corner.northing; break;
303 case PARAM_CE: rv.d = vgl->corner.easting; break;
304 case PARAM_MN: rv.d = vgl->mpp_northing; break;
305 case PARAM_ME: rv.d = vgl->mpp_easting; break;
69c4125a
RN
306 case PARAM_CZ: rv.u = vgl->corner.zone; break;
307 case PARAM_CL: rv.u = vgl->corner.letter; break;
b7a0cc40 308 case PARAM_AA: rv.u = vgl->alpha; break;
9351abc4 309 default: break;
50a14534
EB
310 }
311 return rv;
312}
313
a7023a1b 314static VikGeorefLayer *georef_layer_new ( VikViewport *vvp )
50a14534
EB
315{
316 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( g_object_new ( VIK_GEOREF_LAYER_TYPE, NULL ) );
a0c65899 317 vik_layer_set_type ( VIK_LAYER(vgl), VIK_LAYER_GEOREF );
50a14534 318
a7023a1b
RN
319 // Since GeoRef layer doesn't use uibuilder
320 // initializing this way won't do anything yet..
321 vik_layer_set_defaults ( VIK_LAYER(vgl), vvp );
322
26342bd8
RN
323 // Make these defaults based on the current view
324 vgl->mpp_northing = vik_viewport_get_ympp ( vvp );
325 vgl->mpp_easting = vik_viewport_get_xmpp ( vvp );
326 vik_coord_to_utm ( vik_viewport_get_center ( vvp ), &(vgl->corner) );
327
50a14534
EB
328 vgl->image = NULL;
329 vgl->pixbuf = NULL;
330 vgl->click_x = -1;
331 vgl->click_y = -1;
f3505ea3
MR
332 vgl->scaled = NULL;
333 vgl->scaled_width = 0;
334 vgl->scaled_height = 0;
69c4125a
RN
335 vgl->ll_br.lat = 0.0;
336 vgl->ll_br.lon = 0.0;
b7a0cc40 337 vgl->alpha = 255;
50a14534
EB
338 return vgl;
339}
340
fd22ce3e 341static void georef_layer_draw ( VikGeorefLayer *vgl, VikViewport *vp )
50a14534 342{
50a14534
EB
343 if ( vgl->pixbuf )
344 {
50a14534 345 gdouble xmpp = vik_viewport_get_xmpp(vp), ympp = vik_viewport_get_ympp(vp);
be75ec20
MR
346 GdkPixbuf *pixbuf = vgl->pixbuf;
347 guint layer_width = vgl->width;
348 guint layer_height = vgl->height;
349
be75ec20
MR
350 guint width = vik_viewport_get_width(vp), height = vik_viewport_get_height(vp);
351 gint32 x, y;
be75ec20
MR
352 VikCoord corner_coord;
353 vik_coord_load_from_utm ( &corner_coord, vik_viewport_get_coord_mode(vp), &(vgl->corner) );
354 vik_viewport_coord_to_screen ( vp, &corner_coord, &x, &y );
1b4b9e3b
RN
355
356 /* mark to scale the pixbuf if it doesn't match our dimensions */
357 gboolean scale = FALSE;
358 if ( xmpp != vgl->mpp_easting || ympp != vgl->mpp_northing )
359 {
360 scale = TRUE;
361 layer_width = round(vgl->width * vgl->mpp_easting / xmpp);
362 layer_height = round(vgl->height * vgl->mpp_northing / ympp);
363 }
364
365 // If image not in viewport bounds - no need to draw it (or bother with any scaling)
366 if ( (x < 0 || x < width) && (y < 0 || y < height) && x+layer_width > 0 && y+layer_height > 0 ) {
367
368 if ( scale )
369 {
370 /* rescale if necessary */
371 if (layer_width == vgl->scaled_width && layer_height == vgl->scaled_height && vgl->scaled != NULL)
372 pixbuf = vgl->scaled;
373 else
374 {
375 pixbuf = gdk_pixbuf_scale_simple(
376 vgl->pixbuf,
377 layer_width,
378 layer_height,
379 GDK_INTERP_BILINEAR
380 );
381
382 if (vgl->scaled != NULL)
383 g_object_unref(vgl->scaled);
384
385 vgl->scaled = pixbuf;
386 vgl->scaled_width = layer_width;
387 vgl->scaled_height = layer_height;
388 }
389 }
be75ec20 390 vik_viewport_draw_pixbuf ( vp, pixbuf, 0, 0, x, y, layer_width, layer_height ); /* todo: draw only what we need to. */
1b4b9e3b 391 }
50a14534
EB
392 }
393}
394
395static void georef_layer_free ( VikGeorefLayer *vgl )
396{
397 if ( vgl->image != NULL )
398 g_free ( vgl->image );
f3505ea3
MR
399 if ( vgl->scaled != NULL )
400 g_object_unref ( vgl->scaled );
50a14534
EB
401}
402
a6b90ba4 403static VikGeorefLayer *georef_layer_create ( VikViewport *vp )
50a14534 404{
a7023a1b 405 return georef_layer_new ( vp );
50a14534
EB
406}
407
a6b90ba4 408static gboolean georef_layer_properties ( VikGeorefLayer *vgl, gpointer vp )
50a14534 409{
f6d4661b 410 return georef_layer_dialog ( vgl, vp, VIK_GTK_WINDOW_FROM_WIDGET(vp) );
50a14534
EB
411}
412
fd22ce3e 413static void georef_layer_load_image ( VikGeorefLayer *vgl, VikViewport *vp, gboolean from_file )
50a14534
EB
414{
415 GError *gx = NULL;
416 if ( vgl->image == NULL )
417 return;
418
419 if ( vgl->pixbuf )
420 g_object_unref ( G_OBJECT(vgl->pixbuf) );
f3505ea3
MR
421 if ( vgl->scaled )
422 {
423 g_object_unref ( G_OBJECT(vgl->scaled) );
424 vgl->scaled = NULL;
425 }
50a14534
EB
426
427 vgl->pixbuf = gdk_pixbuf_new_from_file ( vgl->image, &gx );
428
429 if (gx)
430 {
28424566
RN
431 if ( !from_file )
432 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp), _("Couldn't open image file: %s"), gx->message );
50a14534
EB
433 g_error_free ( gx );
434 }
435 else
436 {
437 vgl->width = gdk_pixbuf_get_width ( vgl->pixbuf );
438 vgl->height = gdk_pixbuf_get_height ( vgl->pixbuf );
b7a0cc40
RN
439
440 if ( vgl->pixbuf && vgl->alpha < 255 )
441 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
50a14534 442 }
50a14534
EB
443 /* should find length and width here too */
444}
445
446static void georef_layer_set_image ( VikGeorefLayer *vgl, const gchar *image )
447{
448 if ( vgl->image )
449 g_free ( vgl->image );
f3505ea3
MR
450 if ( vgl->scaled )
451 {
452 g_object_unref ( vgl->scaled );
453 vgl->scaled = NULL;
454 }
50a14534
EB
455 if ( image == NULL )
456 vgl->image = NULL;
1b14d0d2
RN
457
458 if ( g_strcmp0 (image, "") != 0 )
459 vgl->image = vu_get_canonical_filename ( VIK_LAYER(vgl), image );
460 else
461 vgl->image = g_strdup (image);
50a14534
EB
462}
463
92e8adf5
RN
464// Only positive values allowed here
465static void gdouble2spinwidget ( GtkWidget *widget, gdouble val )
50a14534 466{
92e8adf5
RN
467 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(widget), val > 0 ? val : -val );
468}
469
470static void set_widget_values ( changeable_widgets *cw, gdouble values[4] )
471{
472 gdouble2spinwidget ( cw->x_spin, values[0] );
473 gdouble2spinwidget ( cw->y_spin, values[1] );
474 gdouble2spinwidget ( cw->ce_spin, values[2] );
475 gdouble2spinwidget ( cw->cn_spin, values[3] );
476}
477
478static gboolean world_file_read_line ( FILE *ff, gdouble *value, gboolean use_value )
479{
480 gboolean answer = TRUE; // Success
481 gchar buffer[1024];
482 if ( !fgets ( buffer, 1024, ff ) ) {
483 answer = FALSE;
50a14534 484 }
92e8adf5
RN
485 if ( answer && use_value )
486 *value = g_strtod ( buffer, NULL );
487
488 return answer;
489}
490
491/**
492 * http://en.wikipedia.org/wiki/World_file
493 *
494 * Note world files do not define the units and nor are the units standardized :(
495 * Currently Viking only supports:
496 * x&y scale as meters per pixel
497 * x&y coords as UTM eastings and northings respectively
498 */
499static gint world_file_read_file ( const gchar* filename, gdouble values[4] )
500{
501 g_debug ("%s - trying world file %s", __FUNCTION__, filename);
502
503 FILE *f = g_fopen ( filename, "r" );
504 if ( !f )
505 return 1;
506 else {
507 gint answer = 2; // Not enough info read yet
508 // **We do not handle 'skew' values ATM - normally they are a value of 0 anyway to align with the UTM grid
509 if ( world_file_read_line ( f, &values[0], TRUE ) // x scale
510 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in y-skew line**
511 && world_file_read_line ( f, NULL, FALSE ) // Ignore value in x-skew line**
512 && world_file_read_line ( f, &values[1], TRUE ) // y scale
513 && world_file_read_line ( f, &values[2], TRUE ) // x-coordinate of the upper left pixel
514 && world_file_read_line ( f, &values[3], TRUE ) // y-coordinate of the upper left pixel
515 )
516 {
517 // Success
518 g_debug ("%s - %s - world file read success", __FUNCTION__, filename);
519 answer = 0;
520 }
521 fclose ( f );
522 return answer;
50a14534 523 }
50a14534
EB
524}
525
92e8adf5 526static void georef_layer_dialog_load ( changeable_widgets *cw )
50a14534 527{
6e4a49aa
MA
528 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
529 NULL,
530 GTK_FILE_CHOOSER_ACTION_OPEN,
531 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
532 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
533 NULL);
534
535 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
50a14534 536 {
92e8adf5
RN
537 gdouble values[4];
538 gint answer = world_file_read_file ( gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_selector)), values );
539 if ( answer == 1 )
540 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("The World file you requested could not be opened for reading.") );
541 else if ( answer == 2 )
542 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(cw->x_spin), _("Unexpected end of file reading World file.") );
543 else
544 // NB answer should == 0 for success
545 set_widget_values ( cw, values );
50a14534 546 }
92e8adf5
RN
547
548 gtk_widget_destroy ( file_selector );
50a14534
EB
549}
550
551static void georef_layer_export_params ( gpointer *pass_along[2] )
552{
553 VikGeorefLayer *vgl = VIK_GEOREF_LAYER(pass_along[0]);
6e4a49aa
MA
554 GtkWidget *file_selector = gtk_file_chooser_dialog_new (_("Choose World file"),
555 NULL,
556 GTK_FILE_CHOOSER_ACTION_SAVE,
557 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
558 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
559 NULL);
560 if ( gtk_dialog_run ( GTK_DIALOG ( file_selector ) ) == GTK_RESPONSE_ACCEPT )
50a14534 561 {
8c060406 562 FILE *f = g_fopen ( gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(file_selector) ), "w" );
6e4a49aa 563
50a14534
EB
564 gtk_widget_destroy ( file_selector );
565 if ( !f )
566 {
4c77d5e0 567 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_WIDGET(pass_along[0]), _("The file you requested could not be opened for writing.") );
50a14534
EB
568 return;
569 }
570 else
571 {
572 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 );
573 fclose ( f );
8c060406 574 f = NULL;
50a14534
EB
575 }
576 }
577 else
578 gtk_widget_destroy ( file_selector );
579}
580
3bd57299
RN
581/**
582 * Auto attempt to read the world file associated with the image used for the georef
583 * Based on simple file name conventions
584 * Only attempted if the preference is on.
585 */
586static void maybe_read_world_file ( VikFileEntry *vfe, gpointer user_data )
587{
588 if ( a_preferences_get (VIKING_PREFERENCES_IO_NAMESPACE "georef_auto_read_world_file")->b ) {
589 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vfe));
590 gdouble values[4];
591 if ( filename && user_data ) {
592
593 changeable_widgets *cw = user_data;
594
595 gboolean upper = g_ascii_isupper (filename[strlen(filename)-1]);
596 gchar* filew = g_strconcat ( filename, (upper ? "W" : "w") , NULL );
597
598 if ( world_file_read_file ( filew, values ) == 0 ) {
599 set_widget_values ( cw, values );
600 }
601 else {
602 if ( strlen(filename) > 3 ) {
603 gchar* file0 = g_strndup ( filename, strlen(filename)-2 );
604 gchar* file1 = g_strdup_printf ( "%s%c%c", file0, filename[strlen(filename)-1], (upper ? 'W' : 'w') );
605 if ( world_file_read_file ( file1, values ) == 0 ) {
606 set_widget_values ( cw, values );
607 }
608 g_free ( file1 );
609 g_free ( file0 );
610 }
611 }
612 g_free ( filew );
613 }
614 }
615}
616
69c4125a
RN
617static struct LatLon get_ll_tl (VikGeorefLayer *vgl)
618{
619 struct LatLon ll_tl;
620 ll_tl.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin) );
621 ll_tl.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin) );
622 return ll_tl;
623}
624
625static struct LatLon get_ll_br (VikGeorefLayer *vgl)
626{
627 struct LatLon ll_br;
628 ll_br.lat = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lat_br_spin) );
629 ll_br.lon = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.lon_br_spin) );
630 return ll_br;
631}
632
633// Align displayed UTM values with displayed Lat/Lon values
634static void align_utm2ll (VikGeorefLayer *vgl)
635{
636 struct LatLon ll_tl = get_ll_tl (vgl);
637
638 struct UTM utm;
639 a_coords_latlon_to_utm ( &ll_tl, &utm );
640 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin), utm.easting );
641 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin), utm.northing );
642
643 gchar tmp_letter[2];
644 tmp_letter[0] = utm.letter;
645 tmp_letter[1] = '\0';
646 gtk_entry_set_text ( GTK_ENTRY(vgl->cw.utm_letter_entry), tmp_letter );
647
648 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin), utm.zone );
649}
650
651// Align displayed Lat/Lon values with displayed UTM values
652static void align_ll2utm (VikGeorefLayer *vgl)
653{
654 struct UTM corner;
655 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(vgl->cw.utm_letter_entry) );
656 if (*letter)
657 corner.letter = toupper(*letter);
658 corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(vgl->cw.utm_zone_spin) );
659 corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.ce_spin) );
660 corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vgl->cw.cn_spin) );
661
662 struct LatLon ll;
663 a_coords_utm_to_latlon ( &corner, &ll );
664 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lat_tl_spin), ll.lat );
665 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.lon_tl_spin), ll.lon );
666}
667
668/**
669 * Align coordinates between tabs as the user may have changed the values
670 * Use this before acting on the user input
671 * This is easier then trying to use the 'value-changed' signal for each individual coordinate
672 * especiallly since it tends to end up in an infinite loop continually updating each other.
673 */
674static void align_coords ( VikGeorefLayer *vgl )
675{
676 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(vgl->cw.tabs)) == 0)
677 align_ll2utm ( vgl );
678 else
679 align_utm2ll ( vgl );
680}
681
682static void switch_tab (GtkNotebook *notebook, gpointer tab, guint tab_num, gpointer user_data)
683{
684 VikGeorefLayer *vgl = user_data;
685 if ( tab_num == 0 )
686 align_utm2ll (vgl);
687 else
688 align_ll2utm (vgl);
689}
690
691/**
692 *
693 */
694static void check_br_is_good_or_msg_user ( VikGeorefLayer *vgl )
695{
696 // if a 'blank' ll value that's alright
697 if ( vgl->ll_br.lat == 0.0 && vgl->ll_br.lon == 0.0 )
698 return;
699
700 struct LatLon ll_tl = get_ll_tl (vgl);
701 if ( ll_tl.lat < vgl->ll_br.lat || ll_tl.lon > vgl->ll_br.lon )
702 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vgl), _("Lower right corner values may not be consistent with upper right values") );
703}
704
705/**
706 *
707 */
708static void calculate_mpp_from_coords ( GtkWidget *ww, VikGeorefLayer *vgl )
709{
710 const gchar* filename = vik_file_entry_get_filename(VIK_FILE_ENTRY(vgl->cw.imageentry));
711 if ( !filename ) {
712 return;
713 }
714 GError *gx = NULL;
715 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( filename, &gx );
716 if ( gx ) {
717 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Couldn't open image file: %s"), gx->message );
718 g_error_free ( gx );
719 return;
720 }
721
722 guint width = gdk_pixbuf_get_width ( pixbuf );
723 guint height = gdk_pixbuf_get_height ( pixbuf );
724
725 if ( width == 0 || height == 0 ) {
726 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(ww), _("Invalid image size: %s"), filename);
727 }
728 else {
729 align_coords ( vgl );
730
731 struct LatLon ll_tl = get_ll_tl (vgl);
732 struct LatLon ll_br = get_ll_br (vgl);
733
734 struct LatLon ll_tr;
735 ll_tr.lat = ll_tl.lat;
736 ll_tr.lon = ll_br.lon;
737
738 struct LatLon ll_bl;
739 ll_bl.lat = ll_br.lat;
740 ll_bl.lon = ll_tl.lon;
741
742 gdouble diffx = a_coords_latlon_diff ( &ll_tl, &ll_tr );
743 gdouble xmpp = diffx / width;
744
745 gdouble diffy = a_coords_latlon_diff ( &ll_tl, &ll_bl );
746 gdouble ympp = diffy / height;
747
748 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.x_spin), xmpp );
749 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(vgl->cw.y_spin), ympp );
750
751 check_br_is_good_or_msg_user ( vgl );
752 }
753
754 g_object_unref ( G_OBJECT(pixbuf) );
755}
756
757#define VIK_SETTINGS_GEOREF_TAB "georef_coordinate_tab"
758
50a14534 759/* returns TRUE if OK was pressed. */
f6d4661b 760static gboolean georef_layer_dialog ( VikGeorefLayer *vgl, gpointer vp, GtkWindow *w )
50a14534 761{
4c77d5e0 762 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Layer Properties"),
50a14534
EB
763 w,
764 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
765 GTK_STOCK_CANCEL,
766 GTK_RESPONSE_REJECT,
767 GTK_STOCK_OK,
768 GTK_RESPONSE_ACCEPT,
10888930 769 NULL );
535747e9
RN
770 /* Default to reject as user really needs to specify map file first */
771 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
772 GtkWidget *response_w = NULL;
773#if GTK_CHECK_VERSION (2, 20, 0)
774 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
775#endif
69c4125a 776 GtkWidget *table, *wfp_hbox, *wfp_label, *wfp_button, *ce_label, *cn_label, *xlabel, *ylabel, *imagelabel;
92e8adf5 777 changeable_widgets cw;
50a14534 778
69c4125a
RN
779 GtkBox *dgbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
780 table = gtk_table_new ( 4, 2, FALSE );
781 gtk_box_pack_start ( dgbox, table, TRUE, TRUE, 0 );
50a14534
EB
782
783 wfp_hbox = gtk_hbox_new ( FALSE, 0 );
4c77d5e0
GB
784 wfp_label = gtk_label_new ( _("World File Parameters:") );
785 wfp_button = gtk_button_new_with_label ( _("Load From File...") );
50a14534
EB
786
787 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_label, TRUE, TRUE, 0 );
788 gtk_box_pack_start ( GTK_BOX(wfp_hbox), wfp_button, FALSE, FALSE, 3 );
789
4c77d5e0 790 ce_label = gtk_label_new ( _("Corner pixel easting:") );
92e8adf5
RN
791 cw.ce_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 1500000.0, 1, 5, 0 ), 1, 4 );
792 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.ce_spin), _("the UTM \"easting\" value of the upper-left corner pixel of the map") );
50a14534 793
4c77d5e0 794 cn_label = gtk_label_new ( _("Corner pixel northing:") );
92e8adf5
RN
795 cw.cn_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, 0.0, 9000000.0, 1, 5, 0 ), 1, 4 );
796 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.cn_spin), _("the UTM \"northing\" value of the upper-left corner pixel of the map") );
50a14534 797
4c77d5e0
GB
798 xlabel = gtk_label_new ( _("X (easting) scale (mpp): "));
799 ylabel = gtk_label_new ( _("Y (northing) scale (mpp): "));
50a14534 800
92e8adf5
RN
801 cw.x_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
802 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.x_spin), _("the scale of the map in the X direction (meters per pixel)") );
803 cw.y_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( 4, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
804 gtk_widget_set_tooltip_text ( GTK_WIDGET(cw.y_spin), _("the scale of the map in the Y direction (meters per pixel)") );
50a14534 805
4c77d5e0 806 imagelabel = gtk_label_new ( _("Map Image:") );
69c4125a 807 cw.imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE, maybe_read_world_file, &cw);
50a14534 808
92e8adf5
RN
809 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.ce_spin), vgl->corner.easting );
810 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.cn_spin), vgl->corner.northing );
811 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.x_spin), vgl->mpp_easting );
812 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.y_spin), vgl->mpp_northing );
f6d4661b 813 if ( vgl->image )
69c4125a 814 vik_file_entry_set_filename ( VIK_FILE_ENTRY(cw.imageentry), vgl->image );
50a14534
EB
815
816 gtk_table_attach_defaults ( GTK_TABLE(table), imagelabel, 0, 1, 0, 1 );
69c4125a 817 gtk_table_attach_defaults ( GTK_TABLE(table), cw.imageentry, 1, 2, 0, 1 );
50a14534
EB
818 gtk_table_attach_defaults ( GTK_TABLE(table), wfp_hbox, 0, 2, 1, 2 );
819 gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 2, 3 );
92e8adf5 820 gtk_table_attach_defaults ( GTK_TABLE(table), cw.x_spin, 1, 2, 2, 3 );
50a14534 821 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 3, 4 );
92e8adf5 822 gtk_table_attach_defaults ( GTK_TABLE(table), cw.y_spin, 1, 2, 3, 4 );
69c4125a
RN
823
824 cw.tabs = gtk_notebook_new();
825 GtkWidget *table_utm = gtk_table_new ( 3, 2, FALSE );
826
827 gtk_table_attach_defaults ( GTK_TABLE(table_utm), ce_label, 0, 1, 0, 1 );
828 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.ce_spin, 1, 2, 0, 1 );
829 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cn_label, 0, 1, 1, 2 );
830 gtk_table_attach_defaults ( GTK_TABLE(table_utm), cw.cn_spin, 1, 2, 1, 2 );
831
832 GtkWidget *utm_hbox = gtk_hbox_new ( FALSE, 0 );
833 cw.utm_zone_spin = gtk_spin_button_new ((GtkAdjustment*)gtk_adjustment_new( vgl->corner.zone, 1, 60, 1, 5, 0 ), 1, 0 );
834 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Zone:")), TRUE, TRUE, 0 );
835 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_zone_spin, TRUE, TRUE, 0 );
836 gtk_box_pack_start ( GTK_BOX(utm_hbox), gtk_label_new(_("Letter:")), TRUE, TRUE, 0 );
837 cw.utm_letter_entry = gtk_entry_new ();
838 gtk_entry_set_max_length ( GTK_ENTRY(cw.utm_letter_entry), 1 );
839 gtk_entry_set_width_chars ( GTK_ENTRY(cw.utm_letter_entry), 2 );
840 gchar tmp_letter[2];
841 tmp_letter[0] = vgl->corner.letter;
842 tmp_letter[1] = '\0';
843 gtk_entry_set_text ( GTK_ENTRY(cw.utm_letter_entry), tmp_letter );
844 gtk_box_pack_start ( GTK_BOX(utm_hbox), cw.utm_letter_entry, TRUE, TRUE, 0 );
845
846 gtk_table_attach_defaults ( GTK_TABLE(table_utm), utm_hbox, 0, 2, 2, 3 );
847
848 // Lat/Lon
849 GtkWidget *table_ll = gtk_table_new ( 5, 2, FALSE );
850
851 GtkWidget *lat_tl_label = gtk_label_new ( _("Upper left latitude:") );
852 cw.lat_tl_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-90,90.0,0.05,0.1,0), 0.1, 6 );
853 GtkWidget *lon_tl_label = gtk_label_new ( _("Upper left longitude:") );
854 cw.lon_tl_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-180,180.0,0.05,0.1,0), 0.1, 6 );
855 GtkWidget *lat_br_label = gtk_label_new ( _("Lower right latitude:") );
856 cw.lat_br_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-90,90.0,0.05,0.1,0), 0.1, 6 );
857 GtkWidget *lon_br_label = gtk_label_new ( _("Lower right longitude:") );
858 cw.lon_br_spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new (0.0,-180.0,180.0,0.05,0.1,0), 0.1, 6 );
859
860 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_tl_label, 0, 1, 0, 1 );
861 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_tl_spin, 1, 2, 0, 1 );
862 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_tl_label, 0, 1, 1, 2 );
863 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_tl_spin, 1, 2, 1, 2 );
864 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lat_br_label, 0, 1, 2, 3 );
865 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lat_br_spin, 1, 2, 2, 3 );
866 gtk_table_attach_defaults ( GTK_TABLE(table_ll), lon_br_label, 0, 1, 3, 4 );
867 gtk_table_attach_defaults ( GTK_TABLE(table_ll), cw.lon_br_spin, 1, 2, 3, 4 );
868
869 GtkWidget *calc_mpp_button = gtk_button_new_with_label ( _("Calculate MPP values from coordinates") );
870 gtk_widget_set_tooltip_text ( calc_mpp_button, _("Enter all corner coordinates before calculating the MPP values from the image size") );
871 gtk_table_attach_defaults ( GTK_TABLE(table_ll), calc_mpp_button, 0, 2, 4, 5 );
872
873 VikCoord vc;
874 vik_coord_load_from_utm (&vc, VIK_COORD_LATLON, &(vgl->corner));
875 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_tl_spin), vc.north_south );
876 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_tl_spin), vc.east_west );
877 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lat_br_spin), vgl->ll_br.lat );
878 gtk_spin_button_set_value ( GTK_SPIN_BUTTON(cw.lon_br_spin), vgl->ll_br.lon );
879
880 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_utm), gtk_label_new(_("UTM")));
881 gtk_notebook_append_page(GTK_NOTEBOOK(cw.tabs), GTK_WIDGET(table_ll), gtk_label_new(_("Latitude/Longitude")));
882 gtk_box_pack_start ( dgbox, cw.tabs, TRUE, TRUE, 0 );
883
b7a0cc40
RN
884 GtkWidget *alpha_hbox = gtk_hbox_new ( FALSE, 0 );
885 // GTK3 => GtkWidget *alpha_scale = gtk_scale_new_with_range ( GTK_ORIENTATION_HORIZONTAL, 0, 255, 1 );
886 GtkWidget *alpha_scale = gtk_hscale_new_with_range ( 0, 255, 1 );
887 gtk_scale_set_digits ( GTK_SCALE(alpha_scale), 0 );
888 gtk_range_set_value ( GTK_RANGE(alpha_scale), vgl->alpha );
889 gtk_box_pack_start ( GTK_BOX(alpha_hbox), gtk_label_new(_("Alpha:")), TRUE, TRUE, 0 );
890 gtk_box_pack_start ( GTK_BOX(alpha_hbox), alpha_scale, TRUE, TRUE, 0 );
891 gtk_box_pack_start ( dgbox, alpha_hbox, TRUE, TRUE, 0 );
892
69c4125a
RN
893 vgl->cw = cw;
894
895 g_signal_connect ( G_OBJECT(vgl->cw.tabs), "switch-page", G_CALLBACK(switch_tab), vgl );
896 g_signal_connect ( G_OBJECT(calc_mpp_button), "clicked", G_CALLBACK(calculate_mpp_from_coords), vgl );
50a14534 897
92e8adf5 898 g_signal_connect_swapped ( G_OBJECT(wfp_button), "clicked", G_CALLBACK(georef_layer_dialog_load), &cw );
50a14534 899
535747e9
RN
900 if ( response_w )
901 gtk_widget_grab_focus ( response_w );
902
69c4125a
RN
903 gtk_widget_show_all ( dialog );
904
905 // Remember setting the notebook page must be done after the widget is visible.
906 gint page_num = 0;
907 if ( a_settings_get_integer ( VIK_SETTINGS_GEOREF_TAB, &page_num ) )
908 if ( page_num < 0 || page_num > 1 )
909 page_num = 0;
910 gtk_notebook_set_current_page ( GTK_NOTEBOOK(cw.tabs), page_num );
50a14534
EB
911
912 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
913 {
69c4125a
RN
914 align_coords ( vgl );
915
92e8adf5
RN
916 vgl->corner.easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.ce_spin) );
917 vgl->corner.northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.cn_spin) );
69c4125a
RN
918 vgl->corner.zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(cw.utm_zone_spin) );
919 const gchar *letter = gtk_entry_get_text ( GTK_ENTRY(cw.utm_letter_entry) );
920 if (*letter)
921 vgl->corner.letter = toupper(*letter);
92e8adf5
RN
922 vgl->mpp_easting = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.x_spin) );
923 vgl->mpp_northing = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(cw.y_spin) );
69c4125a
RN
924 vgl->ll_br = get_ll_br (vgl);
925 check_br_is_good_or_msg_user ( vgl );
926 if ( g_strcmp0 (vgl->image, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) ) != 0 )
50a14534 927 {
69c4125a 928 georef_layer_set_image ( vgl, vik_file_entry_get_filename(VIK_FILE_ENTRY(cw.imageentry)) );
f6d4661b 929 georef_layer_load_image ( vgl, VIK_VIEWPORT(vp), FALSE );
50a14534
EB
930 }
931
b7a0cc40
RN
932 vgl->alpha = (guint8) gtk_range_get_value ( GTK_RANGE(alpha_scale) );
933 if ( vgl->pixbuf && vgl->alpha < 255 )
934 vgl->pixbuf = ui_pixbuf_set_alpha ( vgl->pixbuf, vgl->alpha );
935 if ( vgl->scaled && vgl->alpha < 255 )
936 vgl->scaled = ui_pixbuf_set_alpha ( vgl->scaled, vgl->alpha );
937
69c4125a
RN
938 a_settings_set_integer ( VIK_SETTINGS_GEOREF_TAB, gtk_notebook_get_current_page(GTK_NOTEBOOK(cw.tabs)) );
939
50a14534
EB
940 gtk_widget_destroy ( GTK_WIDGET(dialog) );
941 return TRUE;
942 }
943 gtk_widget_destroy ( GTK_WIDGET(dialog) );
944 return FALSE;
945}
946
947static void georef_layer_zoom_to_fit ( gpointer vgl_vlp[2] )
948{
949 vik_viewport_set_xmpp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_easting );
950 vik_viewport_set_ympp ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1])), VIK_GEOREF_LAYER(vgl_vlp[0])->mpp_northing );
951 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
952}
953
954static void georef_layer_goto_center ( gpointer vgl_vlp[2] )
955{
956 VikGeorefLayer *vgl = VIK_GEOREF_LAYER ( vgl_vlp[0] );
957 VikViewport *vp = vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vgl_vlp[1]));
958 struct UTM utm;
959 VikCoord coord;
960
961 vik_coord_to_utm ( vik_viewport_get_center ( vp ), &utm );
962
963 utm.easting = vgl->corner.easting + (vgl->width * vgl->mpp_easting / 2); /* only an approximation */
964 utm.northing = vgl->corner.northing - (vgl->height * vgl->mpp_northing / 2);
965
966 vik_coord_load_from_utm ( &coord, vik_viewport_get_coord_mode ( vp ), &utm );
be5554c5 967 vik_viewport_set_center_coord ( vp, &coord, TRUE );
50a14534
EB
968
969 vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vgl_vlp[1]) );
970}
971
972static void georef_layer_add_menu_items ( VikGeorefLayer *vgl, GtkMenu *menu, gpointer vlp )
973{
974 static gpointer pass_along[2];
975 GtkWidget *item;
976 pass_along[0] = vgl;
977 pass_along[1] = vlp;
978
979 item = gtk_menu_item_new();
980 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
981 gtk_widget_show ( item );
982
d6de71f9
RN
983 /* Now with icons */
984 item = gtk_image_menu_item_new_with_mnemonic ( _("_Zoom to Fit Map") );
985 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
50a14534
EB
986 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_zoom_to_fit), pass_along );
987 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
988 gtk_widget_show ( item );
989
d6de71f9
RN
990 item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Map Center") );
991 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
50a14534
EB
992 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_goto_center), pass_along );
993 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
994 gtk_widget_show ( item );
995
d6de71f9
RN
996 item = gtk_image_menu_item_new_with_mnemonic ( _("_Export to World File") );
997 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
50a14534
EB
998 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(georef_layer_export_params), pass_along );
999 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1000 gtk_widget_show ( item );
1001}
1002
941aa6e9
AF
1003
1004static gpointer georef_layer_move_create ( VikWindow *vw, VikViewport *vvp)
1005{
1006 return vvp;
1007}
1008
50a14534
EB
1009static gboolean georef_layer_move_release ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1010{
941aa6e9
AF
1011 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1012 return FALSE;
1013
50a14534
EB
1014 if ( vgl->click_x != -1 )
1015 {
1016 vgl->corner.easting += (event->x - vgl->click_x) * vik_viewport_get_xmpp (vvp);
1017 vgl->corner.northing -= (event->y - vgl->click_y) * vik_viewport_get_ympp (vvp);
da121f9b 1018 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
1019 return TRUE;
1020 }
1021 return FALSE; /* I didn't move anything on this layer! */
1022}
1023
941aa6e9
AF
1024static gpointer georef_layer_zoom_create ( VikWindow *vw, VikViewport *vvp)
1025{
1026 return vvp;
1027}
1028
50a14534
EB
1029static gboolean georef_layer_zoom_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1030{
941aa6e9
AF
1031 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1032 return FALSE;
50a14534
EB
1033 if ( event->button == 1 )
1034 {
1035 if ( vgl->mpp_easting < (VIK_VIEWPORT_MAX_ZOOM / 1.05) && vgl->mpp_northing < (VIK_VIEWPORT_MAX_ZOOM / 1.05) )
1036 {
1037 vgl->mpp_easting *= 1.01;
1038 vgl->mpp_northing *= 1.01;
1039 }
1040 }
1041 else
1042 {
1043 if ( vgl->mpp_easting > (VIK_VIEWPORT_MIN_ZOOM * 1.05) && vgl->mpp_northing > (VIK_VIEWPORT_MIN_ZOOM * 1.05) )
1044 {
1045 vgl->mpp_easting /= 1.01;
1046 vgl->mpp_northing /= 1.01;
1047 }
1048 }
1049 vik_viewport_set_xmpp ( vvp, vgl->mpp_easting );
1050 vik_viewport_set_ympp ( vvp, vgl->mpp_northing );
da121f9b 1051 vik_layer_emit_update ( VIK_LAYER(vgl) );
50a14534
EB
1052 return TRUE;
1053}
1054
1055static gboolean georef_layer_move_press ( VikGeorefLayer *vgl, GdkEventButton *event, VikViewport *vvp )
1056{
941aa6e9
AF
1057 if (!vgl || vgl->vl.type != VIK_LAYER_GEOREF)
1058 return FALSE;
50a14534
EB
1059 vgl->click_x = event->x;
1060 vgl->click_y = event->y;
1061 return TRUE;
1062}