Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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