Subversion Repositories Projects

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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