Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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