Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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