Subversion Repositories Projects

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
834 - 1
#!/usr/bin/perl
2
#!/usr/bin/perl -d:ptkdb
3
 
4
###############################################################################
5
#
6
# mkcockpit.pl -  MK Mission Cockpit - GUI
7
#
8
# Copyright (C) 2009  Rainer Walther  (rainerwalther-mail@web.de)
9
#
10
# Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
11
#
12
# Es ist Ihnen gestattet: 
13
#     * das Werk vervielfältigen, verbreiten und öffentlich zugänglich machen
14
#     * Abwandlungen bzw. Bearbeitungen des Inhaltes anfertigen
15
# 
16
# Zu den folgenden Bedingungen:
17
#     * Namensnennung.
18
#       Sie müssen den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
19
#     * Keine kommerzielle Nutzung.
20
#       Dieses Werk darf nicht für kommerzielle Zwecke verwendet werden.
21
#     * Weitergabe unter gleichen Bedingungen.
22
#       Wenn Sie den lizenzierten Inhalt bearbeiten oder in anderer Weise umgestalten,
23
#       verändern oder als Grundlage für einen anderen Inhalt verwenden,
24
#       dürfen Sie den neu entstandenen Inhalt nur unter Verwendung von Lizenzbedingungen
25
#       weitergeben, die mit denen dieses Lizenzvertrages identisch oder vergleichbar sind.
26
# 
27
# Im Falle einer Verbreitung müssen Sie anderen die Lizenzbedingungen, unter welche dieses
28
# Werk fällt, mitteilen. Am Einfachsten ist es, einen Link auf diese Seite einzubinden.
29
# 
30
# Jede der vorgenannten Bedingungen kann aufgehoben werden, sofern Sie die Einwilligung
31
# des Rechteinhabers dazu erhalten.
32
# 
33
# Diese Lizenz lässt die Urheberpersönlichkeitsrechte unberührt.
34
# 
35
# Weitere Details zur Lizenzbestimmung gibt es hier:
36
#   Kurzform: http://creativecommons.org/licenses/by-nc-sa/3.0/de/
37
#   Komplett: http://creativecommons.org/licenses/by-nc-sa/3.0/de/legalcode
38
#
39
###############################################################################
40
# 2009-02-20 0.0.1 rw created
41
# 2009-04-01 0.1.0 rw RC1
42
# 2009-04-16 0.1.1 rw Bugfix, ALT= average of airsensor and Sat
43
# 2009-05-14 0.2.0 rw Waypoint Player
44
# 2009-05-17 0.2.1 rw Cursor-Steuerung fuer WP-Player. Cmdline-Parameter "-geometry"
45
# 2009-07-18 0.2.2 rw DE/EN multinational
46
#                     Target-Balloon with Distance, Tolerance and Holdtime
47
#                     Fix footprint "Ausreiser"
48
#                     JPEG and PNG maps supported
49
#                     Player for KML Files
50
# 2009-07-26 0.2.3 rw System Messages Balloon
51
# 2009-07-31 0.2.4 rw ODO Kilometerzähler
52
#                     Enter WP-Number from Keyboard
53
#                     Random WP-Player (Waypoint and Map)
54
#                     Check Airfield Border
55
#                     Draw Calibration points on map
56
# 2009-08-08 0.2.5 rw KML Recorder
57
#                     Text to speech
58
#                     Subroutines moved to libmkcockpit.pl
59
#                     Timer moved to libmktimer.pl
60
#                     Start Scenarion configuration
61
#                     Battery capacity estimation
62
#                     Read map definition from maps/map.xml
63
# 2009-08-23 0.2.6 rw Tracking-Antenna Icon
64
#                     Show Fox only in Player-Pause mode
65
#                     POI heading control
66
#                     Display scale
67
#                     Measuring-tool on left mouse button
68
#                     Display Operation Radius Border
69
#                     Read map definition from KML file (GE import)
70
#                     Include of local *.pm changed
71
#                     Copy x/y/Lat/Lon to Clipboard when pressing left mouse button
72
#                     Calculate size of map image
73
#                     track.pl - Commandline parameter added for COM ports
74
#                     don't use local perl libs any more
75
# 2009-10-18 0.2.7 rw Mk-Simulator
76
#                     Start tracker at program start. Coldstart at MK-calibration
77
#                     COM Port >9; PortSetSkip config
78
#                     Reset Flight-Time and ODO when clicking on OSD-value
79
# 2009-10-25 0.3.0 rw NC 0.17
80
#                     Read/Write KopterTool WPL Waypoint list
81
#                     Cfg Optionmenues
82
# 2010-02-09 0.4.0 rw Canvas - Popup focus improvement
83
#                     bugfix "WP hinzufügen und senden" in classic mode
84
#                     Grid on canvas
85
#                     joystick and 3D-Mouse
86
#                     remove main window status line
87
#                     Event engine
88
#                     Serial Channel
89
#                     External Control
90
#                     Expo, Dualrate
91
#                     Player Pause move relative to MAP or MK
92
#                     Load plugin directory
93
#                     Current, UsedCapacity, Power added
94
#                     RETURN turns off External-Control + Serial Channel
95
# 2010-02-15 0.4.1 rw F-Keys for Event
96
# 2010-03-20 0.4.2 rw Maestro Servo Controller
97
# 2010-07-01 0.5.0 rw WP/POI adjustments for NC 0.19/0.20
98
#                     TTS system messages closer to current situation
99
#                     NC Hardware Error Codes
100
# 2010-09-09 0.5.1 rw Use exifTool
101
#                     rename map/map.pl --> libmapdef.pl
102
#                     Tracker start at motor start
103
#                     Start web browser (GeoMapTool)
104
#                     Change Map without program restart
105
#                     Support JPEG from geomaptool.de
106
# 2010-09-18 0.5.2 rw Compose Maps from Google/OSM Download
107
#                     North Arrow
108
#                     Heartbeat shown again
109
# 2010-10-04 0.5.3 rw Google Maps entfernt, wg. rechtlicher Bedenken
110
# 2010-10-16 0.5.4 rw speed controlled mode (SPD) with closed natural cubic spline
111
#                     Border check for KML and SPD
112
#                     WPT Capture
113
#                     Altitude control
114
#                     FctKeyToggle() added
115
# 2010-11-01 0.6.0 rw Bugfix: Target not reachable
116
#                     NC 0.21, DGPS
117
#
118
###############################################################################
119
 
120
$Version = "0.6.0 - 2010-11-01";
121
 
122
# change working directory to program path
123
my $Cwd = substr ($0, 0, rindex ($0, "mkcockpit.pl"));
124
chdir $Cwd;
125
 
126
# set path for local Perl libs
127
push @INC, $Cwd . "perl/lib";
128
 
129
use threads;            # http://search.cpan.org/~jdhedden/threads-1.72/threads.pm
130
                        # http://perldoc.perl.org/threads.html
131
use threads::shared;    # http://search.cpan.org/~jdhedden/threads-shared-1.28/shared.pm
132
use Thread::Queue;      # http://search.cpan.org/dist/Thread-Queue-2.11/lib/Thread/Queue.pm
133
use Tk;
134
use Tk::Balloon;
135
use Tk::Dialog;
136
use Tk::Notebook;
137
use Tk::JPEG;           # http://search.cpan.org/~srezic/Tk-804.028/JPEG/JPEG.pm
138
use Tk::PNG;            # http://search.cpan.org/~srezic/Tk-804.028/PNG/PNG.pm
139
use Tk::Tree;
140
use Math::Trig;
141
use Time::HiRes qw(usleep);  # http://search.cpan.org/~jhi/Time-HiRes-1.9719/HiRes.pm
142
use XML::Simple;             # http://search.cpan.org/dist/XML-Simple-2.18/lib/XML/Simple.pm
143
use Clipboard;               # http://search.cpan.org/~king/Clipboard-0.09/lib/Clipboard.pm
144
use Tk::BrowseEntry;         # http://search.cpan.org/~srezic/Tk-804.028/pod/BrowseEntry.pod
145
 
146
# Version setting
147
share (%Version);
148
$Version{'mkcockpit.pl'}  = $Version;
149
 
150
# Read configuration
151
$XmlConfigFile = "mkcockpit.xml";
152
$Cfg = XMLin($XmlConfigFile);
153
 
154
require "track.pl";        # Tracking antenna
155
require "mkcomm.pl";       # MK communication
156
require "logging.pl";      # CSV and GPX Logging
157
require "libmapdef.pl";    # Map definition
158
 
159
&MapDefLoad();             # Load the Maps in hash %Maps
160
 
161
require "libmap.pl";       # map subs
162
require "translate.pl";    # Übersetzungstable
163
require "tts.pl";          # Text to Speech
164
require "libmkcockpit.pl"; # Subroutines
165
require "libmksim.pl";     # MK Simulator
166
require "libcfgopt.pl";    # Option menu values
167
require "libmouse.pl";     # 3D Mouse
168
require "libjoystick.pl";  # joystick
169
 
170
# Commandline parameter
171
my %CmdLine = @ARGV;
172
 
173
# Aktuell gültige Karte
174
my %Map = %{$Maps{'Current'}};
175
 
176
# Canvas size - get image size
177
$MapSizeX  = $Map{'Size_X'};
178
$MapSizeY  = $Map{'Size_Y'};
179
 
180
# Thread fuer Kommunikation mit MK starten
181
# Output: %MkOsd, %MkTarget, %MkNcDebug, %Mk
182
# Input:  Thread-Queue: $MkSendQueue
183
$mk_thr = threads->create (\&MkCommLoop) -> detach();
184
 
185
# Start Logging Thread
186
$log_thr = threads->create (\&MkLogLoop) -> detach();
187
 
188
# Start TTS Thread
189
$tts_thr = threads->create (\&TtsLoop) -> detach();
190
 
191
# Start Antenna tracker
192
if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
193
    {
194
    $track_thr = threads->create (\&TrackAntennaGps)->detach();
195
    }
196
 
197
# 3D Mouse Thread
198
$mouse_thr = threads->create (\&Mouse3D) -> detach();
199
 
200
# Joystick Thread
201
$joystick_thr = threads->create (\&Joystick) -> detach();
202
 
203
#
204
# Player:
205
#    Waypoint-List:   @Waypoints
206
#    KML-Target-List: @KmlTargets
207
#
208
 
209
# Player state machine
210
$PlayerMode = 'Stop';       # Play, Stop, Pause, Home ...
211
$PlayerWptKmlMode = 'WPT';  # WPT, KML, SPD
212
$PlayerRandomMode = 'STD';  # STD, RND, MAP
213
$PlayerRecordMode = "";     # "", REC
214
$PlayerPauseMode  = "MAP";  # MAP, MK
215
$WpPlayerIndex = 0;
216
$WpPlayerHoldtime = -1;
217
$WpPlayerMapAlt = 5;        # Altitude WP MAP mode
218
$SpdPlayerTime = 0;         # SPD-Player Track time
219
$SpdPlayerIndex = 0;        # SPD-Player WP Index
220
$SpdPlayerTargetReached = 0;
221
@SplineCoeffX;              # Coefficients for spline
222
@SplineCoeffY;              # Coefficients for spline
223
$KmlPlayerIndex = 0;
224
$PlayerPause_Lat = "";      # coordinates for pause mode
225
$PlayerPause_Lon = "";
226
 
227
# Point Of Interest (POI)
228
my $Poi_x = $MapSizeX/2-50;
229
my $Poi_y = $MapSizeY/2 ;
230
($Poi_Lat, $Poi_Lon) = &MapXY2Gps($Poi_x + 24, $Poi_y + 48);
231
 
232
# POI from Map configuration
233
if ( $Map{'Poi_Lat'} ne ""  and  $Map{'Poi_Lon'} ne "" )
234
    {
235
    $Poi_Lat = $Map{'Poi_Lat'};
236
    $Poi_Lon = $Map{'Poi_Lon'};
237
    ($Poi_x, $Poi_y) = &MapGps2XY($Poi_Lat, $Poi_Lon);
238
    $Poi_x = $Poi_x - 24;
239
    $Poi_y = $Poi_y - 48;
240
    }
241
$Poi_Mode = 0;     # POI Mode off
242
$TxExtOn = 0;      # Tx External-Control/SerialChannel off
243
 
244
# Event configuration
245
my $XmlEventConfigFile = $Cfg->{'StartScenario'}->{'EventFile'} || "event/mkevent.xml";
246
if ( ! -f $XmlEventConfigFile )
247
    {
248
    $XmlEventConfigFile = "event/" . $XmlEventConfigFile;
249
    }
250
if ( -f $XmlEventConfigFile )
251
    {
252
    $Event = XMLin($XmlEventConfigFile);
253
    }
254
 
255
if ( scalar keys %{$Event} == 0 )
256
    {
257
    # create new dummy event, if no XML or XML is empty
258
    &EventInit("Dummy", $Event);
259
    }
260
 
261
my %EventStat;    # internal state of event maschine
262
 
263
 
264
# load user plugins
265
opendir DIR, "plugin";
266
my @Plugin = readdir DIR;
267
closedir DIR;
268
@Plugin = grep /\.pl$/, @Plugin;
269
foreach my $File (@Plugin)
270
    {
271
    require "plugin/$File";
272
    }
273
 
274
 
275
# Hauptfenster
276
$main = new MainWindow;
277
$main->title ("MK Mission Cockpit - Version $Version");
278
 
279
if ( $CmdLine{'-geometry'} ne "" )
280
    {
281
    $main->geometry( "$CmdLine{'-geometry'}" );
282
    }
283
 
284
# pattern for dashed lines
285
my $stipple_bits = [];
286
foreach my $b (1..8)
287
    {
288
    push @$stipple_bits, pack ('b8', '1' x $b . '.' x (8 - $b));
289
    $main->DefineBitmap("stipple$b" => 8, 1, $stipple_bits->[$b-1]);
290
    }
291
 
292
# Catch delete window event and exit
293
$main->protocol( 'WM_DELETE_WINDOW' => sub
294
    {
295
    &CbExit();
296
    });
297
 
298
# disable main window Key-Bindings for F10
299
$main->bind('all', '<Key-F10>', undef);
300
 
301
#-----------------------------------------------------------------
302
# Menu
303
#-----------------------------------------------------------------
304
 
305
# Menu bar
306
my $menu_bar = $main->Menu;
307
$main->optionAdd("*tearOff", "false");
308
$main->configure ('-menu' => $menu_bar);
309
 
310
my $menu_file = $menu_bar->cascade('-label' => $Translate{'File'});
311
    $menu_file->command('-label' => $Translate{'Preferences'},
312
                        '-command' => sub
313
        {
314
        # Reload Map directory
315
        &MapDefLoad();
316
        &Configure ($XmlConfigFile, $Cfg, "CONFIG");
317
        },
318
                       );
319
    $menu_file->command('-label' => $Translate{'ConfigEvent'},
320
                        '-command' => [\&Configure, $XmlEventConfigFile, $Event, "EVENT", ],
321
                       );
322
    if ( $Cfg->{'map2'}->{'ImageMagickInstalled'} =~ /y/i )
323
        {
324
        $menu_file->separator;
325
        $menu_file->command('-label' => $Translate{'ComposeOsmMap'},
326
                            '-command' => [\&MapCompose,],
327
                           );
328
        }
329
    $menu_file->separator;                                     
330
    $menu_file->command('-label' => $Translate{'GeoMapTool'},
331
                        '-command' => [\&StartBrowser, "http://www.geomaptool.de", ],
332
                       );
333
    $menu_file->separator;                                     
334
    $menu_file->command('-label' => $Translate{'Exit'},
335
                        '-command' => [\&CbExit ],
336
                        );
337
 
338
my $menu_debug = $menu_bar->cascade(-label => $Translate{'Debug'});
339
    $menu_debug->command('-label' => $Translate{'NcOsdDataset'},
340
                         '-command' => [\&DisplayHash, \%MkOsd, $Translate{'NcOsdDataset'}, "Display Refresh Heartbeat"],
341
                        );
342
    $menu_debug->command('-label' => $Translate{'NcTargetDataset'},
343
                         '-command' => [\&DisplayHash, \%MkTarget, $Translate{'NcTargetDataset'}, "Display Refresh Heartbeat"],
344
                        );
345
    $menu_debug->command('-label' => $Translate{'NcDebugDataset'},
346
                         '-command' => [\&DisplayHash, \%MkNcDebug, $Translate{'NcDebugDataset'}, "Display Refresh Heartbeat"],
347
                                        );             
348
    $menu_debug->command('-label' => $Translate{'NcOther'},
349
                         '-command' => [\&DisplayHash, \%Mk, $Translate{'NcOther'}, "Display Refresh Heartbeat"],
350
                                        );
351
    $menu_debug->command('-label' => $Translate{'TrackingDebugDataset'},
352
                         '-command' => [\&DisplayHash, \%MkTrack, $Translate{'TrackingDebugDataset'}, "Display Refresh Heartbeat"],
353
                        );
354
 
355
    $menu_debug->command('-label' => $Translate{'MapDebugDataset'},
356
                         '-command' => [\&DisplayHash, \%Map, $Translate{'MapDebugDataset'}, "Display"],
357
                        );
358
    $menu_debug->command('-label' => $Translate{'SystemDebug'},
359
                         '-command' => [\&DisplayHash, \%System, $Translate{'SystemDebug'}, "Display Refresh"],
360
                        );
361
    $menu_debug->separator;                                    
362
    $menu_debug->command('-label' => $Translate{'StickDebug'},
363
                         '-command' => [\&DisplayHash, \%Stick, $Translate{'StickDebug'}, "Display Refresh"],
364
                        );
365
    $menu_debug->command('-label' => $Translate{'SerialChannel'},
366
                         '-command' => [\&DisplayHash, \%MkSerialChannel, $Translate{'SerialChannel'}, "Display Refresh SerialChannel"],
367
                        );
368
    $menu_debug->command('-label' => $Translate{'ExternControl'},
369
                         '-command' => [\&DisplayHash, \%MkExternControl, $Translate{'ExternControl'}, "Display Refresh ExternControl"],
370
                        );
371
    $menu_debug->separator;                                    
372
    $menu_debug->command('-label' => $Translate{'MkDebugSim'},
373
                         '-command' => \&MkSim,
374
                        );
375
 
376
 
377
my $menu_help = $menu_bar->cascade(-label => $Translate{'Help'});
378
    $menu_help->command('-label' => 'Version',
379
                        '-command' => [\&DisplayHash, \%Version, $Translate{'Version'}, "Display"],
380
                       );
381
    $menu_help->separator;
382
    $menu_help->command('-label' => $Translate{'About'},
383
                        '-command' => sub
384
        {
385
        my $License = <<EOF;
386
Copyright (C) 2010  Rainer Walther (rainerwalther-mail\@web.de)
387
 
388
Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
389
 
390
See LICENSE.TXT
391
EOF
392
 
393
        my $DlgAbout = $frame_map->Dialog('-title' => $Translate{'AboutMissionCockpit'},
394
                                          '-text' => "$License",
395
                                          '-buttons' => ['OK'],
396
                                          '-bitmap' => 'info',
397
                                         );
398
        $DlgAbout->Show;
399
        });  
400
 
401
 
402
#-----------------------------------------------------------------
403
# Frames
404
#-----------------------------------------------------------------                        
405
 
406
#
407
# Frame: Map
408
#
409
 
410
$frame_map = $main->Frame( '-background' => 'lightgray',
411
                           '-relief' => 'sunken',
412
                           '-borderwidth' => 5,
413
                          ) -> pack('-side' => 'top',
414
                                    '-fill' => 'x',
415
                                    );
416
 
417
# Map Überschrift
418
$frame_map_top = $frame_map->Frame( -background => 'lightgray',
419
                                  ) -> pack( -side   => 'top',
420
                                             -anchor => 'w',
421
                                             -fill => 'x',
422
                                             -expand => 1,
423
                                           );
424
 
425
$map_top_label = $frame_map_top->Label (-text       => "$Translate{'Map'}: $Map{'Name'} ($Map{'File'})",
426
                                        -background => 'lightgray',
427
                                        -relief     => 'flat',
428
                                       ) -> pack( -side => 'left' );
429
 
430
 
431
# 10 placeholders for status texts in upper status line. Field update in libmktimer
432
for ($i=0; $i<10; $i++)
433
    {
434
    $map_status_top[$i] = $frame_map_top->Label ( -text       => "",
435
                                                  -background => 'lightgray',
436
                                                  -anchor     => 'e',
437
                                                ) -> pack (-side => 'right',
438
                                                           -anchor => 'e',
439
                                                           -padx  => 1,
440
                                                          );
441
    }
442
 
443
# Map Statuszeile
444
$map_status = $frame_map->Frame( -background => 'lightgray',
445
                               ) -> pack( -side   => 'bottom',
446
                                          -anchor => 'w',
447
                                          -fill   => 'x',
448
                                          -expand => 1,
449
                                        );
450
$map_status_line = $map_status->Label ( -text => $Translate{'StatusLine'},
451
                                        -background => 'lightgray',
452
                                       ) -> pack (-side   => 'left',
453
                                                  -anchor => 'w',
454
                                                  -expand => 1,
455
                                                  );
456
 
457
# 10 placeholders for event status in lower status line. Field update in libmktimer
458
for ($i=0; $i<10; $i++)
459
    {
460
    $map_status_event[$i] = $map_status->Label ( -text       => "",
461
                                                 -background => 'lightgray',
462
                                                 -anchor     => 'e',
463
                                               ) -> pack (-side => 'right',
464
                                                          -anchor => 'e',
465
                                                          -padx  => 1,
466
                                                         );
467
    }
468
 
469
#
470
# Map Canvas
471
#
472
&CanvasCreate();
473
 
474
 
475
# Balloon attached to Canvas
476
$map_balloon = $frame_map->Balloon('-statusbar' => $status_line, );
477
$map_balloon->attach($map_canvas,
478
                     '-balloonposition' => 'mouse',
479
                     '-state' => 'balloon',
480
                     '-msg' => { 'MK-Arrow'               => $Translate{'Balloon-MK-Arrow'},
481
                                 'MK-Home-Line'           => $Translate{'Balloon-MK-Home-Line'},
482
                                 'MK-Home-Dist'           => $Translate{'Balloon-MK-Home-Dist'},
483
                                 'MK-Target-Line'         => $Translate{'Balloon-MK-Target-Line' },
484
                                 'MK-Target-Dist'         => $Translate{'Balloon-MK-Target-Dist'},
485
                                 'MK-Speed'               => $Translate{'Balloon-MK-Speed'},
486
                                 'Map-Variometer'         => $Translate{'Balloon-Map-Variometer' },
487
                                 'Map-Variometer-Pointer' => $Translate{'Balloon-Map-Variometer-Pointer'},
488
                                 'Map-Variometer-Skala'   => $Translate{'Balloon-Map-Variometer-Pointer'},
489
                                 'Fox'                    => $Translate{'Balloon-Fox'},
490
                                 'Heartbeat'              => $Translate{'Balloon-Heartbeat'},
491
                                 'Satellite'              => $Translate{'Balloon-Satellite'},
492
                                 'Waypoint'               => $Translate{'Balloon-Waypoint'},
493
                                 'Map-Border'             => $Translate{'Balloon-Map-Border'},
494
                                 'Waypoint-Connector'     => $Translate{'Balloon-Waypoint-Connector'},
495
                                 'Wp-PlayPause'           => $Translate{'Balloon-Wp-PlayPause'},
496
                                 'Wp-Stop'                => $Translate{'Balloon-Wp-Stop'},
497
                                 'Wp-First'               => $Translate{'Balloon-Wp-First'},
498
                                 'Wp-Last'                => $Translate{'Balloon-Wp-Last'},
499
                                 'Wp-Next'                => $Translate{'Balloon-Wp-Next'},
500
                                 'Wp-Prev'                => $Translate{'Balloon-Wp-Prev'},
501
                                 'Wp-Home'                => $Translate{'Balloon-Wp-Home'},
502
                                 'Wp-WptKml'              => $Translate{'Balloon-Wp-WptKml'},
503
                                 'Wp-WptRandom'           => $Translate{'Balloon-Wp-WptRandom'},
504
                                 'Wp-Record'              => $Translate{'Balloon-Wp-Record'},
505
                                 'Track-Antenna'          => $Translate{'Balloon-TrackAntenna'},
506
                                 'POI'                    => $Translate{'Balloon-Poi'},
507
                               },
508
                    );
509
 
510
#                                       
511
# Mouse button 1
512
#
513
 
514
# Button 1 Press
515
$map_canvas->CanvasBind("<Button-1>", sub
516
    {
517
    # print coords in status line
518
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
519
    my ($Lat, $Lon) = &MapXY2Gps($x, $y);
520
 
521
    $map_status_line->configure ('-text' => "Lat: $Lat  Lon: $Lon     x: $x  y: $y");
522
 
523
    # save Coords and GPS-Pos for Button-Motion and Release
524
    $Button1_x = $x;
525
    $Button1_y = $y;
526
    $Button1_Lat = $Lat;
527
    $Button1_Lon = $Lon;
528
 
529
    # copy Pixel-Coordinates to Clipboard
530
    Clipboard->copy ("x=$x\r\n" . "y=$y\r\n" . "Lat=$Lat\r\n" . "Lon=$Lon\r\n");
531
    });
532
 
533
# Button 1 Motion
534
$map_canvas->CanvasBind("<Button1-Motion>", sub
535
    {
536
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
537
    my $id      = $map_canvas->find('withtag', 'current');
538
 
539
    # delete old measuring line
540
    $map_canvas->delete('Map-Measure');
541
 
542
    my @Tags = $map_canvas->gettags($id);
543
    if ( ( $Tags[0] eq "Map"  or $Tags[0] eq "Map-Border") and
544
         $x ne $Button1_x  and  $y ne $Button1_y )
545
        {
546
        # button moved on Map
547
 
548
        # draw new measuring line
549
        $map_canvas->createLine ( $Button1_x, $Button1_y, $x, $y,
550
                                  '-tags' => 'Map-Measure',
551
                                  '-arrow' => 'none',
552
                                  '-fill' => 'white',
553
                                  '-width' => 1,
554
                         );
555
 
556
        # update status line
557
        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
558
        my ($Dist, $Bearing) = &MapGpsTo($Button1_Lat, $Button1_Lon, $Lat, $Lon);
559
        $Dist = sprintf ("%.2f m", $Dist);
560
        $Bearing = sprintf ("%.2f degree", $Bearing);
561
 
562
        $map_status_line->configure ('-text' => "Dist: $Dist  Bearing: $Bearing");
563
        }
564
    });
565
 
566
# Button 1 Release
567
$map_canvas->CanvasBind("<Button1-ButtonRelease>", sub
568
    {
569
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
570
    my $id      = $map_canvas->find('withtag', 'current');
571
 
572
    # delete measuring line
573
    $map_canvas->delete('Map-Measure');
574
 
575
    my @Tags = $map_canvas->gettags($id);
576
    if ( ( $Tags[0] eq "Map"  or $Tags[0] eq "Map-Border") and
577
         $x ne $Button1_x  and  $y ne $Button1_y )
578
        {
579
        # button released on Map
580
 
581
        # update status line
582
        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
583
        my ($Dist, $Bearing) = &MapGpsTo($Button1_Lat, $Button1_Lon, $Lat, $Lon);
584
        $Dist = sprintf ("%.2f m", $Dist);
585
        $Bearing = sprintf ("%.2f degree", $Bearing);
586
 
587
        $map_status_line->configure ('-text' => "Dist: $Dist  Bearing: $Bearing");
588
        }
589
    });
590
 
591
 
592
# Mouse button 1 for Fox
593
my $FoxOldx = 0;
594
my $FoxOldy = 0;
595
my $FoxTime = time;
596
&FoxHide();   # Show only in Player-Pause Mode
597
 
598
# Pick Fox
599
$map_canvas->bind('Fox' => '<Button-1>' => sub
600
    {
601
    # prepare to move Fox
602
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
603
    $FoxOldx = $x;
604
    $FoxOldy = $y;
605
    $FoxTime = time;
606
    });
607
 
608
# Move Fox
609
$map_canvas->bind('Fox' => '<Button1-Motion>' => sub
610
    {
611
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
612
    my $id      = $map_canvas->find('withtag', 'current');
613
 
614
    $map_canvas->move($id => $x - $FoxOldx, $y - $FoxOldy);
615
    $FoxOldx = $x;
616
    $FoxOldy = $y;
617
 
618
    if ( time > $FoxTime )
619
        {
620
        # wenn in Bewegung Koordinaten nur 1/s senden
621
        my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
622
        $x = $x0 + ($x1 - $x0)/2;
623
        $y = $y1;
624
 
625
        ($PlayerPause_Lat, $PlayerPause_Lon) = &MapXY2Gps($x, $y);
626
        $FoxTime = time;
627
 
628
        $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $PlayerPause_Lat  Lon: $PlayerPause_Lon     x: $x  y: $y");
629
        }
630
    });
631
 
632
# Release Fox
633
$map_canvas->bind('Fox' => '<Button1-ButtonRelease>' => sub
634
    {
635
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
636
    my $id      = $map_canvas->find('withtag', 'current');
637
 
638
    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
639
    $x = $x0 + ($x1 - $x0)/2;
640
    $y = $y1;
641
 
642
    ($PlayerPause_Lat, $PlayerPause_Lon) = &MapXY2Gps($x, $y);
643
 
644
    # Show user that Waypoints in MK are cleared
645
    $WaypointsModified = 1;
646
    &WpRedrawLines();
647
 
648
    $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $PlayerPause_Lat  Lon: $PlayerPause_Lon     x: $x  y: $y");
649
    });
650
 
651
# Pick Waypoint
652
my $WpOldx;
653
my $WpOldy;
654
$map_canvas->bind('Waypoint' => '<Button-1>' => sub
655
    {
656
    # prepare to move
657
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
658
    $WpOldx = $x;
659
    $WpOldy = $y;
660
    });
661
 
662
# Move Waypoint
663
$map_canvas->bind('Waypoint' => '<Button1-Motion>' => sub
664
    {
665
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
666
    my $id      = $map_canvas->find('withtag', 'current');
667
 
668
    # move icon and Wp-Number
669
    my $WpIndex = &WpGetIndexFromId($id);
670
    if ( $WpIndex >= 0 )
671
        {
672
        # move Icon
673
        my $Tag = $Waypoints[$WpIndex]{'Tag'};
674
        $map_canvas->move($Tag => $x - $WpOldx, $y - $WpOldy);
675
 
676
        #
677
        # update WP-Connector, Spline polygon
678
        #
679
 
680
        # take coords from lower/middle icon position
681
        my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
682
        my $xi = $x0 + ($x1 - $x0)/2;
683
        my $yi = $y1;
684
 
685
        # Update WP-Array
686
        my ($Lat, $Lon) = &MapXY2Gps($xi, $yi);
687
        my $Wp = $Waypoints[$WpIndex];
688
        $Wp->{'MapX'} = $xi;
689
        $Wp->{'MapY'} = $yi;
690
        $Wp->{'_MapX_Rel'} = $xi / $MapSizeX;
691
        $Wp->{'_MapY_Rel'} = $yi / $MapSizeY;
692
        $Wp->{'Pos_Lat'} = $Lat;
693
        $Wp->{'Pos_Lon'} = $Lon;
694
 
695
        # redraw connector-lines
696
        &WpRedrawLines();
697
 
698
        # red connectors: Wp still have to be sent to MK
699
        $map_canvas->itemconfigure('Waypoint-Connector',
700
                                           '-fill' => $Cfg->{'mkcockpit'}->{'ColorWpResend'},
701
                                  );
702
        $WaypointsModified = 1;
703
        }
704
 
705
    $WpOldx = $x;
706
    $WpOldy = $y;
707
    });
708
 
709
# Release Wp
710
$map_canvas->bind('Waypoint' => '<Button1-ButtonRelease>' => sub
711
    {
712
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
713
    my $id      = $map_canvas->find('withtag', 'current');
714
 
715
    # take coords from lower/middle icon position
716
    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
717
    $x = $x0 + ($x1 - $x0)/2;
718
    $y = $y1;
719
 
720
    # update Waypoint-Array
721
    my $WpIndex = &WpGetIndexFromId($id);
722
    if ( $WpIndex >= 0 )
723
        {
724
        # got it: set new coords
725
 
726
        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
727
        my $Wp = $Waypoints[$WpIndex];
728
        $Wp->{'MapX'} = $x;
729
        $Wp->{'MapY'} = $y;
730
        $Wp->{'_MapX_Rel'} = $x / $MapSizeX;
731
        $Wp->{'_MapY_Rel'} = $y / $MapSizeY;
732
        $Wp->{'Pos_Lat'} = $Lat;
733
        $Wp->{'Pos_Lon'} = $Lon;
734
 
735
        # redraw connector-lines
736
        &WpRedrawLines();
737
 
738
        # red connectors: Wp still have to be sent to MK
739
        $map_canvas->itemconfigure('Waypoint-Connector',
740
                                   '-fill' => $Cfg->{'mkcockpit'}->{'ColorWpResend'},
741
                                  );
742
        $WaypointsModified = 1;
743
 
744
        my $WpNum = $WpIndex + 1;
745
        $map_status_line->configure ('-text' => "$Translate{'WpMoved'}: $WpNum -> Lat: $Lat  Lon: $Lon     x: $x  y: $y");
746
        }
747
    });
748
 
749
# Mouse button 1 for POI
750
my $PoiOldx = 0;
751
my $PoiOldy = 0;
752
&PoiHide();
753
 
754
# Pick POI
755
$map_canvas->bind('POI' => '<Button-1>' => sub
756
    {
757
    # prepare to move Icon
758
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
759
    $PoiOldx = $x;
760
    $PoiOldy = $y;
761
    });
762
 
763
# Move POI
764
$map_canvas->bind('POI' => '<Button1-Motion>' => sub
765
    {
766
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
767
    my $id      = $map_canvas->find('withtag', 'current');
768
 
769
    $map_canvas->move($id => $x - $PoiOldx, $y - $PoiOldy);
770
    $PoiOldx = $x;
771
    $PoiOldy = $y;
772
    });
773
 
774
# Release POI
775
$map_canvas->bind('POI' => '<Button1-ButtonRelease>' => sub
776
    {
777
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
778
    my $id      = $map_canvas->find('withtag', 'current');
779
 
780
    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
781
    $x = $x0 + ($x1 - $x0)/2;
782
    $y = $y1;
783
 
784
    ($Poi_Lat, $Poi_Lon) = &MapXY2Gps($x, $y);
785
 
786
    $map_status_line->configure ('-text' => "$Translate{'PoiMoved'}: ->   Lat: $Poi_Lat  Lon: $Poi_Lon     x: $x  y: $y");
787
    });
788
 
789
 
790
# Reset Flight time
791
$map_canvas->bind('MK-OSD-Tim-Value' => '<Button-1>' => sub
792
    {
793
    $MkFlyingTime = 0;
794
    });
795
 
796
# Reset ODO
797
$map_canvas->bind('MK-OSD-Odo-Value' => '<Button-1>' => sub
798
    {
799
    $OdoMeter = 0;
800
    });
801
 
802
 
803
#
804
# Mouse button 3 context menu
805
#
806
my $map_menu = $map_canvas->Menu('-tearoff' => 0,
807
                                 '-title' =>'None',
808
                                 '-menuitems' =>
809
    [
810
     [Button => $Translate{'WpAddAndSend'},  -command => sub
811
        {
812
        # send Wp to MK         
813
        my ($Lat, $Lon) = &MapXY2Gps($MapCanvasX, $MapCanvasY);
814
        &MkFlyTo ( -lat => $Lat,
815
                   -lon => $Lon,
816
                   -mode => "Waypoint",
817
                   -index => scalar @Waypoints,
818
                 );
819
 
820
        # Add Wp to Waypoints list
821
        &WpAdd (-lat => $Lat,
822
                -lon => $Lon,
823
                -x   => $MapCanvasX,
824
                -y   => $MapCanvasY,
825
               );
826
 
827
        if ( $PlayerWptKmlMode =~ /KML/i )
828
            {
829
            # switch player to Wpt mode and redraw waypoints
830
            &PlayerWpt();
831
            }
832
        else
833
            {
834
            &WpRedrawIcons();
835
            &WpRedrawLines();
836
            }
837
 
838
        $map_status_line->configure ('-text' => "$Translate{'WpSavedAndSent'} -> Lat: $Lat Lon: $Lon");
839
        }],
840
 
841
 
842
     [Button => $Translate{'WpProperties'},  -command => sub
843
        {
844
        # find Wp-Hash for selected icon/tag
845
        my $WpIndex = &WpGetIndexFromId($MapCanvasId);
846
        if ( $WpIndex >= 0 )
847
            {
848
            my $Wp = $Waypoints[$WpIndex];
849
            my $WpNum = $WpIndex + 1;
850
 
851
            &DisplayHash ($Wp, "$Translate{'WpProperties'} $WpNum", "Edit Waypoint Refresh");
852
 
853
            $map_status_line->configure ('-text' => "$Translate{'WpProperties'} $WpNum");
854
            }
855
        }],
856
 
857
     [Button => $Translate{'WpResendAll'},  -command => sub
858
        {
859
        &WpSendAll();
860
 
861
        $map_status_line->configure ('-text' => $Translate{'WpAllSent'});
862
        }],
863
 
864
      '',   # Separator
865
 
866
     [Button => $Translate{'WpLoadAndSend'},  -command => sub
867
        {
868
        my $WpFile = $main->getOpenFile('-defaultextension' => ".xml",
869
                                        '-filetypes'        =>
870
                                            [['Mission Cockpit',  '.xml' ],
871
                                             ['Mikrokopter Tool', '.wpl' ],
872
                                             ['All Files',     '*', ],
873
                                            ],
874
                                        '-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
875
                                        '-title' => $Translate{'WpLoad'},
876
                                       );
877
        if ( -f $WpFile )
878
            {
879
            &WpLoadFile ($WpFile);
880
 
881
            # send all Wp to MK
882
            &WpSendAll();
883
 
884
            # switch player to Wp mode and redraw waypoints
885
            $PlayerRandomMode  = 'STD';
886
            &PlayerWpt();
887
 
888
            $map_status_line->configure ('-text' => "$Translate{'WpLoadedAndSent'}: $WpFile");
889
            }
890
        }],    
891
 
892
     [Button => $Translate{'WpSave'},  -command => sub
893
        {
894
        my $WpFile = $main->getSaveFile('-defaultextension' => ".xml",
895
                                        '-filetypes'        =>
896
                                         [['Mission Cockpit',  '.xml' ],
897
                                          ['Mikrokopter Tool', '.wpl' ],
898
                                          ['All Files',     '*', ],
899
                                          ],
900
                                        '-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
901
                                        '-title' => $Translate{'WpSave'},
902
                                       );
903
 
904
        &WpSaveFile ($WpFile);
905
 
906
        $map_status_line->configure ('-text' => "$Translate{'WpSaved'}: $WpFile");
907
        }],
908
 
909
     '',   # Separator
910
 
911
     [Button => $Translate{'WpDelete'},  -command => sub
912
        {
913
        # find Wp-Hash for selected icon/tag
914
        my $WpIndex = &WpGetIndexFromId($MapCanvasId);
915
        if ( $WpIndex >= 0 )
916
            {
917
            &WpDelete ($WpIndex);
918
 
919
            # redraw connector-lines
920
            $WaypointsModified = 1;
921
            &WpRedrawLines();  
922
            &WpRedrawIcons();  # wg. Wp-Nummern
923
 
924
            my $WpNum = $WpIndex + 1;
925
            $map_status_line->configure ('-text' => "$Translate{'WpDeleted'}: $WpNum");
926
            }
927
        }],
928
 
929
     [Button => $Translate{'WpAllDeleteAndSend'},  -command => sub
930
        {
931
        &WpDeleteAll();
932
        &WpSendAll();
933
 
934
        $map_status_line->configure ('-text' => "$Translate{'WpAllDeleted'}: $WpIndex");
935
        }],
936
 
937
    '',   # Separator
938
 
939
     [Button => $Translate{'KmlLoadAndPlay'},  -command => sub
940
        {
941
        $KmlFile = $main->getOpenFile('-defaultextension' => ".kml",
942
                                     '-filetypes'        =>
943
                                         [['KML',           '.kml' ],
944
                                          ['All Files',     '*', ],
945
                                         ],
946
                                     '-initialdir' => $Cfg->{'waypoint'}->{'KmlDir'},
947
                                     '-title' => $Translate{'KmlLoad'},
948
                                    );
949
        if ( -f $KmlFile )
950
            {
951
            &KmlLoadFile($KmlFile);
952
 
953
            # switch player to KML mode and redraw track
954
            &PlayerKml();
955
 
956
            $map_status_line->configure ('-text' => "$Translate{'KmlLoaded'}: $KmlFile" );
957
            }
958
 
959
        }],
960
    ]
961
                                    );
962
$map_canvas->CanvasBind("<Button-3>" => [ sub
963
    {
964
    $map_canvas->focus;
965
    my($w, $x, $y) = @_;
966
    ($MapCanvasX, $MapCanvasY) = ($Tk::event->x, $Tk::event->y);
967
    $MapCanvasId = $map_canvas->find('withtag', 'current');
968
    $map_menu->post($x, $y);
969
    }, Ev('X'), Ev('Y') ] );
970
 
971
 
972
# Mouse bindings
973
$map_canvas->bind('Wp-PlayPause' => '<Button-1>' => \&CbPlayerPlayPause );
974
$map_canvas->bind('Wp-Next'      => '<Button-1>' => \&CbPlayerNext );
975
$map_canvas->bind('Wp-Prev'      => '<Button-1>' => \&CbPlayerPrev );
976
$map_canvas->bind('Wp-First'     => '<Button-1>' => \&CbPlayerFirst );
977
$map_canvas->bind('Wp-Last'      => '<Button-1>' => \&CbPlayerLast );
978
$map_canvas->bind('Wp-Home'      => '<Button-1>' => \&CbPlayerHome );
979
$map_canvas->bind('Wp-Stop'      => '<Button-1>' => \&CbPlayerStop );
980
$map_canvas->bind('Wp-WptKml'    => '<Button-1>' => \&CbPlayerWptKml );
981
$map_canvas->bind('Wp-WptRandom' => '<Button-1>' => \&CbPlayerWptRandom );
982
$map_canvas->bind('Wp-Record'    => '<Button-1>' => \&CbPlayerRecord );
983
 
984
 
985
# Focus Canvas, if any key pressed. Needed for the following key-bindings
986
my $bBindFocus = 0;
987
$main->bind('<Any-Enter>' => sub
988
    {
989
    if ($bBindFocus == 0)
990
        {
991
        # focus only once. Verhindern vom canvas-popup, wenn Config-Dialog aktiv ist.
992
        # funktioniert so, habe aber keine Ahnung warum
993
        $map_canvas->Tk::focus;
994
        $bBindFocus = 1;
995
        }
996
    });
997
 
998
 
999
# Disable default arrow-key bindings on canvas
1000
$main->bind('Tk::Canvas',"<$_>",undef)for qw /Left Right Up Down/;
1001
 
1002
# keyboard bindings
1003
$map_canvas->Tk::bind( '<Key-space>' , \&CbPlayerPlayPause );
1004
$map_canvas->Tk::bind( '<Key-n>'     , \&CbPlayerNext );
1005
$map_canvas->Tk::bind( '<Key-p>'     , \&CbPlayerPrev );
1006
$map_canvas->Tk::bind( '<Key-f>'     , \&CbPlayerFirst );
1007
$map_canvas->Tk::bind( '<Key-l>'     , \&CbPlayerLast );
1008
$map_canvas->Tk::bind( '<Key-h>'     , \&CbPlayerHome );
1009
$map_canvas->Tk::bind( '<Key-s>'     , \&CbPlayerStop );
1010
$map_canvas->Tk::bind( '<Key-w>'     , \&CbPlayerWptKml );
1011
$map_canvas->Tk::bind( '<Key-k>'     , \&CbPlayerWptKmlRev );
1012
$map_canvas->Tk::bind( '<Key-r>'     , \&CbPlayerWptRandom );
1013
$map_canvas->Tk::bind( '<Key-a>'     , \&CbPlayerRecord );
1014
$map_canvas->Tk::bind( '<Key-m>'     , \&CbPlayerMute );
1015
$map_canvas->Tk::bind( '<Key-v>'     , \&CbPoi );
1016
$map_canvas->Tk::bind( '<Key-g>'     , \&CbGrid );
1017
$map_canvas->Tk::bind( '<Key-x>'     , \&CbPlayerPauseMode );
1018
$map_canvas->Tk::bind( '<Key-c>'     , \&CbWptCapture );
1019
$map_canvas->Tk::bind( '<Key-0>'     , [\&CbPlayerNum, "0"] );
1020
$map_canvas->Tk::bind( '<Key-1>'     , [\&CbPlayerNum, "1"] );
1021
$map_canvas->Tk::bind( '<Key-2>'     , [\&CbPlayerNum, "2"] );
1022
$map_canvas->Tk::bind( '<Key-3>'     , [\&CbPlayerNum, "3"] );
1023
$map_canvas->Tk::bind( '<Key-4>'     , [\&CbPlayerNum, "4"] );
1024
$map_canvas->Tk::bind( '<Key-5>'     , [\&CbPlayerNum, "5"] );
1025
$map_canvas->Tk::bind( '<Key-6>'     , [\&CbPlayerNum, "6"] );
1026
$map_canvas->Tk::bind( '<Key-7>'     , [\&CbPlayerNum, "7"] );
1027
$map_canvas->Tk::bind( '<Key-8>'     , [\&CbPlayerNum, "8"] );
1028
$map_canvas->Tk::bind( '<Key-9>'     , [\&CbPlayerNum, "9"] );
1029
$map_canvas->Tk::bind( '<Key-Left>'  , [\&CbPlayerMove, -1,  0] );
1030
$map_canvas->Tk::bind( '<Key-Right>' , [\&CbPlayerMove,  1,  0] );
1031
$map_canvas->Tk::bind( '<Key-Up>'    , [\&CbPlayerMove,  0,  1] );
1032
$map_canvas->Tk::bind( '<Key-Down>'  , [\&CbPlayerMove,  0, -1] );
1033
$map_canvas->Tk::bind( '<Key-Escape>', \&CbExit );
1034
$map_canvas->Tk::bind( '<Key-Return>', \&CbTxOnOff );
1035
 
1036
# Fct-Keys F1 .. F12
1037
for ($i=1; $i <= 12; $i++)
1038
    {
1039
    $map_canvas->Tk::bind( "<KeyPress-F$i>",   [\&CbFctKeyPress,   "$i"] );
1040
    $map_canvas->Tk::bind( "<KeyRelease-F$i>", [\&CbFctKeyRelease, "$i"] );
1041
    }
1042
$Stick{'FctKey'} = 0;
1043
$Stick{'FctKeyToggle'} = 0;
1044
 
1045
#
1046
# Load Start Scenario
1047
#
1048
 
1049
# Waypoint file
1050
my $CfgVal = $Cfg->{'StartScenario'}->{'WpFile'};
1051
if ( ! -f $CfgVal )
1052
    {
1053
    $CfgVal = $Cfg->{'waypoint'}->{'WpDir'} . "/" . $Cfg->{'StartScenario'}->{'WpFile'};
1054
    }
1055
if ( -f $CfgVal )
1056
    {
1057
    &WpLoadFile($CfgVal);
1058
 
1059
    # send all Wp to MK
1060
    &WpSendAll();
1061
    }
1062
 
1063
# KML file
1064
my $CfgVal = $Cfg->{'StartScenario'}->{'KmlFile'};
1065
if ( ! -f $CfgVal )
1066
    {
1067
    $CfgVal = $Cfg->{'waypoint'}->{'KmlDir'} . "/" . $Cfg->{'StartScenario'}->{'KmlFile'};
1068
    }
1069
if ( -f $CfgVal )
1070
    {
1071
    &KmlLoadFile($CfgVal);
1072
    }
1073
 
1074
# PLayer Mode
1075
my $CfgVal  = $Cfg->{'StartScenario'}->{'PlayerMode'};
1076
if ( $CfgVal =~ /Play/i )  { &PlayerPlay(); }
1077
if ( $CfgVal =~ /Pause/i ) { &PlayerPause(); }
1078
if ( $CfgVal =~ /Home/i )  { &PlayerHome(); }
1079
if ( $CfgVal =~ /Stop/i )  { &PlayerStop(); }
1080
 
1081
# Player Random Mode
1082
my $CfgVal  = $Cfg->{'StartScenario'}->{'PlayerRandomMode'};
1083
if ( $CfgVal eq "STD" ) { &PlayerRandomStd(); }
1084
if ( $CfgVal eq "RND" ) { &PlayerRandomRnd(); }
1085
if ( $CfgVal eq "MAP" ) { &PlayerRandomMap(); }
1086
 
1087
# PLayer Wpt/Spd/Kml Mode
1088
my $CfgVal  = $Cfg->{'StartScenario'}->{'PlayerWptKmlMode'};
1089
if ( $CfgVal eq "WPT" )  { &PlayerWpt(); }
1090
if ( $CfgVal eq "KML" )  { &PlayerKml(); }
1091
if ( $CfgVal eq "SPD" )  { &PlayerSpd(); }
1092
 
1093
# PLayer Pause Mode
1094
my $CfgVal  = $Cfg->{'StartScenario'}->{'PlayerPauseMode'};
1095
if ( $CfgVal eq "MAP" )  { &PlayerPauseMode("MAP"); }
1096
if ( $CfgVal eq "MK" )   { &PlayerPauseMode("MK"); }
1097
 
1098
# Audio TTS Mute
1099
my $CfgVal  = $Cfg->{'StartScenario'}->{'AudioMute'};
1100
if ( $CfgVal =~ /y/i )
1101
    {
1102
    $TtsMute = 1;    
1103
    }
1104
 
1105
# External-Contorl/Serial Channel Tx On/Off
1106
my $CfgVal  = $Cfg->{'StartScenario'}->{'TxExtOn'};
1107
if ( $CfgVal =~ /y/i )
1108
    {
1109
    $TxExtOn = 1;    
1110
    }
1111
 
1112
#
1113
# Timer
1114
#
1115
require "libmktimer.pl";
1116
 
1117
MainLoop();   # should never end
1118
 
1119
 
1120
#
1121
# Canvas handling
1122
# 
1123
 
1124
# Create map canvas
1125
sub CanvasCreate()
1126
    {
1127
    if ( defined $map_canvas )
1128
        {
1129
        # update size
1130
        $map_canvas->configure ('-width' => $MapSizeX,
1131
                                '-height' => $MapSizeY,
1132
                               );
1133
        }
1134
    else
1135
        {
1136
        # create new
1137
        $map_canvas = $frame_map->Canvas( '-width'  => $MapSizeX,
1138
                                          '-height' => $MapSizeY,
1139
                                          '-cursor' => 'cross',
1140
                                        ) -> pack();
1141
        }
1142
 
1143
    # Images and Icons on canvas
1144
    my @Icons = (
1145
                # Image             Tag              File                                       Pos_x            Pos_y
1146
                'Map',              'Map',           "$Cfg->{'map'}->{'MapDir'}/$Map{'File'}",  0,               0,
1147
                'HeartbeatSmall',   'HeartbeatSmall',"$Cfg->{'mkcockpit'}->{'IconHeartSmall'}", $MapSizeX/4-10,  -100,
1148
                'HeartbeatLarge',   'HeartbeatLarge',"$Cfg->{'mkcockpit'}->{'IconHeartLarge'}", $MapSizeX/4-10,  -150,
1149
                'Heartbeat',        'Heartbeat',     "$Cfg->{'mkcockpit'}->{'IconHeartSmall'}", $MapSizeX/4-10,  10,
1150
                'Satellite-Photo',  'Satellite',     "$Cfg->{'mkcockpit'}->{'IconSatellite'}",  $MapSizeX/4-10,  -100,
1151
                'Antenna-Photo',    'Track-Antenna', "$Cfg->{'track'}->{'IconAntenna'}",        0,               -50,
1152
                'POI-Photo',        'POI'          , "$Cfg->{'mkcockpit'}->{'IconPoi'}",        $Poi_x,          $Poi_y,
1153
                'Waypoint-Photo',   'Waypoint',      "$Cfg->{'mkcockpit'}->{'IconWaypoint'}",   0,               -150,
1154
                'Target-Photo',     'Target',        "$Cfg->{'mkcockpit'}->{'IconTarget'}",     0,               -100,
1155
                'Fox-Photo',        'Fox',           "$Cfg->{'mkcockpit'}->{'IconFox'}",        $MapSizeX/2-100, $MapSizeY/2,
1156
                'WpPlay-Foto',      'Wp-PlayPause',  "$Cfg->{'waypoint'}->{'IconPlay'}",        $MapSizeX/2+150, $MapSizeY-48,
1157
                'WpPause-Foto',     'Wp-PlayPause',  "$Cfg->{'waypoint'}->{'IconPause'}",       $MapSizeX/2+150, -100,
1158
                'WpStop-Foto',      'Wp-Stop',       "$Cfg->{'waypoint'}->{'IconStop'}",        $MapSizeX/2+200, $MapSizeY-48,
1159
                'WpNext-Foto',      'Wp-Next',       "$Cfg->{'waypoint'}->{'IconNext'}",        $MapSizeX/2+50,  $MapSizeY-48,
1160
                'WpPrev-Foto',      'Wp-Prev',       "$Cfg->{'waypoint'}->{'IconPrev'}",        $MapSizeX/2,     $MapSizeY-48,
1161
                'WpFirst-Foto',     'Wp-First',      "$Cfg->{'waypoint'}->{'IconFirst'}",       $MapSizeX/2-50,  $MapSizeY-48,
1162
                'WpLast-Foto',      'Wp-Last',       "$Cfg->{'waypoint'}->{'IconLast'}",        $MapSizeX/2+100, $MapSizeY-48,
1163
                'WpHome-Foto',      'Wp-Home',       "$Cfg->{'waypoint'}->{'IconHome'}",        $MapSizeX/2-100, $MapSizeY-48,
1164
                'WpRecord-Foto',    'Wp-Record',     "$Cfg->{'waypoint'}->{'IconRecord'}",      $MapSizeX/2-150, $MapSizeY-48,
1165
                'WpRandomOff-Foto', 'Wp-WptRandom',  "$Cfg->{'waypoint'}->{'IconRandomOff'}",   $MapSizeX/2-200, -100,
1166
                'WpRandomOn-Foto',  'Wp-WptRandom',  "$Cfg->{'waypoint'}->{'IconRandomOn'}",    $MapSizeX/2-200, $MapSizeY-48,
1167
                'WpRandomMap-Foto', 'Wp-WptRandom',  "$Cfg->{'waypoint'}->{'IconRandomMap'}",   $MapSizeX/2-200, -100,
1168
                'WpWpt-Foto',       'Wp-WptKml',     "$Cfg->{'waypoint'}->{'IconWpt'}",         $MapSizeX/2-250, $MapSizeY-48,
1169
                'WpKml-Foto',       'Wp-WptKml',     "$Cfg->{'waypoint'}->{'IconKml'}",         $MapSizeX/2-250, -100 ,
1170
                'WpSpd-Foto',       'Wp-WptKml',     "$Cfg->{'waypoint'}->{'IconSpd'}",         $MapSizeX/2-250, -100 ,
1171
                );
1172
    my $i = 0;
1173
    for $Icon (0 .. $#Icons/5)
1174
        {
1175
        my $Image =  $Icons[$i++];
1176
        my $Tag =    $Icons[$i++];
1177
        my $File =   $Icons[$i++];
1178
        my $Pos_x =  $Icons[$i++];
1179
        my $Pos_y =  $Icons[$i++];
1180
 
1181
        $map_canvas->Photo( $Image,
1182
                            -file => $File,
1183
                          );
1184
 
1185
        $map_canvas->delete($Tag);
1186
        $map_canvas->createImage( $Pos_x, $Pos_y,
1187
                                  -tags   => $Tag,
1188
                                  -anchor => 'nw',
1189
                                  -image  => $Image,
1190
                                );
1191
        }
1192
 
1193
    # Calibration Points
1194
    $map_canvas->delete('Calibration');
1195
    $map_canvas->createLine ( $Map{'P1_x'}-8, $Map{'P1_y'},
1196
                              $Map{'P1_x'}+8, $Map{'P1_y'},
1197
                              $Map{'P1_x'},   $Map{'P1_y'},
1198
                              $Map{'P1_x'},   $Map{'P1_y'}-8,
1199
                              $Map{'P1_x'},   $Map{'P1_y'}+8,
1200
                              '-tags'  => 'Calibration',
1201
                              '-arrow' => 'none',
1202
                              '-fill'  => 'red',
1203
                              '-width' => 1,
1204
                             );
1205
    $map_canvas->createLine ( $Map{'P2_x'}-8, $Map{'P2_y'},
1206
                              $Map{'P2_x'}+8, $Map{'P2_y'},
1207
                              $Map{'P2_x'},   $Map{'P2_y'},
1208
                              $Map{'P2_x'},   $Map{'P2_y'}-8,
1209
                              $Map{'P2_x'},   $Map{'P2_y'}+8,
1210
                              '-tags'  => 'Calibration',
1211
                              '-arrow' => 'none',
1212
                              '-fill'  => 'red',
1213
                              '-width' => 1,
1214
                             );
1215
 
1216
    # display scale on canvas
1217
    my $x1 = $MapSizeX/2 +280;
1218
    my $x2 = $MapSizeX -30;
1219
    my $y1 = $MapSizeY - 20;
1220
    my $y2 = $MapSizeY - 15;
1221
    if ( $x2 - $x1 > 150 )
1222
        {
1223
        $x1 = $x2 - 150;
1224
        }
1225
 
1226
    $map_canvas->delete('Scale');
1227
    $map_canvas->createLine ( $x1, $y1,
1228
                              $x1, $y2,
1229
                              $x2, $y2,
1230
                              $x2, $y1,
1231
                              '-tags'  => 'Scale',
1232
                              '-arrow' => 'none',
1233
                              '-fill'  => 'red',
1234
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorScale'} || 'white',
1235
                              '-width' => 1,
1236
                              );
1237
 
1238
    my ($Lat1, $Lon1) = &MapXY2Gps($x1, $y1);
1239
    my ($Lat2, $Lon2) = &MapXY2Gps($x2, $y2);
1240
    my ($Dist, $Bearing) = &MapGpsTo($Lat1, $Lon1, $Lat2, $Lon2 );
1241
    $Dist = sprintf ("%.2f m", $Dist);
1242
    $map_canvas->delete('Scale-Text');
1243
    $map_canvas->createText ( $x1 + ($x2 - $x1)/2 - 20, $y1 - ($y2 - $y1)/2,
1244
                              '-tags' => 'Scale-Text',
1245
                              '-text' => $Dist,
1246
                              '-anchor' => 'w',
1247
                              '-font' => '-*-Arial-Bold-R-Normal--*-120-*',
1248
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorScale'} || 'white',
1249
                              );
1250
 
1251
    # North arrow above scale
1252
    $NorthArrowLen = 25;
1253
    my $x = $x1 + ($x2 - $x1)/2;     # x1, x2 from scale abowe
1254
    my $y = $y1 - $NorthArrowLen/2 - 10;
1255
 
1256
    my $Angle = &MapAngel();
1257
    my $dx = cos (deg2rad $Angle) * ($NorthArrowLen/2);
1258
    my $dy = sin (deg2rad $Angle) * ($NorthArrowLen/2);
1259
    my $x0 = $x - $dx;
1260
    my $y0 = $y + $dy;
1261
    my $x1 = $x + $dx;
1262
    my $y1 = $y - $dy;
1263
    $map_canvas->delete('North-Arrow');
1264
    $map_canvas->createLine ( $x0, $y0, $x1, $y1,
1265
                              '-tags' => 'North-Arrow',
1266
                              '-arrow' => 'last',
1267
                              '-arrowshape' => [15, 15, 5 ],
1268
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorScale'} || 'white',
1269
                              '-width' => 4,
1270
                             );
1271
    $map_canvas->createOval ( $x-$NorthArrowLen/2, $y-$NorthArrowLen/2, $x+$NorthArrowLen/2, $y+$NorthArrowLen/2,
1272
                              '-tags'   => 'North-Arrow',
1273
                              '-outline' => 'white',
1274
                              '-width' => 1,
1275
                            );
1276
 
1277
    # border polygon
1278
    $map_canvas->delete('Map-Border');
1279
    $map_canvas->createPolygon( @Map{'Border'},
1280
                               '-tags' => 'Map-Border',
1281
                               '-fill' => '',
1282
                               '-outline' => $Cfg->{'mkcockpit'}->{'ColorAirfield'}, '-width' => 2,
1283
                              );
1284
    $map_canvas->raise('Map-Border', 'Map');  # Border above Map
1285
 
1286
 
1287
    #
1288
    # dynamic objecs on canvas
1289
    #
1290
 
1291
    # current MK position on canvas
1292
    $MkPos_x = $MapSizeX/2;
1293
    $MkPos_y = $MapSizeY/2;
1294
 
1295
    # Line from MK to Home
1296
    $map_canvas->delete('MK-Home-Line');
1297
    $map_canvas->createLine ( $MapSizeX/2, $MapSizeY/2, $MapSizeX/2, $MapSizeY/2,
1298
                              '-tags' => 'MK-Home-Line',
1299
                              '-arrow' => 'none',
1300
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeLine'},
1301
                              '-width' => 3,
1302
                             );
1303
 
1304
    # Text Entfernung positioniert an der Home-Linie
1305
    $map_canvas->delete('MK-Home-Dist');
1306
    $map_canvas->createText ( $MapSizeX/2 + 8, $MapSizeY/2 - 8,
1307
                              '-tags' => 'MK-Home-Dist',
1308
                              '-text' => '0 m',
1309
                              '-anchor' => 'w',
1310
                              '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
1311
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeDist'},
1312
                              );
1313
 
1314
    # Line from MK to Target, draw invisible out of sight
1315
    $map_canvas->delete('MK-Target-Line');
1316
    $map_canvas->createLine ( 0, -100, 0, -100,
1317
                              '-tags' => 'MK-Target-Line',
1318
                              '-arrow' => 'none',
1319
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetLine'},
1320
                              '-width' => 3,
1321
                             );
1322
 
1323
    # Text Entfernung positioniert an der Target-Linie
1324
    $map_canvas->delete('MK-Target-Dist');
1325
    $map_canvas->createText ( 0, -100,
1326
                              '-tags' => 'MK-Target-Dist',
1327
                              '-text' => '0 m',
1328
                              '-anchor' => 'w',
1329
                              '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
1330
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetDist'},
1331
                              );
1332
 
1333
    # Line from MK to POI, draw invisible out of sight
1334
    $map_canvas->delete('MK-POI-Line');
1335
    $map_canvas->createLine ( 0, -200, 0, -200,
1336
                              '-tags' => 'MK-POI-Line',
1337
                              '-arrow' => 'none',
1338
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorPoiLine'},
1339
                              '-stipple' => "stipple4",
1340
                              '-width' => 1,
1341
                             );
1342
    $map_canvas->lower('MK-POI-Line', 'Target');
1343
 
1344
    # MK Geschwindigkeits-Vektor
1345
    $MapMkSpeedLen = 60;    # Länge Speed-Zeiger
1346
    my $x0 = $MapSizeX/2;
1347
    my $y0 = $MapSizeY/2;
1348
    my $x1 = $MapSizeX/2;
1349
    my $y1 = $MapSizeY/2 - $MapMkSpeedLen;
1350
    $map_canvas->delete('MK-Speed');
1351
    $map_canvas->createLine ( $x0, $y0, $x1, $y1,
1352
                              '-tags' => 'MK-Speed',
1353
                              '-arrow' => 'last',
1354
                              '-arrowshape' => [10, 10, 3 ],
1355
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorSpeedVector'},
1356
                              '-width' => 4,
1357
                             );
1358
 
1359
    # MK als Pfeilspitze einer Linie darstellen
1360
    $MapMkLen = 25;
1361
    my $x0 = $MapSizeX/2;
1362
    my $y0 = $MapSizeY/2 + $MapMkLen/2;
1363
    my $x1 = $MapSizeX/2;
1364
    my $y1 = $MapSizeY/2 - $MapMkLen/2;
1365
    $map_canvas->delete('MK-Arrow');
1366
    $map_canvas->createLine ( $x0, $y0, $x1, $y1,
1367
                              '-tags' => 'MK-Arrow',
1368
                              '-arrow' => 'last',
1369
                              '-arrowshape' => [25, 30, 10 ],
1370
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorMkSatNo'},
1371
                              '-width' => 1
1372
                             );
1373
 
1374
    # OSD Texte auf Karte anzeigen
1375
    my @Texts = (
1376
                # Tag                 Text         Pos_x           Pos_y  Font
1377
                'MK-OSD-Tim-Label',   "TIM",       $MapSizeX/2 + 30,  20, '-*-Arial-Bold-R-Normal--*-150-*',
1378
                'MK-OSD-Tim-Value',   "00:00",     $MapSizeX/2 + 80,  20, '-*-Arial-Bold-R-Normal--*-270-*',
1379
                'MK-OSD-Bat-Label',   "BAT",       $MapSizeX/2 + 30,  50, '-*-Arial-Bold-R-Normal--*-150-*',
1380
                'MK-OSD-Bat-Value',   "0.0 V",     $MapSizeX/2 + 80,  50, '-*-Arial-Bold-R-Normal--*-270-*',
1381
                'MK-OSD-Cap-Label',   "CAP",       $MapSizeX/2 - 150, 20, '-*-Arial-Bold-R-Normal--*-150-*',
1382
                'MK-OSD-Cap-Value',   "0.00 Ah",   $MapSizeX/2 - 100, 20, '-*-Arial-Bold-R-Normal--*-270-*',
1383
                'MK-OSD-Cur-Label',   "CUR",       $MapSizeX/2 - 150, 50, '-*-Arial-Bold-R-Normal--*-150-*',
1384
                'MK-OSD-Cur-Value',   "0.0 A",     $MapSizeX/2 - 100, 50, '-*-Arial-Bold-R-Normal--*-270-*',
1385
                'MK-OSD-Pow-Label',   "POW",       $MapSizeX/2 - 150, 80, '-*-Arial-Bold-R-Normal--*-150-*',
1386
                'MK-OSD-Pow-Value',   "0.0 W",     $MapSizeX/2 - 100, 80, '-*-Arial-Bold-R-Normal--*-270-*',
1387
                'MK-OSD-Spd-Label',   "SPD",       10,                20, '-*-Arial-Bold-R-Normal--*-150-*',
1388
                'MK-OSD-Spd-Value',   "0.0 km/h",  60,                20, '-*-Arial-Bold-R-Normal--*-270-*',
1389
                'MK-OSD-Alt-Label',   "ALT",       10,                50, '-*-Arial-Bold-R-Normal--*-150-*',
1390
                'MK-OSD-Alt-Value',   "0 m",       60,                50, '-*-Arial-Bold-R-Normal--*-270-*',
1391
                'MK-OSD-Odo-Label',   "ODO",       10,                80, '-*-Arial-Bold-R-Normal--*-150-*',
1392
                'MK-OSD-Odo-Value',   "0.000 km",  60,                80, '-*-Arial-Bold-R-Normal--*-270-*',
1393
                'MK-OSD-Sat-Label',   "SAT",       $MapSizeX - 230,   20, '-*-Arial-Bold-R-Normal--*-150-*',
1394
                'MK-OSD-Sat-Value',   "No GPS",    $MapSizeX - 180,   20, '-*-Arial-Bold-R-Normal--*-270-*',
1395
                'MK-OSD-Wp-Label',    "WPT",       $MapSizeX - 230,   50, '-*-Arial-Bold-R-Normal--*-150-*',
1396
                'MK-OSD-Wp-Value',    "0 / 0",     $MapSizeX - 180,   50, '-*-Arial-Bold-R-Normal--*-270-*',
1397
                'MK-OSD-Mode-Label',  "MOD",       $MapSizeX - 230,   80, '-*-Arial-Bold-R-Normal--*-150-*',
1398
                'MK-OSD-Mode-Value',  "",          $MapSizeX - 180,   80, '-*-Arial-Bold-R-Normal--*-270-*',
1399
                'MK-OSD-Rec-Value',   "",          $MapSizeX - 180,  110, '-*-Arial-Bold-R-Normal--*-200-*',
1400
                );
1401
    my $i = 0;
1402
    for $Text (0 .. $#Texts/5)
1403
        {
1404
        my $Tag =   $Texts[$i++];
1405
        my $Text =  $Texts[$i++];
1406
        my $Pos_x = $Texts[$i++];
1407
        my $Pos_y = $Texts[$i++];
1408
        my $Font =  $Texts[$i++];
1409
 
1410
        $map_canvas->delete($Tag);
1411
        $map_canvas->createText ( $Pos_x, $Pos_y,
1412
                                  '-tags' => $Tag,
1413
                                  '-text' => $Text,
1414
                                  '-font' => $Font,
1415
                                  '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
1416
                                  '-anchor' => 'w',
1417
                                 );
1418
        }
1419
 
1420
 
1421
    # Variometer on canvas
1422
    $map_canvas->delete('Map-Variometer-Skala');
1423
 
1424
    my @Polygon;
1425
    for ( $y = -100; $y <= 100; $y += 10)
1426
        {
1427
        my $Len = 5;
1428
        if ( ($y % 50) == 0 )
1429
            {
1430
            $Len = 10;
1431
            $map_canvas->createText ( $Len+5, $MapSizeY/2 + $y,
1432
                                      '-tags' => 'Map-Variometer-Skala',
1433
                                      '-text' => sprintf ("%3d", -$y / 10),
1434
                                      '-anchor' => 'w',
1435
                                      '-font' => '-*-Arial-Normal-R-Normal--*-150-*',
1436
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
1437
                              );
1438
            }
1439
        push @Polygon, (   0, $MapSizeY/2 + $y);
1440
        push @Polygon, ($Len, $MapSizeY/2 + $y);
1441
        push @Polygon, (   0, $MapSizeY/2 + $y);
1442
        }
1443
 
1444
    $map_canvas->delete('Map-Variometer');
1445
    $map_canvas->createLine(@Polygon,
1446
                            '-tags' => 'Map-Variometer',
1447
                            '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
1448
                            '-width' => 2,
1449
                            '-arrow' => 'none',
1450
                           );
1451
    # Vario Pointer
1452
    $map_canvas->delete('Map-Variometer-Pointer');
1453
    $map_canvas->createPolygon( 5, $MapSizeY/2, 20, $MapSizeY/2+10, 20, $MapSizeY/2-10,
1454
                               '-tags' => 'Map-Variometer-Pointer',
1455
                               '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometerPointer'},
1456
                               '-outline' => 'black', '-width' => 1,
1457
                              );
1458
 
1459
    # Crosshair
1460
    $map_canvas->delete('Map-Crosshair');
1461
    $map_canvas->createLine ( 0, $MapSizeY/2, $MapSizeX, $MapSizeY/2,
1462
                              '-tags' => ['Map-Crosshair', 'Map-Crosshair-X'],
1463
                              '-arrow' => 'none',
1464
                              '-fill' => $Cfg->{'map'}->{'CrosshairColor'},
1465
                              '-width' => 1,
1466
                            );
1467
    $map_canvas->createLine ( $MapSizeX/2, 0, $MapSizeX/2, $MapSizeY,
1468
                              '-tags' => ['Map-Crosshair', 'Map-Crosshair-Y'],
1469
                              '-arrow' => 'none',
1470
                              '-fill' => $Cfg->{'map'}->{'CrosshairColor'},
1471
                              '-width' => 1,
1472
                            );
1473
    $map_canvas->lower('Map-Crosshair', 'Map');   # hide below map
1474
 
1475
 
1476
    # Tracking Canvas
1477
 
1478
    if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
1479
        {
1480
        # Canvas size
1481
        $TrackSizeX  = 125;
1482
        $TrackSizeY  = 100;
1483
        $TrackOffY   = $TrackSizeY - $MapSizeY + $TrackSizeY/2;
1484
        $TrackPtrLen = 50;    # Länge Zeiger
1485
 
1486
        # draw in map-canvas
1487
        $track_canvas = $map_canvas;
1488
 
1489
        # Ziffernblatt
1490
        my $x0 = $TrackSizeX/2 - $TrackPtrLen;
1491
        my $y0 = $TrackSizeY   + $TrackPtrLen - $TrackOffY;
1492
        my $x1 = $TrackSizeX/2 + $TrackPtrLen;
1493
        my $y1 = $TrackSizeY   - $TrackPtrLen - $TrackOffY;
1494
        $map_canvas->delete('Map-Tracker');
1495
        $track_canvas->createArc ( $x0, $y0, $x1, $y1,
1496
                                   '-tags'   => 'Map-Tracker',
1497
                                   '-extent' => '359',
1498
                                   '-start' => '0',
1499
                                   '-style' => 'chord',
1500
                                   '-outline' => 'gray', '-width' => '1',
1501
                                 );
1502
 
1503
        # Skala Ziffernblatt
1504
        for ($i=0; $i<360; $i+=15)
1505
            {
1506
            my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 20) * cos( deg2rad $i );
1507
            my $y0 = $TrackSizeY   - ($TrackPtrLen - 20) * sin( deg2rad $i ) - $TrackOffY;
1508
            my $x1 = $TrackSizeX/2 - ($TrackPtrLen - 28) * cos( deg2rad $i );
1509
            my $y1 = $TrackSizeY   - ($TrackPtrLen - 28) * sin( deg2rad $i ) - $TrackOffY;
1510
            $track_canvas->createLine ( $x0, $y0, $x1, $y1,
1511
                                       '-tags'   => 'Map-Tracker',
1512
                                       '-fill' => 'white',
1513
                                       '-width' => 1,
1514
                                      );
1515
            }
1516
 
1517
        # Skala Beschriftung Ziffernblatt
1518
        for ($i=-180; $i<180; $i+=45)
1519
            {
1520
            my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 12) * cos( deg2rad $i+90 );
1521
            my $y0 = $TrackSizeY   - ($TrackPtrLen - 12) * sin( deg2rad $i+90 ) - $TrackOffY;
1522
            $track_canvas->createText ( $x0, $y0,
1523
                                       '-tags'   => 'Map-Tracker',
1524
                                       '-text' => $i,
1525
                                       '-fill' => 'white',
1526
                                      );
1527
            }
1528
 
1529
        # Zeiger Pan
1530
        my $x0 = $TrackSizeX/2;
1531
        my $y0 = $TrackSizeY - 0 - $TrackOffY;
1532
        my $x1 = $TrackSizeX/2;
1533
        my $y1 = $TrackSizeY - ($TrackPtrLen - 22) - $TrackOffY;
1534
        $track_canvas->createLine ( $x0, $y0, $x1, $y1,
1535
                                    '-tags' => [ 'Map-Tracker', 'Track-Ptr-Pan' ],
1536
                                    '-arrow' => 'last',
1537
                                    '-arrowshape' => [20, 30, 5 ],
1538
                                    '-fill' => 'red',
1539
                                    '-width' => 8,
1540
                                    );
1541
        # Zeiger Tilt
1542
        my $x0 = $TrackSizeX/2;
1543
        my $y0 = $TrackSizeY - 0 - $TrackOffY;
1544
        my $x1 = $TrackSizeX/2;
1545
        my $y1 = $TrackSizeY - ($TrackPtrLen - 22) - $TrackOffY;
1546
        $track_canvas->createLine ( $x0, $y0, $x1, $y1,
1547
                                    '-tags' => [ 'Map-Tracker', 'Track-Ptr-Tilt' ],
1548
                                    '-fill' => 'white',
1549
                                    '-width' => 1,
1550
                                  );
1551
 
1552
        # Zeiger Center
1553
        my $Dia = 7;
1554
        my $x0 = $TrackSizeX/2 - $Dia;
1555
        my $y0 = $TrackSizeY + $Dia - $TrackOffY;
1556
        my $x1 = $TrackSizeX/2 + $Dia;
1557
        my $y1 = $TrackSizeY   - $Dia - $TrackOffY;
1558
        $track_canvas->createArc ( $x0, $y0, $x1, $y1,
1559
                                   '-tags'   => 'Map-Tracker',
1560
                                   '-extent' => '359',
1561
                                   '-outline' => 'gray', '-width' => 1,
1562
                                   '-fill' => 'gray',
1563
                                 );
1564
        }
1565
 
1566
 
1567
    $map_status_line->configure ('-text' => "" );
1568
    $map_top_label->configure (-text => "$Translate{'Map'}: $Map{'Name'} ($Map{'File'})", );
1569
    }
1570
 
1571
 
1572
# Redraw map canvas after Map change
1573
sub CanvasRedraw()
1574
    {
1575
    # Aktuell gültige Karte
1576
    &MapSetCurrentFromCfg();
1577
 
1578
    # global map variables used everywhere
1579
    %Map = %{$Maps{'Current'}};
1580
    $MapSizeX  = $Map{'Size_X'};
1581
    $MapSizeY  = $Map{'Size_Y'};
1582
 
1583
    # Draw new Canvas
1584
    &CanvasCreate();
1585
 
1586
    # Re-calculate WP Lat/Lon from X/Y for map
1587
    &WpRecalc();
1588
 
1589
    # PLayer Mode
1590
    if ( $PlayerMode =~ /Play/i )  { &PlayerPlay(); }
1591
    if ( $PlayerMode =~ /Pause/i ) { &PlayerPause(); }
1592
    if ( $PlayerMode =~ /Home/i )  { &PlayerHome(); }
1593
    if ( $PlayerMode =~ /Stop/i )  { &PlayerStop(); }
1594
 
1595
    # Player Random Mode
1596
    if ( $PlayerRandomMode eq "STD" ) { &PlayerRandomStd(); }
1597
    if ( $PlayerRandomMode eq "RND" ) { &PlayerRandomRnd(); }
1598
    if ( $PlayerRandomMode eq "MAP" ) { &PlayerRandomMap(); }
1599
 
1600
    # PLayer Wpt/Kml Mode
1601
    if ( $PlayerWptKmlMode eq "WPT" )  { &PlayerWpt(); }
1602
    if ( $PlayerWptKmlMode eq "KML" )  { &PlayerKml(); }
1603
    if ( $PlayerWptKmlMode eq "SPD" )  { &PlayerSpd(); }
1604
 
1605
    # PLayer Pause Mode
1606
    if ( $PlayerPauseMode eq "MAP" )  { &PlayerPauseMode("MAP"); }
1607
    if ( $PlayerPauseMode eq "MK" )   { &PlayerPauseMode("MK"); }
1608
 
1609
    # Set POI position
1610
    ($Poi_Lat, $Poi_Lon) = &MapXY2Gps($Poi_x + 24, $Poi_y + 48);
1611
    if ( $PoiMode )
1612
        {
1613
        &PoiShow();
1614
        }
1615
    else
1616
        {
1617
        &PoiHide();
1618
        }
1619
 
1620
    # delete Footprint
1621
    @Footprint = ();
1622
    &FootprintRedraw();
1623
    }
1624
 
1625
 
1626
 
1627
# Start Web Browser with URL
1628
sub StartBrowser()
1629
    {
1630
    ($Url) = @_;
1631
    system ("start $Url")
1632
    }
1633
 
1634
#
1635
# GUI Call Back
1636
# 
1637
 
1638
# Player CallBack: Play/Pause button
1639
sub CbPlayerPlayPause()
1640
    {
1641
    if ( ($PlayerMode eq "Pause") or  ($PlayerMode eq "Stop") or  ($PlayerMode eq "Home") )
1642
        {
1643
        &PlayerPlay();
1644
        }
1645
    else
1646
        {
1647
        &PlayerPause();
1648
        }
1649
    }
1650
 
1651
 
1652
# Player CallBack: Next
1653
sub CbPlayerNext()
1654
    {
1655
    if ( $PlayerMode ne 'Stop' )
1656
        {
1657
        if ( $PlayerWptKmlMode eq 'WPT' )
1658
           {
1659
           &WpTargetNext();
1660
           }
1661
        elsif ( $PlayerWptKmlMode eq 'KML' )
1662
           {
1663
           &KmlTargetNext();
1664
           }
1665
        elsif ( $PlayerWptKmlMode eq 'SPD' )
1666
           {
1667
           &SpdTargetNext();
1668
           }
1669
        }
1670
    }
1671
 
1672
 
1673
# Player CallBack: Prev
1674
sub CbPlayerPrev()
1675
    {
1676
    if ( $PlayerMode ne 'Stop' )
1677
        {
1678
        if ( $PlayerWptKmlMode eq 'WPT' )
1679
           {
1680
           &WpTargetPrev();
1681
           }
1682
        elsif ( $PlayerWptKmlMode eq 'KML' )
1683
           {
1684
           &KmlTargetPrev();
1685
           }
1686
        elsif ( $PlayerWptKmlMode eq 'SPD' )
1687
           {
1688
           &SpdTargetPrev();
1689
           }
1690
        }
1691
    }
1692
 
1693
 
1694
# Player CallBack: First
1695
sub CbPlayerFirst()
1696
    {
1697
    if ( $PlayerMode ne 'Stop' )
1698
        {
1699
        if ( $PlayerWptKmlMode eq 'WPT' )
1700
           {
1701
           &WpTargetFirst();
1702
           }
1703
        elsif ( $PlayerWptKmlMode eq 'KML' )
1704
           {
1705
           &KmlTargetFirst();
1706
           }
1707
        elsif ( $PlayerWptKmlMode eq 'SPD' )
1708
           {
1709
           &SpdTargetFirst();
1710
           }
1711
        }
1712
    }
1713
 
1714
# Player CallBack: Last
1715
sub CbPlayerLast()
1716
    {
1717
    if ( $PlayerMode ne 'Stop' )
1718
        {
1719
        if ( $PlayerWptKmlMode eq 'WPT' )
1720
           {
1721
           &WpTargetLast();
1722
           }
1723
        elsif ( $PlayerWptKmlMode eq 'KML' )
1724
           {
1725
           &KmlTargetLast();
1726
           }
1727
        elsif ( $PlayerWptKmlMode eq 'SPD' )
1728
           {
1729
           &SpdTargetLast();
1730
           }
1731
        }
1732
    }
1733
 
1734
 
1735
# Player CallBack: Home
1736
sub CbPlayerHome()
1737
    {
1738
    if ( $PlayerMode ne 'Stop' )
1739
        {
1740
        &PlayerHome();
1741
        }
1742
    }
1743
 
1744
 
1745
# Player CallBack: Stop
1746
sub CbPlayerStop()
1747
    {
1748
    if ( $PlayerMode ne 'Stop' )
1749
        {
1750
        &PlayerStop();
1751
        }
1752
    }
1753
 
1754
 
1755
# Player CallBack: Move MK in Pause-Mode
1756
sub CbPlayerMove()
1757
    {
1758
    my ($Id, $DirX, $DirY) = @_;
1759
 
1760
    if ( $PlayerMode eq 'Pause'  and
1761
         $PlayerPause_Lat ne ""  and  $PlayerPause_Lon ne "" )
1762
        {
1763
        my $Dist = $Cfg->{'map'}->{'PauseMoveDist'} || 1;  # 1m default
1764
 
1765
        my $BearingTop = &MapAngel() - 90.0;
1766
        my $BearingKey = rad2deg atan2($DirX, $DirY);
1767
        my $Bearing = $BearingTop + $BearingKey;
1768
        if ( $PlayerPauseMode eq "MK" )
1769
            {
1770
            # MK Reference
1771
            $Bearing = $MkOsd{'CompassHeading'} + $BearingKey;
1772
            }
1773
 
1774
        ($PlayerPause_Lat, $PlayerPause_Lon) = &MapGpsAt($PlayerPause_Lat, $PlayerPause_Lon, $Dist, $Bearing);
1775
 
1776
        # restart crosshair display timer
1777
        $CrosshairTimerCnt = 0;
1778
        }
1779
    }
1780
 
1781
 
1782
# Player CallBack: Toggle Mode WPT -> SPD -> KML
1783
sub CbPlayerWptKml()
1784
    {
1785
    if ( $PlayerWptKmlMode =~ /WPT/i )
1786
        {
1787
        &PlayerSpd();
1788
        }
1789
    elsif ( $PlayerWptKmlMode =~ /SPD/i )
1790
        {
1791
        &PlayerKml();
1792
        }
1793
    elsif ( $PlayerWptKmlMode =~ /KML/i )
1794
        {
1795
        &PlayerWpt();
1796
        }
1797
    }
1798
 
1799
# Player CallBack: Reverse Toggle Mode WPT -> KML -> SPD
1800
sub CbPlayerWptKmlRev()
1801
    {
1802
    if ( $PlayerWptKmlMode =~ /WPT/i )
1803
        {
1804
        &PlayerKml();
1805
        }
1806
    elsif ( $PlayerWptKmlMode =~ /KML/i )
1807
        {
1808
        &PlayerSpd();
1809
        }
1810
    elsif ( $PlayerWptKmlMode =~ /SPD/i )
1811
        {
1812
        &PlayerWpt();
1813
        }
1814
    }
1815
 
1816
 
1817
# Player CallBack: Toggle Random modes. STD -> RND -> MAP
1818
sub CbPlayerWptRandom()
1819
    {
1820
    if ( $PlayerRandomMode eq "STD" )
1821
        {
1822
        &PlayerRandomRnd();
1823
        }
1824
    elsif ( $PlayerRandomMode eq "RND" )
1825
        {
1826
        &PlayerRandomMap();
1827
        }
1828
    else
1829
        {
1830
        &PlayerRandomStd();
1831
        }
1832
    }
1833
 
1834
 
1835
# Player CallBack: Toggle Record KML
1836
sub CbPlayerRecord()
1837
    {
1838
    if ( $PlayerRecordMode =~ /REC/i )
1839
        {
1840
        &PlayerRecordOff();
1841
        }
1842
    elsif ( $PlayerRecordMode eq "" )
1843
        {
1844
        &PlayerRecordOn();
1845
        }
1846
    }
1847
 
1848
 
1849
# Player CallBack: Number Keys
1850
sub CbPlayerNum()
1851
    {
1852
    my ($Id, $Num) = @_;
1853
 
1854
    $CbPlayerKey = "$CbPlayerKey" . "$Num";
1855
    }
1856
 
1857
 
1858
# Player CallBack: mute TTS audio
1859
sub CbPlayerMute()
1860
    {
1861
    if ( $TtsMute )
1862
        {
1863
        &TtsMute(0);
1864
        }
1865
    else
1866
        {
1867
        &TtsMute(1);
1868
        }
1869
    }
1870
 
1871
# Switch POI Mode
1872
sub CbPoi()
1873
    {
1874
    if ( $PoiMode )
1875
        {
1876
        $PoiMode = 0;
1877
        &PoiHide();
1878
        }
1879
    else
1880
        {
1881
        $PoiMode = 1;
1882
        &PoiShow();
1883
        }
1884
    }
1885
 
1886
# Grid on canvas
1887
$GridIsOn = 0;
1888
sub CbGrid()
1889
    {
1890
    if ( $GridIsOn )
1891
        {
1892
        $GridIsOn = 0;
1893
        &GridHide();
1894
        }
1895
    else
1896
        {
1897
        $GridIsOn = 1;
1898
        &GridShow();
1899
        }
1900
    }
1901
 
1902
# Player Pause Mode
1903
sub CbPlayerPauseMode()
1904
    {
1905
    if ( $PlayerPauseMode eq "MAP" )
1906
        {
1907
        &PlayerPauseMode("MK");
1908
        }
1909
    else
1910
        {
1911
        &PlayerPauseMode("MAP");
1912
        }
1913
    }
1914
 
1915
# External-Control, SerialChannel On/Off
1916
sub CbTxOnOff()
1917
    {
1918
    if ( $TxExtOn == 1 )
1919
        {
1920
        $TxExtOn = 0;
1921
        }
1922
    else
1923
        {
1924
        $TxExtOn = 1;
1925
        }
1926
    }
1927
 
1928
 
1929
# Function Key Press
1930
sub CbFctKeyPress()
1931
    {
1932
    my ($Id, $Num) = @_;
1933
 
1934
    $Num --;
1935
    $Stick{'FctKey'} |= (1 << $Num);
1936
    $Stick{'FctKeyToggle'} ^= (1 << $Num);
1937
    }
1938
 
1939
 
1940
# Function Key Release
1941
sub CbFctKeyRelease()
1942
    {
1943
    my ($Id, $Num) = @_;
1944
 
1945
    $Num --;
1946
    $Stick{'FctKey'} ^= (1 << $Num);
1947
    }
1948
 
1949
 
1950
# Capture Waypoint from current position
1951
sub CbWptCapture()
1952
    {
1953
    &WpCapture();
1954
 
1955
    if ( $PlayerWptKmlMode =~ /KML/i )
1956
        {
1957
        # switch player to Wpt mode and redraw waypoints
1958
        &PlayerWpt();
1959
        }
1960
    else
1961
        {
1962
        &WpRedrawIcons();
1963
        &WpRedrawLines();
1964
        }
1965
    }
1966
 
1967
 
1968
# CallBack: Exit Mission Cockpit
1969
sub CbExit()
1970
    {
1971
 
1972
    # stop 3D Mouse
1973
    &Mouse3DStop();
1974
 
1975
    # stop Joystick
1976
    &JoystickStop();
1977
 
1978
    # stop antenna tracking
1979
    $TrackQueue->enqueue( "IDLE" );
1980
 
1981
    # wait for tracker shutdown, with timeout
1982
    if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
1983
        {
1984
        for ($i=0; $i < 5; $i++)
1985
            {
1986
            if ( $MkTrack{'State'} ne "Idle" )
1987
                {
1988
                sleep 1;
1989
                }
1990
            }
1991
        }
1992
 
1993
    exit;
1994
    }
1995
 
1996
 
1997
__END__