Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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