Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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