Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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