Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed

#!/usr/bin/perl
#!/usr/bin/perl -d:ptkdb

###############################################################################
#
# mkcockpit.pl -  MK Mission Cockpit - GUI
#
# Copyright (C) 2009  Rainer Walther  (rainerwalther-mail@web.de)
#
# Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
#
# Es ist Ihnen gestattet:
#     * das Werk vervielfältigen, verbreiten und öffentlich zugänglich machen
#     * Abwandlungen bzw. Bearbeitungen des Inhaltes anfertigen
#
# Zu den folgenden Bedingungen:
#     * Namensnennung.
#       Sie müssen den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
#     * Keine kommerzielle Nutzung.
#       Dieses Werk darf nicht für kommerzielle Zwecke verwendet werden.
#     * Weitergabe unter gleichen Bedingungen.
#       Wenn Sie den lizenzierten Inhalt bearbeiten oder in anderer Weise umgestalten,
#       verändern oder als Grundlage für einen anderen Inhalt verwenden,
#       dürfen Sie den neu entstandenen Inhalt nur unter Verwendung von Lizenzbedingungen
#       weitergeben, die mit denen dieses Lizenzvertrages identisch oder vergleichbar sind.
#
# Im Falle einer Verbreitung müssen Sie anderen die Lizenzbedingungen, unter welche dieses
# Werk fällt, mitteilen. Am Einfachsten ist es, einen Link auf diese Seite einzubinden.
#
# Jede der vorgenannten Bedingungen kann aufgehoben werden, sofern Sie die Einwilligung
# des Rechteinhabers dazu erhalten.
#
# Diese Lizenz lässt die Urheberpersönlichkeitsrechte unberührt.
#
# Weitere Details zur Lizenzbestimmung gibt es hier:
#   Kurzform: http://creativecommons.org/licenses/by-nc-sa/3.0/de/
#   Komplett: http://creativecommons.org/licenses/by-nc-sa/3.0/de/legalcode
#
###############################################################################
# 2009-02-20 0.0.1 rw created
# 2009-04-01 0.1.0 rw RC1
# 2009-04-16 0.1.1 rw Bugfix, ALT= average of airsensor and Sat
# 2009-05-14 0.2.0 rw Waypoint Player
# 2009-05-17 0.2.1 rw Cursor-Steuerung fuer WP-Player. Cmdline-Parameter "-geometry"
# 2009-07-18 0.2.2 rw DE/EN multinational
#                     Target-Balloon with Distance, Tolerance and Holdtime
#                     Fix footprint "Ausreiser"
#                     JPEG and PNG maps supported
#                     Player for KML Files
# 2009-07-26 0.2.3 rw System Messages Balloon
# 2009-07-31 0.2.4 rw ODO Kilometerzähler
#                     Enter WP-Number from Keyboard
#                     Random WP-Player (Waypoint and Map)
#                     Check Airfield Border
#                     Draw Calibration points on map
# 2009-08-08 0.2.5 rw KML Recorder
#                     Text to speech
#                     Subroutines moved to libmkcockpit.pl
#                     Timer moved to libmktimer.pl
#                     Start Scenarion configuration
#                     Battery capacity estimation
#                     Read map definition from maps/map.xml
# 2009-08-23 0.2.6 rw Tracking-Antenna Icon
#                     Show Fox only in Player-Pause mode
#                     POI heading control
#                     Display scale
#                     Measuring-tool on left mouse button
#                     Display Operation Radius Border
#                     Read map definition from KML file (GE import)
#                     Include of local *.pm changed
#                     Copy x/y/Lat/Lon to Clipboard when pressing left mouse button
#                     Calculate size of map image
#                     track.pl - Commandline parameter added for COM ports
#                     don't use local perl libs any more
# 2009-10-18 0.2.7 rw Mk-Simulator
#                     Start tracker at program start. Coldstart at MK-calibration
#                     COM Port >9; PortSetSkip config
#                     Reset Flight-Time and ODO when clicking on OSD-value
#
###############################################################################

$Version = "0.2.7 - 2009-10-18";

 
# change working directory to program path
my $Cwd = substr ($0, 0, rindex ($0, "mkcockpit.pl"));
chdir $Cwd;

# set path for local Perl libs
push @INC, $Cwd . "perl/lib";

use threads;            # http://search.cpan.org/~jdhedden/threads-1.72/threads.pm
                        # http://perldoc.perl.org/threads.html
use threads::shared;    # http://search.cpan.org/~jdhedden/threads-shared-1.28/shared.pm
use Thread::Queue;      # http://search.cpan.org/dist/Thread-Queue-2.11/lib/Thread/Queue.pm
use Tk;
use Tk::Balloon;
use Tk::Dialog;
use Tk::Notebook;
use Tk::JPEG;           # http://search.cpan.org/~srezic/Tk-804.028/JPEG/JPEG.pm
use Tk::PNG;            # http://search.cpan.org/~srezic/Tk-804.028/PNG/PNG.pm
use Math::Trig;
use Time::HiRes qw(usleep);  # http://search.cpan.org/~jhi/Time-HiRes-1.9719/HiRes.pm
use XML::Simple;             # http://search.cpan.org/dist/XML-Simple-2.18/lib/XML/Simple.pm
use Clipboard;               # http://search.cpan.org/~king/Clipboard-0.09/lib/Clipboard.pm
use Image::Size;             # http://search.cpan.org/~rjray/Image-Size-3.2/lib/Image/Size.pm


# Version setting
share (%Version);
$Version{'mkcockpit.pl'}  = $Version;

# Read configuration
$XmlConfigFile = "mkcockpit.xml";
$Cfg = XMLin($XmlConfigFile);

require "track.pl";        # Tracking antenna
require "mkcomm.pl";       # MK communication
require "logging.pl";      # CSV and GPX Logging
require "geserver.pl";     # Google Earth Server
require "$Cfg->{'map'}->{'MapDir'}/map.pl";   # Landkarte
require "libmap.pl";       # map subs
require "translate.pl";    # Übersetzungstable
require "tts.pl";          # Text to Speech
require "libmkcockpit.pl"; # Subroutines
require "libmksim.pl";     # MK Simulator

# Commandline parameter
my %CmdLine = @ARGV;

# Aktuell gültige Karte
my %Map = %{$Maps{'Current'}};

# optional map specific Cfg setup from map definition
foreach $Key (keys %Map)
    {
    # Cfg:Section:Keyword
    if ( $Key =~ /^Cfg:(\S*):(\S*)/i )
        {
        $Section = $1;
        $Keyword = $2;
        $Cfg->{$Section}->{$Keyword} = $Map{$Key};
        }
    }

# Canvas size - get image size
my $ImgFile = "$Cfg->{'map'}->{'MapDir'}/$Map{'File'}";
($MapSizeX, $MapSizeY, my $ImgError) = imgsize ($ImgFile);
if ( $MapSizeX eq "" )
    {
    print "$ImgFile: $ImgError\n";
   
    # Try size information from map definition
    $MapSizeX  = $Map{'Size_X'};
    $MapSizeY  = $Map{'Size_Y'};
    }


# Thread fuer Kommunikation mit MK starten
# Output: %MkOsd, %MkTarget, %MkNcDebug, %Mk
# Input:  Thread-Queue: $MkSendQueue
$mk_thr = threads->create (\&MkCommLoop) -> detach();

# Start Logging Thread
$log_thr = threads->create (\&MkLogLoop) -> detach();

# Start GoogleEarth Thread
$ge_thr = threads->create (\&GeServer) -> detach();

# Start TTS Thread
$tts_thr = threads->create (\&TtsLoop) -> detach();

# Start Antenna tracker
if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
    {
    $track_thr = threads->create (\&TrackAntennaGps)->detach();
    }

#
# Player:
#    Waypoint-List:   @Waypoints
#    KML-Target-List: @KmlTargets
#

# Player state machine
$PlayerMode = 'Stop';       # Play, Stop, Pause, Home ...
$PlayerWptKmlMode = 'WPT';  # WPT, KML
$PlayerRandomMode = 'STD';  # STD, RND, MAP
$PlayerRecordMode = "";     # "", REC
$WpPlayerIndex = 0;
$WpPlayerHoldtime = -1;
$KmlPlayerIndex = 0;
$PlayerPause_Lat = "";
$PlayerPause_Lon = "";

# Point Of Interest (POI)
my $Poi_x = $MapSizeX/2-100;
my $Poi_y = $MapSizeY/2 ;
($Poi_Lat, $Poi_Lon) = &MapXY2Gps($Poi_x + 24, $Poi_y + 48);

# POI from Map configuration
if ( $Map{'Poi_Lat'} ne ""  and   $Map{'Poi_Lon'} ne "" )
    {
    $Poi_Lat = $Map{'Poi_Lat'};
    $Poi_Lon = $Map{'Poi_Lon'};
    ($Poi_x, $Poi_y) = &MapGps2XY($Poi_Lat, $Poi_Lon);
    $Poi_x = $Poi_x - 24;
    $Poi_y = $Poi_y - 48;
    }
$Poi_Mode = 0;     # POI Mode off

# Hauptfenster
$main = new MainWindow;
$main->title ("MK Mission Cockpit - Version $Version");

if ( $CmdLine{'-geometry'} ne "" )
    {
    $main->geometry( "$CmdLine{'-geometry'}" );
    }


# pattern for dashed lines
my $stipple_bits = [];
foreach my $b (1..8)
    {
    push @$stipple_bits, pack ('b8', '1' x $b . '.' x (8 - $b));
    $main->DefineBitmap("stipple$b" => 8, 1, $stipple_bits->[$b-1]);
    }

#-----------------------------------------------------------------
# Menu
#-----------------------------------------------------------------

# Menu bar
my $menu_bar = $main->Menu;
$main->optionAdd("*tearOff", "false");
$main->configure ('-menu' => $menu_bar);

my $menu_file = $menu_bar->cascade('-label' => $Translate{'File'});
    $menu_file->command('-label' => $Translate{'Preferences'},
                        '-command' => [\&Configure],
                       );
    $menu_file->separator;                                     
    $menu_file->command('-label' => $Translate{'Exit'},
                        '-command' => [\&CbExit ],
                        );

my $menu_debug = $menu_bar->cascade(-label => $Translate{'Debug'});
    $menu_debug->command('-label' => $Translate{'NcOsdDataset'},
                         '-command' => [\&DisplayHash, \%MkOsd, $Translate{'NcOsdDataset'}, "Display Refresh Heartbeat"],
                        );
    $menu_debug->command('-label' => $Translate{'NcTargetDataset'},
                         '-command' => [\&DisplayHash, \%MkTarget, $Translate{'NcTargetDataset'}, "Display Refresh Heartbeat"],
                        );
    $menu_debug->command('-label' => $Translate{'NcDebugDataset'},
                         '-command' => [\&DisplayHash, \%MkNcDebug, $Translate{'NcDebugDataset'}, "Display Refresh Heartbeat"],
                                        );             
    $menu_debug->command('-label' => $Translate{'NcOther'},
                         '-command' => [\&DisplayHash, \%Mk, $Translate{'NcOther'}, "Display Refresh Heartbeat"],
                                        );
    $menu_debug->separator;                                    
    $menu_debug->command('-label' => $Translate{'TrackingDebugDataset'},
                         '-command' => [\&DisplayHash, \%MkTrack, $Translate{'TrackingDebugDataset'}, "Display Refresh Heartbeat"],
                        );
    $menu_debug->separator;                                    
    $menu_debug->command('-label' => $Translate{'MkDebugSim'},
                         '-command' => \&MkSim,
                        );
    #$menu_debug->command('-label' => $Translate{'MapDebugDataset'},
    #                     '-command' => [\&DisplayHash, \%Map, $Translate{'MapDebugDataset'}, "Display"],
    #                    );

my $menu_help = $menu_bar->cascade(-label => $Translate{'Help'});
    $menu_help->command('-label' => 'Version',
                        '-command' => [\&DisplayHash, \%Version, $Translate{'Version'}, "Display"],
                       );
    $menu_help->separator;
    $menu_help->command('-label' => $Translate{'About'},
                        '-command' => sub
        {
        my $License = <<EOF;
Copyright (C) 2009  Rainer Walther (rainerwalther-mail\@web.de)

Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)

See LICENSE.TXT
EOF


        my $DlgAbout = $frame_map->Dialog('-title' => $Translate{'AboutMissionCockpit'},
                                          '-text' => "$License",
                                          '-buttons' => ['OK'],
                                          '-bitmap' => 'info',
                                         );
        $DlgAbout->Show;
        });  


# Hauptfenster Statuszeile
$frame_status = $main->Frame( '-background' => 'lightgray',
                         ) -> pack('-side' => 'bottom',
                                   '-anchor' => 'w',
                                   '-fill' => 'none',
                                   '-expand' => 'y',
                                    );
$status_line = $frame_status->Label ('-text' => $Translate{'StatusLine'},
                                    ) -> pack ('-side' => 'bottom',
                                               );

                                                                                           
#-----------------------------------------------------------------
# Frames
#-----------------------------------------------------------------                       

#
# Frame: Map
#
                                 
$frame_map = $main->Frame( '-background' => 'lightgray',
                           '-relief' => 'sunken',
                           '-borderwidth' => 5,
                          ) -> pack('-side' => 'top',
                                    '-fill' => 'x',
                                    );

# Map Überschrift
$frame_map_top = $frame_map->Frame() -> pack( '-side' => 'top',
                                              '-expand' => 'x',
                                              '-anchor' => 'w',
                                            );

$frame_map_top->Label ('-text' => "$Translate{'Map'}: $Map{'Name'} ($Map{'File'})",
                       '-background' => 'lightgray',
                       '-relief' => 'flat',
                       ) -> pack( '-side' => 'left' );

# Map Statuszeile
$map_status = $frame_map->Frame( '-background' => 'lightgray',
                               ) -> pack('-side' => 'bottom',
                                         '-anchor' => 'w',
                                         '-fill' => 'none',
                                         '-expand' => 'y',
                                        );
$map_status_line = $map_status->Label ( '-text' => $Translate{'StatusLine'},
                                        '-background' => 'lightgray',
                                       ) -> pack ('-side' => 'bottom',);

#
# Map Canvas
#

$map_canvas = $frame_map->Canvas( '-width'  => $MapSizeX,
                                  '-height' => $MapSizeY,
                                  '-cursor' => 'cross',
                                ) -> pack();


# Images and Icons on canvas
my @Icons = (
            # Image             Tag             File                                       Pos_x            Pos_y
            'Map',              'Map',          "$Cfg->{'map'}->{'MapDir'}/$Map{'File'}",  0,               0,
            'HeartbeatSmall',   'Heartbeat',    "$Cfg->{'mkcockpit'}->{'IconHeartSmall'}", $MapSizeX/4,     10,
            'HeartbeatLarge',   'Heartbeat',    "$Cfg->{'mkcockpit'}->{'IconHeartLarge'}", $MapSizeX/4,     -100,
            'Satellite-Photo',  'Satellite',    "$Cfg->{'mkcockpit'}->{'IconSatellite'}",  $MapSizeX-300,   -100,
            'Antenna-Photo',    'Track-Antenna',"$Cfg->{'track'}->{'IconAntenna'}",        0,               -50,
            'POI-Photo',        'POI'          ,"$Cfg->{'mkcockpit'}->{'IconPoi'}",        $Poi_x,          $Poi_y,
            'Waypoint-Photo',   'Waypoint',     "$Cfg->{'mkcockpit'}->{'IconWaypoint'}",   0,               -150,
            'Target-Photo',     'Target',       "$Cfg->{'mkcockpit'}->{'IconTarget'}",     0,               -100,
            'Fox-Photo',        'Fox',          "$Cfg->{'mkcockpit'}->{'IconFox'}",        $MapSizeX/2-100, $MapSizeY/2,
            'WpPlay-Foto',      'Wp-PlayPause', "$Cfg->{'waypoint'}->{'IconPlay'}",        $MapSizeX/2+150, $MapSizeY-48,
            'WpPause-Foto',     'Wp-PlayPause', "$Cfg->{'waypoint'}->{'IconPause'}",       $MapSizeX/2+150, -100,
            'WpStop-Foto',      'Wp-Stop',      "$Cfg->{'waypoint'}->{'IconStop'}",        $MapSizeX/2+200, $MapSizeY-48,
            'WpNext-Foto',      'Wp-Next',      "$Cfg->{'waypoint'}->{'IconNext'}",        $MapSizeX/2+50,  $MapSizeY-48,
            'WpPrev-Foto',      'Wp-Prev',      "$Cfg->{'waypoint'}->{'IconPrev'}",        $MapSizeX/2,     $MapSizeY-48,
            'WpFirst-Foto',     'Wp-First',     "$Cfg->{'waypoint'}->{'IconFirst'}",       $MapSizeX/2-50,  $MapSizeY-48,
            'WpLast-Foto',      'Wp-Last',      "$Cfg->{'waypoint'}->{'IconLast'}",        $MapSizeX/2+100, $MapSizeY-48,
            'WpHome-Foto',      'Wp-Home',      "$Cfg->{'waypoint'}->{'IconHome'}",        $MapSizeX/2-100, $MapSizeY-48,
            'WpRecord-Foto',    'Wp-Record',    "$Cfg->{'waypoint'}->{'IconRecord'}",      $MapSizeX/2-150, $MapSizeY-48,
            'WpRandomOff-Foto', 'Wp-WptRandom', "$Cfg->{'waypoint'}->{'IconRandomOff'}",   $MapSizeX/2-200, -100,
            'WpRandomOn-Foto',  'Wp-WptRandom', "$Cfg->{'waypoint'}->{'IconRandomOn'}",    $MapSizeX/2-200, $MapSizeY-48,
            'WpRandomMap-Foto', 'Wp-WptRandom', "$Cfg->{'waypoint'}->{'IconRandomMap'}",   $MapSizeX/2-200, -100,
            'WpWpt-Foto',       'Wp-WptKml',    "$Cfg->{'waypoint'}->{'IconWpt'}",         $MapSizeX/2-250, $MapSizeY-48,
            'WpKml-Foto',       'Wp-WptKml',    "$Cfg->{'waypoint'}->{'IconKml'}",         $MapSizeX/2-250, -100 ,
            );
my $i = 0;
for $Icon (0 .. $#Icons/5)
    {
    my $Image =  $Icons[$i++];
    my $Tag =    $Icons[$i++];
    my $File =   $Icons[$i++];
    my $Pos_x =  $Icons[$i++];
    my $Pos_y =  $Icons[$i++];

    $map_canvas->Photo( $Image,
                        '-file' => $File,
                      );
    $map_canvas->createImage( $Pos_x, $Pos_y,
                              '-tags'   => $Tag,
                              '-anchor' => 'nw',
                              '-image'  => $Image,
                            );
    }


# Calibration Points
$map_canvas->createLine ( $Map{'P1_x'}-8, $Map{'P1_y'},
                          $Map{'P1_x'}+8, $Map{'P1_y'},
                          $Map{'P1_x'},   $Map{'P1_y'},
                          $Map{'P1_x'},   $Map{'P1_y'}-8,
                          $Map{'P1_x'},   $Map{'P1_y'}+8,
                          '-tags'  => 'Calibration',
                          '-arrow' => 'none',
                          '-fill'  => 'red',
                          '-width' => 1,
                         );
$map_canvas->createLine ( $Map{'P2_x'}-8, $Map{'P2_y'},
                          $Map{'P2_x'}+8, $Map{'P2_y'},
                          $Map{'P2_x'},   $Map{'P2_y'},
                          $Map{'P2_x'},   $Map{'P2_y'}-8,
                          $Map{'P2_x'},   $Map{'P2_y'}+8,
                          '-tags'  => 'Calibration',
                          '-arrow' => 'none',
                          '-fill'  => 'red',
                          '-width' => 1,
                         );

# scale
my $x1 = $MapSizeX/2 +280;
my $x2 = $MapSizeX -30;
my $y1 = $MapSizeY - 20;
my $y2 = $MapSizeY - 15;
if ( $x2 - $x1 > 150 )
    {
    $x1 = $x2 - 150;
    }

$map_canvas->createLine ( $x1, $y1,
                          $x1, $y2,
                          $x2, $y2,
                          $x2, $y1,
                          '-tags'  => 'Scale',
                          '-arrow' => 'none',
                          '-fill'  => 'red',
                           '-fill' => $Cfg->{'mkcockpit'}->{'ColorScale'} || 'white',
                          '-width' => 1,
                         );

my ($Lat1, $Lon1) = &MapXY2Gps($x1, $y1);
my ($Lat2, $Lon2) = &MapXY2Gps($x2, $y2);
my ($Dist, $Bearing) = &MapGpsTo($Lat1, $Lon1, $Lat2, $Lon2 );
$Dist = sprintf ("%.2f m", $Dist);
$map_canvas->createText ( $x1 + ($x2 - $x1)/2 - 20, $y1 - ($y2 - $y1)/2,
                          '-tags' => 'Scale-Text',
                          '-text' => $Dist,
                          '-anchor' => 'w',
                          '-font' => '-*-Arial-Bold-R-Normal--*-120-*',
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorScale'} || 'white',
                          );

# border polygon
$map_canvas->createPolygon( @Map{'Border'},
                           '-tags' => 'Map-Border',
                           '-fill' => '',
                           '-outline' => $Cfg->{'mkcockpit'}->{'ColorAirfield'}, '-width' => 2,
                          );
$map_canvas->raise('Map-Border', 'Map');  # Border above Map


# Balloon attached to Canvas
$map_balloon = $frame_map->Balloon('-statusbar' => $status_line, );
$map_balloon->attach($map_canvas,
                     '-balloonposition' => 'mouse',
                     '-state' => 'balloon',
                     '-msg' => { 'MK-Arrow'               => $Translate{'Balloon-MK-Arrow'},
                                 'MK-Home-Line'           => $Translate{'Balloon-MK-Home-Line'},
                                 'MK-Home-Dist'           => $Translate{'Balloon-MK-Home-Dist'},
                                 'MK-Target-Line'         => $Translate{'Balloon-MK-Target-Line' },
                                 'MK-Target-Dist'         => $Translate{'Balloon-MK-Target-Dist'},
                                 'MK-Speed'               => $Translate{'Balloon-MK-Speed'},
                                 'Map-Variometer'         => $Translate{'Balloon-Map-Variometer' },
                                 'Map-Variometer-Pointer' => $Translate{'Balloon-Map-Variometer-Pointer'},
                                 'Map-Variometer-Skala'   => $Translate{'Balloon-Map-Variometer-Pointer'},
                                 'Fox'                    => $Translate{'Balloon-Fox'},
                                 'Heartbeat'              => $Translate{'Balloon-Heartbeat'},
                                 'Satellite'              => $Translate{'Balloon-Satellite'},
                                 'Waypoint'               => $Translate{'Balloon-Waypoint'},
                                 'Map-Border'             => $Translate{'Balloon-Map-Border'},
                                 'Waypoint-Connector'     => $Translate{'Balloon-Waypoint-Connector'},
                                 'Wp-PlayPause'           => $Translate{'Balloon-Wp-PlayPause'},
                                 'Wp-Stop'                => $Translate{'Balloon-Wp-Stop'},
                                 'Wp-First'               => $Translate{'Balloon-Wp-First'},
                                 'Wp-Last'                => $Translate{'Balloon-Wp-Last'},
                                 'Wp-Next'                => $Translate{'Balloon-Wp-Next'},
                                 'Wp-Prev'                => $Translate{'Balloon-Wp-Prev'},
                                 'Wp-Home'                => $Translate{'Balloon-Wp-Home'},
                                 'Wp-WptKml'              => $Translate{'Balloon-Wp-WptKml'},
                                 'Wp-WptRandom'           => $Translate{'Balloon-Wp-WptRandom'},
                                 'Wp-Record'              => $Translate{'Balloon-Wp-Record'},
                                 'Track-Antenna'          => $Translate{'Balloon-TrackAntenna'},
                                 'POI'                    => $Translate{'Balloon-Poi'},
                               },
                    );

#                                      
# Mouse button 1
#

# Button 1 Press
$map_canvas->CanvasBind("<Button-1>", sub
    {
    # print coords in status line
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my ($Lat, $Lon) = &MapXY2Gps($x, $y);

    $map_status_line->configure ('-text' => "Lat: $Lat  Lon: $Lon     x: $x  y: $y");

    # save Coords and GPS-Pos for Button-Motion and Release
    $Button1_x = $x;
    $Button1_y = $y;
    $Button1_Lat = $Lat;
    $Button1_Lon = $Lon;

    # copy Pixel-Coordinates to Clipboard
    Clipboard->copy ("x=$x\r\n" . "y=$y\r\n" . "Lat=$Lat\r\n" . "Lon=$Lon\r\n");
    });

# Button 1 Motion
$map_canvas->CanvasBind("<Button1-Motion>", sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    # delete old measuring line
    $map_canvas->delete('Map-Measure');

    my @Tags = $map_canvas->gettags($id);
    if ( ( $Tags[0] eq "Map"  or $Tags[0] eq "Map-Border") and
         $x ne $Button1_x  and  $y ne $Button1_y )
        {
        # button moved on Map

        # draw new measuring line
        $map_canvas->createLine ( $Button1_x, $Button1_y, $x, $y,
                                  '-tags' => 'Map-Measure',
                                  '-arrow' => 'none',
                                  '-fill' => 'white',
                                  '-width' => 1,
                         );

        # update status line
        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
        my ($Dist, $Bearing) = &MapGpsTo($Button1_Lat, $Button1_Lon, $Lat, $Lon);
        $Dist = sprintf ("%.2f m", $Dist);
        $Bearing = sprintf ("%.2f degree", $Bearing);

        $map_status_line->configure ('-text' => "Dist: $Dist  Bearing: $Bearing");
        }
    });

# Button 1 Release
$map_canvas->CanvasBind("<Button1-ButtonRelease>", sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    # delete measuring line
    $map_canvas->delete('Map-Measure');

    my @Tags = $map_canvas->gettags($id);
    if ( ( $Tags[0] eq "Map"  or $Tags[0] eq "Map-Border") and
         $x ne $Button1_x  and  $y ne $Button1_y )
        {
        # button released on Map

        # update status line
        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
        my ($Dist, $Bearing) = &MapGpsTo($Button1_Lat, $Button1_Lon, $Lat, $Lon);
        $Dist = sprintf ("%.2f m", $Dist);
        $Bearing = sprintf ("%.2f degree", $Bearing);

        $map_status_line->configure ('-text' => "Dist: $Dist  Bearing: $Bearing");
        }
    });


# Mouse button 1 for Fox
my $FoxOldx = 0;
my $FoxOldy = 0;
my $FoxTime = time;
&FoxHide();   # Show only in Player-Pause Mode

# Pick Fox
$map_canvas->bind('Fox' => '<Button-1>' => sub
    {
    # prepare to move Fox
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    $FoxOldx = $x;
    $FoxOldy = $y;
    $FoxTime = time;
    });

# Move Fox
$map_canvas->bind('Fox' => '<Button1-Motion>' => sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    $map_canvas->move($id => $x - $FoxOldx, $y - $FoxOldy);
    $FoxOldx = $x;
    $FoxOldy = $y;
       
    if ( time > $FoxTime )
        {
        # wenn in Bewegung Koordinaten nur 1/s senden
        my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
        $x = $x0 + ($x1 - $x0)/2;
        $y = $y1;

        ($PlayerPause_Lat, $PlayerPause_Lon) = &MapXY2Gps($x, $y);
        $FoxTime = time;

        $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $PlayerPause_Lat  Lon: $PlayerPause_Lon     x: $x  y: $y");
        }
    });

# Release Fox
$map_canvas->bind('Fox' => '<Button1-ButtonRelease>' => sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
    $x = $x0 + ($x1 - $x0)/2;
    $y = $y1;

    ($PlayerPause_Lat, $PlayerPause_Lon) = &MapXY2Gps($x, $y);

    # Show user that Waypoints in MK are cleared
    $WaypointsModified = 1;
    &WpRedrawLines();

    $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $PlayerPause_Lat  Lon: $PlayerPause_Lon     x: $x  y: $y");
    });

# Pick Waypoint
my $WpOldx;
my $WpOldy;
$map_canvas->bind('Waypoint' => '<Button-1>' => sub
    {
    # prepare to move
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    $WpOldx = $x;
    $WpOldy = $y;
    });
       
# Move Waypoint
$map_canvas->bind('Waypoint' => '<Button1-Motion>' => sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    # move icon and Wp-Number
    my $WpIndex = &WpGetIndexFromId($id);
    if ( $WpIndex >= 0 )
        {
        my $Tag = $Waypoints[$WpIndex]{'Tag'};
        $map_canvas->move($Tag => $x - $WpOldx, $y - $WpOldy);
        }

    $WpOldx = $x;
    $WpOldy = $y;
    });

# Release Wp
$map_canvas->bind('Waypoint' => '<Button1-ButtonRelease>' => sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    # take coords from lower/middle icon position
    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
    $x = $x0 + ($x1 - $x0)/2;
    $y = $y1;

    # update Waypoint-Array
    my $WpIndex = &WpGetIndexFromId($id);
    if ( $WpIndex >= 0 )
            {
        # got it: set new coords

        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
        my $Wp = $Waypoints[$WpIndex];
        $Wp->{'MapX'} = $x;
        $Wp->{'MapY'} = $y;
        $Wp->{'Pos_Lat'} = $Lat;
        $Wp->{'Pos_Lon'} = $Lon;
               
        # redraw connector-lines
        &WpRedrawLines();

        # red connectors: Wp still have to be sent to MK
        $map_canvas->itemconfigure('Waypoint-Connector',
                                           '-fill' => $Cfg->{'mkcockpit'}->{'ColorWpResend'},
                                  );
        $WaypointsModified = 1;
                       
        my $WpNum = $WpIndex + 1;
        $map_status_line->configure ('-text' => "$Translate{'WpMoved'}: $WpNum -> Lat: $Lat  Lon: $Lon     x: $x  y: $y");
        }
    });

# Mouse button 1 for POI
my $PoiOldx = 0;
my $PoiOldy = 0;
&PoiHide();

# Pick Poi
$map_canvas->bind('POI' => '<Button-1>' => sub
    {
    # prepare to move Icon
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    $PoiOldx = $x;
    $PoiOldy = $y;
    });

# Move POI
$map_canvas->bind('POI' => '<Button1-Motion>' => sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    $map_canvas->move($id => $x - $PoiOldx, $y - $PoiOldy);
    $PoiOldx = $x;
    $PoiOldy = $y;
    });

# Release POI
$map_canvas->bind('POI' => '<Button1-ButtonRelease>' => sub
    {
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
    my $id      = $map_canvas->find('withtag', 'current');

    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
    $x = $x0 + ($x1 - $x0)/2;
    $y = $y1;

    ($Poi_Lat, $Poi_Lon) = &MapXY2Gps($x, $y);

    $map_status_line->configure ('-text' => "$Translate{'PoiMoved'}: ->   Lat: $Poi_Lat  Lon: $Poi_Lon     x: $x  y: $y");
    });


# Reset Flight time
$map_canvas->bind('MK-OSD-Tim-Value' => '<Button-1>' => sub
    {
    $MkFlyingTime = 0;
    });

# Reset ODO
$map_canvas->bind('MK-OSD-Odo-Value' => '<Button-1>' => sub
    {
    $OdoMeter = 0;
    });


#
# Mouse button 3 context menu
#
my $map_menu = $map_canvas->Menu('-tearoff' => 0,
                                 '-title' =>'None',
                                 '-menuitems' =>
    [
     [Button => $Translate{'WpAddAndSend'},  -command => sub
        {
        # send Wp to MK        
        ($Lat, $Lon) = &MapXY2Gps($Wp_x, $Wp_y);
        &MkFlyTo ( '-lat' => $Lat,
                   '-lon' => $Lon,
                   '-mode' => "Waypoint"
                 );

        # Add Wp to Waypoints list
        &WpAdd ($MapCanvasX, $MapCanvasY);

        # switch player to Wp mode and redraw waypoints
        &PlayerWpt();

        $map_status_line->configure ('-text' => "$Translate{'WpSavedAndSent'} -> Lat: $Lat Lon: $Lon");
        }],


     [Button => $Translate{'WpProperties'},  -command => sub
        {
        # find Wp-Hash for selected icon/tag
        my $WpIndex = &WpGetIndexFromId($MapCanvasId);
        if ( $WpIndex >= 0 )
            {
            my $Wp = $Waypoints[$WpIndex];
            my $WpNum = $WpIndex + 1;

            &DisplayHash ($Wp, "$Translate{'WpProperties'} $WpNum", "Edit Waypoint Refresh");

            $map_status_line->configure ('-text' => "$Translate{'WpProperties'} $WpNum");
            }
        }],
               
     [Button => $Translate{'WpResendAll'},  -command => sub
        {
        &WpSendAll();
               
        $map_status_line->configure ('-text' => $Translate{'WpAllSent'});
        }],

      '',   # Separator
       
     [Button => $Translate{'WpLoadAndSend'},  -command => sub
        {
        my $WpFile = $main->getOpenFile('-defaultextension' => ".xml",
                                        '-filetypes'        =>
                                            [['Waypoints',     '.xml' ],
                                             ['All Files',     '*', ],
                                            ],
                                        '-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
                                        '-title' => $Translate{'WpLoad'},
                                       );
        if ( -f $WpFile )
            {
            &WpLoadFile ($WpFile);

            # send all Wp to MK
            &WpSendAll();

            # switch player to Wp mode and redraw waypoints
            $PlayerRandomMode  = 'STD';
            &PlayerWpt();
       
            $map_status_line->configure ('-text' => "$Translate{'WpLoadedAndSent'}: $WpFile");
            }
        }],    
       
     [Button => $Translate{'WpSave'},  -command => sub
        {
        my $WpFile = $main->getSaveFile('-defaultextension' => ".xml",
                                        '-filetypes'        =>
                                          [['Waypoints',     '.xml' ],
                                           ['All Files',     '*', ],
                                          ],
                                        '-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
                                        '-title' => $Translate{'WpSave'},
                                       );

        &WpSaveFile ($WpFile);
               
        $map_status_line->configure ('-text' => "$Translate{'WpSaved'}: $WpFile");
        }],
               
     '',   # Separator

     [Button => $Translate{'WpDelete'},  -command => sub
        {
        # find Wp-Hash for selected icon/tag
        my $WpIndex = &WpGetIndexFromId($MapCanvasId);
        if ( $WpIndex >= 0 )
            {
            &WpDelete ($WpIndex);

            # redraw connector-lines
            $WaypointsModified = 1;
            &WpRedrawLines();  
            &WpRedrawIcons();  # wg. Wp-Nummern

            my $WpNum = $WpIndex + 1;
            $map_status_line->configure ('-text' => "$Translate{'WpDeleted'}: $WpNum");
            }
        }],

     [Button => $Translate{'WpAllDeleteAndSend'},  -command => sub
        {
        undef @Waypoints;
        $WpPlayerIndex = 0;
        $WpPlayerHoldtime = -1;

        # remove all Wp-Icons and Wp-Number on canvas
        &WpHide();

        &WpSendAll();

        $map_status_line->configure ('-text' => "$Translate{'WpAllDeleted'}: $WpIndex");
        }],

    '',   # Separator

     [Button => $Translate{'KmlLoadAndPlay'},  -command => sub
        {
        $KmlFile = $main->getOpenFile('-defaultextension' => ".kml",
                                     '-filetypes'        =>
                                         [['KML',           '.kml' ],
                                          ['All Files',     '*', ],
                                         ],
                                     '-initialdir' => $Cfg->{'waypoint'}->{'KmlDir'},
                                     '-title' => $Translate{'KmlLoad'},
                                    );
        if ( -f $KmlFile )
            {
            &KmlLoadFile($KmlFile);

            # switch player to KML mode and redraw track
            &PlayerKml();

            $map_status_line->configure ('-text' => "$Translate{'KmlLoaded'}: $KmlFile" );
            }

        }],

    '',   # Separator
         
     [Button => $Translate{'WpFlyImmediately'},  -command => sub
        {
        &MkFlyTo ( '-x' => $MapCanvasX,
                   '-y' => $MapCanvasY,
                   '-mode' => "Target"
                 );

        # redraw connector-lines
        $WaypointsModified = 1;
        &WpRedrawLines();  

        $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $Lat  Lon: $Lon     x: $MapCanvasX  y: $MapCanvasY");
        }],
    ]
                                    );
$map_canvas->CanvasBind("<Button-3>" => [ sub
    {
    $map_canvas->focus;
    my($w, $x, $y) = @_;
    ($MapCanvasX, $MapCanvasY) = ($Tk::event->x, $Tk::event->y);
    $MapCanvasId = $map_canvas->find('withtag', 'current');
    $map_menu->post($x, $y);
    }, Ev('X'), Ev('Y') ] );


# Mouse bindings
$map_canvas->bind('Wp-PlayPause' => '<Button-1>' => \&CbPlayerPlayPause );
$map_canvas->bind('Wp-Next'      => '<Button-1>' => \&CbPlayerNext );
$map_canvas->bind('Wp-Prev'      => '<Button-1>' => \&CbPlayerPrev );
$map_canvas->bind('Wp-First'     => '<Button-1>' => \&CbPlayerFirst );
$map_canvas->bind('Wp-Last'      => '<Button-1>' => \&CbPlayerLast );
$map_canvas->bind('Wp-Home'      => '<Button-1>' => \&CbPlayerHome );
$map_canvas->bind('Wp-Stop'      => '<Button-1>' => \&CbPlayerStop );
$map_canvas->bind('Wp-WptKml'    => '<Button-1>' => \&CbPlayerWptKml );
$map_canvas->bind('Wp-WptRandom' => '<Button-1>' => \&CbPlayerWptRandom );
$map_canvas->bind('Wp-Record'    => '<Button-1>' => \&CbPlayerRecord );


# Focus Canvas, if any key pressed. Needed for the following key-bindings
$main->bind('<Any-Enter>' => sub { $map_canvas->Tk::focus });

# Disable default arrow-key bindings on canvas
$main->bind('Tk::Canvas',"<$_>",undef)for qw /Left Right Up Down/;

# keyboard bindings
$map_canvas->Tk::bind( '<Key-space>' , \&CbPlayerPlayPause );
$map_canvas->Tk::bind( '<Key-n>'     , \&CbPlayerNext );
$map_canvas->Tk::bind( '<Key-p>'     , \&CbPlayerPrev );
$map_canvas->Tk::bind( '<Key-f>'     , \&CbPlayerFirst );
$map_canvas->Tk::bind( '<Key-l>'     , \&CbPlayerLast );
$map_canvas->Tk::bind( '<Key-h>'     , \&CbPlayerHome );
$map_canvas->Tk::bind( '<Key-s>'     , \&CbPlayerStop );
$map_canvas->Tk::bind( '<Key-w>'     , \&CbPlayerWptKml );
$map_canvas->Tk::bind( '<Key-k>'     , \&CbPlayerWptKml );
$map_canvas->Tk::bind( '<Key-r>'     , \&CbPlayerWptRandom );
$map_canvas->Tk::bind( '<Key-a>'     , \&CbPlayerRecord );
$map_canvas->Tk::bind( '<Key-m>'     , \&CbPlayerMute );
$map_canvas->Tk::bind( '<Key-v>'     , \&CbPoi );
$map_canvas->Tk::bind( '<Key-0>'     , [\&CbPlayerNum, "0"] );
$map_canvas->Tk::bind( '<Key-1>'     , [\&CbPlayerNum, "1"] );
$map_canvas->Tk::bind( '<Key-2>'     , [\&CbPlayerNum, "2"] );
$map_canvas->Tk::bind( '<Key-3>'     , [\&CbPlayerNum, "3"] );
$map_canvas->Tk::bind( '<Key-4>'     , [\&CbPlayerNum, "4"] );
$map_canvas->Tk::bind( '<Key-5>'     , [\&CbPlayerNum, "5"] );
$map_canvas->Tk::bind( '<Key-6>'     , [\&CbPlayerNum, "6"] );
$map_canvas->Tk::bind( '<Key-7>'     , [\&CbPlayerNum, "7"] );
$map_canvas->Tk::bind( '<Key-8>'     , [\&CbPlayerNum, "8"] );
$map_canvas->Tk::bind( '<Key-9>'     , [\&CbPlayerNum, "9"] );
$map_canvas->Tk::bind( '<Key-Left>'  , [\&CbPlayerMove, -1,  0] );
$map_canvas->Tk::bind( '<Key-Right>' , [\&CbPlayerMove,  1,  0] );
$map_canvas->Tk::bind( '<Key-Up>'    , [\&CbPlayerMove,  0,  1] );
$map_canvas->Tk::bind( '<Key-Down>'  , [\&CbPlayerMove,  0, -1] );
$map_canvas->Tk::bind( '<Key-Escape>', \&CbExit );


#
# dynamic objecs on canvas
#

# current MK position on canvas
$MkPos_x = $MapSizeX/2;
$MkPos_y = $MapSizeY/2;

# Line from MK to Home
$map_canvas->createLine ( $MapSizeX/2, $MapSizeY/2, $MapSizeX/2, $MapSizeY/2,
                          '-tags' => 'MK-Home-Line',
                          '-arrow' => 'none',
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeLine'},
                          '-width' => 3,
                         );
                                                                                 
# Text Entfernung positioniert an der Home-Linie
$map_canvas->createText ( $MapSizeX/2 + 8, $MapSizeY/2 - 8,
                          '-tags' => 'MK-Home-Dist',
                          '-text' => '0 m',
                          '-anchor' => 'w',
                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeDist'},
                          );

# Line from MK to Target, draw invisible out of sight
$map_canvas->createLine ( 0, -100, 0, -100,
                          '-tags' => 'MK-Target-Line',
                          '-arrow' => 'none',
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetLine'},
                          '-width' => 3,
                         );
                                                                                 
# Text Entfernung positioniert an der Target-Linie
$map_canvas->createText ( 0, -100,
                          '-tags' => 'MK-Target-Dist',
                          '-text' => '0 m',
                          '-anchor' => 'w',
                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetDist'},
                          );

# Line from MK to POI, draw invisible out of sight
$map_canvas->createLine ( 0, -200, 0, -200,
                          '-tags' => 'MK-POI-Line',
                          '-arrow' => 'none',
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorPoiLine'},
                          '-stipple' => "stipple4",
                          '-width' => 1,
                         );
$map_canvas->lower('MK-POI-Line', 'Target');

# MK Geschwindigkeits-Vektor
$MapMkSpeedLen = 60;    # Länge Speed-Zeiger
my $x0 = $MapSizeX/2;
my $y0 = $MapSizeY/2;
my $x1 = $MapSizeX/2;
my $y1 = $MapSizeY/2 - $MapMkSpeedLen;
$map_canvas->createLine ( $x0, $y0, $x1, $y1,
                          '-tags' => 'MK-Speed',
                          '-arrow' => 'last',
                          '-arrowshape' => [10, 10, 3 ],
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorSpeedVector'},
                          '-width' => 4,
                         );

# MK als Pfeilspitze einer Linie darstellen
$MapMkLen = 25;
my $x0 = $MapSizeX/2;
my $y0 = $MapSizeY/2 + $MapMkLen/2;
my $x1 = $MapSizeX/2;
my $y1 = $MapSizeY/2 - $MapMkLen/2;
$map_canvas->createLine ( $x0, $y0, $x1, $y1,
                          '-tags' => 'MK-Arrow',
                          '-arrow' => 'last',
                          '-arrowshape' => [25, 30, 10 ],
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorMkSatNo'},
                          '-width' => 1
                         );
                                         
# OSD Texte auf Karte anzeigen
my @Texts = (
            # Tag                 Text         Pos_x           Pos_y  Font
            'MK-OSD-Tim-Label',   "TIM",       $MapSizeX/2 - 40,  20, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Tim-Value',   "00:00",     $MapSizeX/2,       20, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Tim-Left',    "",          $MapSizeX/2 + 90,  20, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Bat-Label',   "BAT",       $MapSizeX/2 - 40,  50, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Bat-Value',   "0.0 V",     $MapSizeX/2,       50, '-*-Arial-Bold-R-Normal--*-270-*',
          # 'MK-OSD-Bat-Level',   "",          $MapSizeX/2 + 90,  50, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Spd-Label',   "SPD",       10,                20, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Spd-Value',   "0.0 km/h",  60,                20, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Alt-Label',   "ALT",       10,                50, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Alt-Value',   "0 m",       60,                50, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Odo-Label',   "ODO",       10,                80, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Odo-Value',   "0.000 km",  60,                80, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Sat-Label',   "SAT",       $MapSizeX - 230,   20, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Sat-Value',   "0",         $MapSizeX - 180,   20, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Wp-Label',    "WPT",       $MapSizeX - 230,   50, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Wp-Value',    "0 / 0",     $MapSizeX - 180,   50, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Mode-Label',  "MOD",       $MapSizeX - 230,   80, '-*-Arial-Bold-R-Normal--*-150-*',
            'MK-OSD-Mode-Value',  "",          $MapSizeX - 180,   80, '-*-Arial-Bold-R-Normal--*-270-*',
            'MK-OSD-Rec-Value',   "",          $MapSizeX - 180,  110, '-*-Arial-Bold-R-Normal--*-200-*',
            );
my $i = 0;
for $Text (0 .. $#Texts/5)
    {
    my $Tag =   $Texts[$i++];
    my $Text =  $Texts[$i++];
    my $Pos_x = $Texts[$i++];
    my $Pos_y = $Texts[$i++];
    my $Font =  $Texts[$i++];

    $map_canvas->createText ( $Pos_x, $Pos_y,
                              '-tags' => $Tag,
                              '-text' => $Text,
                              '-font' => $Font,
                              '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
                              '-anchor' => 'w',
                             );

    }


# Variometer on canvas
my @Polygon;
for ( $y = -100; $y <= 100; $y += 10)
    {
    my $Len = 5;
    if ( ($y % 50) == 0 )
        {
        $Len = 10;
        $map_canvas->createText ( $Len+5, $MapSizeY/2 + $y,
                                  '-tags' => 'Map-Variometer-Skala',
                                  '-text' => sprintf ("%3d", -$y / 10),
                                  '-anchor' => 'w',
                                  '-font' => '-*-Arial-Normal-R-Normal--*-150-*',
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
                          );
        }
    push @Polygon, (   0, $MapSizeY/2 + $y);
    push @Polygon, ($Len, $MapSizeY/2 + $y);
    push @Polygon, (   0, $MapSizeY/2 + $y);
    }

$map_canvas->createLine(@Polygon,
                        '-tags' => 'Map-Variometer',
                        '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
                        '-width' => 2,
                        '-arrow' => 'none',
                       );
# Vario Pointer
$map_canvas->createPolygon( 5, $MapSizeY/2, 20, $MapSizeY/2+10, 20, $MapSizeY/2-10,
                           '-tags' => 'Map-Variometer-Pointer',
                           '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometerPointer'},
                           '-outline' => 'black', '-width' => 1,
                          );

# Tracking Canvas

if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
    {
    # Canvas size
    $TrackSizeX  = 125;
    $TrackSizeY  = 100;
    $TrackOffY   = $TrackSizeY - $MapSizeY + 20;
    $TrackPtrLen = 50;    # Länge Zeiger

    # draw in map-canvas
    $track_canvas = $map_canvas;

    # Ziffernblatt
    my $x0 = $TrackSizeX/2 - $TrackPtrLen;
    my $y0 = $TrackSizeY + $TrackPtrLen - $TrackOffY;
    my $x1 = $TrackSizeX/2 + $TrackPtrLen;
    my $y1 = $TrackSizeY   - $TrackPtrLen - $TrackOffY;
    $track_canvas->createArc ( $x0, $y0, $x1, $y1,
                               '-extent' => '200',
                               '-start' => '-10',
                               '-style' => 'chord',
                               '-outline' => 'gray', '-width' => '1',
                             );

    # Skala Ziffernblatt
    for ($i=0; $i<=180; $i+=15)
        {
        my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 20) * cos( deg2rad $i );
        my $y0 = $TrackSizeY   - ($TrackPtrLen - 20) * sin( deg2rad $i ) - $TrackOffY;
        my $x1 = $TrackSizeX/2 - ($TrackPtrLen - 28) * cos( deg2rad $i );
        my $y1 = $TrackSizeY   - ($TrackPtrLen - 28) * sin( deg2rad $i ) - $TrackOffY;
        $track_canvas->createLine ( $x0, $y0, $x1, $y1,
                                   '-fill' => 'white',
                                   '-width' => 1,
                                  );
        }

    # Skala Beschriftung Ziffernblatt
    for ($i=0; $i<=180; $i+=45)
        {
        my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 12) * cos( deg2rad $i );
        my $y0 = $TrackSizeY   - ($TrackPtrLen - 12) * sin( deg2rad $i ) - $TrackOffY;
        $track_canvas->createText ( $x0, $y0,
                                   '-text' => $i - 90,
                                   '-fill' => 'white',
                                  );
        }

    # Ziffernblatt Beschriftung Einheit
    my $x0 = $TrackSizeX/2;
    my $y0 = $MapSizeY -6;
    $track_canvas->createText ( $x0, $y0,
                                '-text' => "Antenne Winkel",
                                '-justify' => 'center',
                                '-fill' => 'white',
                                );
                                         
    # Zeiger
    my $x0 = $TrackSizeX/2;
    my $y0 = $TrackSizeY - 0 - $TrackOffY;
    my $x1 = $TrackSizeX/2;
    my $y1 = $TrackSizeY - ($TrackPtrLen - 22) - $TrackOffY;
    $track_ptr_id= $track_canvas->createLine ( $x0, $y0, $x1, $y1,
                                               '-tags' => 'Track-Ptr',
                                               '-arrow' => 'last',
                                               '-arrowshape' => [20, 30, 5 ],
                                               '-fill' => 'red',
                                               '-width' => 8,
                                              );
    # Zeiger Center
    my $Dia = 7;
    my $x0 = $TrackSizeX/2 - $Dia;
    my $y0 = $TrackSizeY + $Dia - $TrackOffY;
    my $x1 = $TrackSizeX/2 + $Dia;
    my $y1 = $TrackSizeY   - $Dia - $TrackOffY;
    $track_canvas->createArc ( $x0, $y0, $x1, $y1,
                               '-extent' => '359',
                               '-outline' => 'gray', '-width' => 1,
                               '-fill' => 'gray',
                             );
    }
                                                                                 
#
# Load Start Scenario
#

# Waypoint file
my $CfgVal = $Cfg->{'StartScenario'}->{'WpFile'};
if ( ! -f $CfgVal )
    {
    $CfgVal = $Cfg->{'waypoint'}->{'WpDir'} . "/" . $Cfg->{'StartScenario'}->{'WpFile'};
    }
if ( -f $CfgVal )
    {
    &WpLoadFile($CfgVal);

    # send all Wp to MK
    &WpSendAll();
    }

# KML file
my $CfgVal = $Cfg->{'StartScenario'}->{'KmlFile'};
if ( ! -f $CfgVal )
    {
    $CfgVal = $Cfg->{'waypoint'}->{'KmlDir'} . "/" . $Cfg->{'StartScenario'}->{'KmlFile'};
    }
if ( -f $CfgVal )
    {
    &KmlLoadFile($CfgVal);
    }

# PLayer Mode
my $CfgVal  = $Cfg->{'StartScenario'}->{'PlayerMode'};
if ( $CfgVal =~ /Play/i )  { &PlayerPlay(); }
if ( $CfgVal =~ /Pause/i ) { &PlayerPause(); }
if ( $CfgVal =~ /Home/i )  { &PlayerHome(); }
if ( $CfgVal =~ /Stop/i )  { &PlayerStop(); }

# Player Random Mode
my $CfgVal  = $Cfg->{'StartScenario'}->{'PlayerRandomMode'};
if ( $CfgVal eq "STD" ) { &PlayerRandomStd(); }
if ( $CfgVal eq "RND" ) { &PlayerRandomRnd(); }
if ( $CfgVal eq "MAP" ) { &PlayerRandomMap(); }

# PLayer Wpt/Kml Mode
my $CfgVal  = $Cfg->{'StartScenario'}->{'PlayerWptKmlMode'};
if ( $CfgVal eq "WPT" )  { &PlayerWpt(); }
if ( $CfgVal eq "KML" )  { &PlayerKml(); }

# Audio TTS Mute
my $CfgVal  = $Cfg->{'StartScenario'}->{'AudioMute'};
if ( $CfgVal =~ /y/i )
    {
    $TtsMute = 1;    
    }


#
# Timer
#
require "libmktimer.pl";


MainLoop();   # should never end


#
# GUI Call Back
#

# Player CallBack: Play/Pause button
sub CbPlayerPlayPause()
    {
    if ( ($PlayerMode eq "Pause") or  ($PlayerMode eq "Stop") or  ($PlayerMode eq "Home") )
        {
        &PlayerPlay();
        }
    else
        {
        &PlayerPause();
        }
    }


# Player CallBack: Next
sub CbPlayerNext()
    {
    if ( $PlayerMode ne 'Stop' )
        {
        if ( $PlayerWptKmlMode eq 'WPT' )
           {
           &WpTargetNext();
           }
        if ( $PlayerWptKmlMode eq 'KML' )
           {
           &KmlTargetNext();
           }
        }
    }


# Player CallBack: Prev
sub CbPlayerPrev()
    {
    if ( $PlayerMode ne 'Stop' )
        {
        if ( $PlayerWptKmlMode eq 'WPT' )
           {
           &WpTargetPrev();
           }
        if ( $PlayerWptKmlMode eq 'KML' )
           {
           &KmlTargetPrev();
           }
        }
    }


# Player CallBack: First
sub CbPlayerFirst()
    {
    if ( $PlayerMode ne 'Stop' )
        {
        if ( $PlayerWptKmlMode eq 'WPT' )
           {
           &WpTargetFirst();
           }
        if ( $PlayerWptKmlMode eq 'KML' )
           {
           &KmlTargetFirst();
           }
        }
    }

# Player CallBack: Last
sub CbPlayerLast()
    {
    if ( $PlayerMode ne 'Stop' )
        {
        if ( $PlayerWptKmlMode eq 'WPT' )
           {
           &WpTargetLast();
           }
        if ( $PlayerWptKmlMode eq 'KML' )
           {
           &KmlTargetLast();
           }
        }
    }


# Player CallBack: Home
sub CbPlayerHome()
    {
    if ( $PlayerMode ne 'Stop' )
        {
        &PlayerHome();
        }
    }


# Player CallBack: Stop
sub CbPlayerStop()
    {
    if ( $PlayerMode ne 'Stop' )
        {
        &PlayerStop();
        }
    }


# Player CallBack: Move MK in Pause-Mode
sub CbPlayerMove()
    {
    my ($Id, $DirX, $DirY) = @_;

    if ( $PlayerMode eq 'Pause'  and
         $PlayerPause_Lat ne ""  and  $PlayerPause_Lon ne "" )
        {
        my $Dist = $Cfg->{'waypoint'}->{'PauseMoveDist'} || 1;  # 1m default

        my $BearingTop = &MapAngel() - 90.0;
        my $BearingKey = rad2deg atan2($DirX, $DirY);
        my $Bearing = $BearingTop + $BearingKey;

        ($PlayerPause_Lat, $PlayerPause_Lon) = &MapGpsAt($PlayerPause_Lat, $PlayerPause_Lon, $Dist, $Bearing)
        }
    }


# Player CallBack: Toggle WPT/KML button
sub CbPlayerWptKml()
    {

    if ( $PlayerWptKmlMode =~ /WPT/i )
        {
        &PlayerKml();
        }
    elsif ( $PlayerWptKmlMode =~ /KML/i )
        {
        &PlayerWpt();
        }
    }


# Player CallBack: Toggle Random modes. STD -> RND -> MAP
sub CbPlayerWptRandom()
    {
    if ( $PlayerRandomMode eq "STD" )
        {
        &PlayerRandomRnd();
        }
    elsif ( $PlayerRandomMode eq "RND" )
        {
        &PlayerRandomMap();
        }
    else
        {
        &PlayerRandomStd();
        }
    }


# Player CallBack: Togglle Record KML
sub CbPlayerRecord()
    {
    if ( $PlayerRecordMode =~ /REC/i )
        {
        &PlayerRecordOff();
        }
    elsif ( $PlayerRecordMode eq "" )
        {
        &PlayerRecordOn();
        }
    }


# Player CallBack: Number Keys
sub CbPlayerNum()
    {
    my ($Id, $Num) = @_;

    $CbPlayerKey = "$CbPlayerKey" . "$Num";
    }


# Player CallBack: mute TTS audio
sub CbPlayerMute()
    {
    if ( $TtsMute )
        {
        $TtsMute = 0;
        }
    else
        {
        $TtsMute = 1;
        }
    }

# Switch POI Mode
sub CbPoi()
    {
    if ( $PoiMode )
        {
        $PoiMode = 0;
        &PoiHide();
        }
    else
        {
        $PoiMode = 1;
        &PoiShow();
        }
    }

# CallBack: Exit Mission Cockpit
sub CbExit()
    {
    # stop antenna tracking
    $TrackQueue->enqueue( "IDLE" );

    # wait for tracker shutdown, with timeout
    for ($i=0; $i < 5; $i++)
        {
        if ( $MkTrack{'State'} ne "Idle" )
            {
            sleep 1;
            }
        }

    exit;
    }


#
# subroutines moved to libmkcockpit.pl
# Timer moved to libmktimer.pl
#


__END__