Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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