The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Text::Editor::Easy::Graphic::Tk_glue::Canva;

use base qw/Tk::Canvas/;
Construct Tk::Widget 'EditorCanva';

sub ClassInit {
    my ($class, $mw) = @_;
    
    # Don't look for default bindings
    #$class->SUPER::ClassInit($mw);
    
    # Adding "CanvasRaise" method, which enables to modify
    # stack order of Canvas objects between them
    *CanvasRaise = \&Tk::raise;
    *CanvasLower = \&Tk::lower;
}

package Text::Editor::Easy::Graphic;

use warnings;
use strict;

=head1 NAME

Text::Editor::Easy::Graphic::Tk_glue - Link between "Text::Editor::Easy::Abstract" and "Tk".

=head1 VERSION

Version 0.49

=cut

our $VERSION = '0.49';

use Tk;
use Tk::Scrollbar;    # perl2exe
use Tk::Canvas;       # perl2exe

use Scalar::Util qw(refaddr);

# A un canevas, on fait correspondre un éditeur, l'éditeur qui a le focus
my %editor;

my %graphic;    # Liste des objets graphiques créés
my $repeat_id;

my %zone;
my %global_zone;

use constant {
    TOP_LEVEL => 0,
    CANVA     => 1,
    SCROLLBAR => 2,
    FIND      => 3,
    ZONE      => 4,

    # FIND
    #TOP_LEVEL => 0,
    ENTRY  => 1,
    REGEXP => 2,
};

sub new {
    my ( $class, $hash_ref ) = @_;

    my $self = [];
    bless $self, $class;
    $self->initialize($hash_ref);

    # Référencement
    $graphic{ refaddr $self} = $self;
    return $self;
}

sub initialize {
    my ( $self, $hash_ref ) = @_;
    my $mw;
    if ( $hash_ref->{main_window} ) {

        #print "La fenêtre principale a déjà été créée\n";
        $mw = $hash_ref->{main_window};
    }
    elsif (%graphic) {    # La mainwindow est déjà créée, on reprend la même
        for ( keys %graphic ) {
            if ( $_ != refaddr $self ) {
                $mw = $graphic{$_}->get_mw;

                # Cancel de la boucle provisoire
                $repeat_id->cancel;
                last;
            }
        }
    }
    else {
        $mw = create_main_window(
            $hash_ref->{'width'},    $hash_ref->{'height'},
            $hash_ref->{'x_offset'}, $hash_ref->{'y_offset'},
            $hash_ref->{'title'},
            $hash_ref->{'destroy'},
        );
    }
    $self->[TOP_LEVEL] = $mw;

    #$self->[SCROLLBAR] = create_scrollbar (
    #  $mw,
    #  $hash_ref->{vertical_scrollbar_sub},
    #    $hash_ref->{vertical_scrollbar_position},
    # );
    my $canva;
    my $zone_ref = $hash_ref->{'zone'};
    if ( $hash_ref->{canvas} ) {

        #print "Le canevas existe déjà\n";
        $canva = $hash_ref->{canvas};
    }
    else {
        ( $canva, $zone_ref ) = create_canva(
            $mw,
            $hash_ref->{background},
            $hash_ref->{'zone'},
            -xscrollincrement => 0,
            -yscrollincrement => 0,
        );
    }
    my $zone_name = $zone_ref->{'name'};
    #print "Affectation du nom de zone $zone_name à l'objet graphique $self\n";
    $self->[ZONE] = $zone_name;
    $global_zone{$zone_name} = $zone_ref;
    if ( $hash_ref->{editor_ref} ) {
        $editor{ refaddr $canva} = $hash_ref->{editor_ref};
    }
    $self->[CANVA] = $canva;

    #print "CANVA est un objet de type ", ref $canva, "\n";

    #$canva->bindtags(undef);
    #$canva->bind('text', <KeyPress>, sub {}) ;
    #$mw->bind('Tk::text', <KeyPress>, sub {}) ;


# CLIC SUBSET
    $canva->CanvasBind( '<Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => '',
    } ] );
    
    $canva->CanvasBind( '<Alt-Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => 'alt_',
    } ] );
    
    $canva->CanvasBind( '<Control-Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'ctrl_',
    } ] );

    $canva->CanvasBind( '<Shift-Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'shift_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Control-Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'alt_ctrl_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Shift-Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'alt_shift_',
    } ] );
    
    $canva->CanvasBind( '<Control-Shift-Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'ctrl_shift_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Control-Shift-Button-1>', [
         \&redirect_x_y, $hash_ref->{'clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'alt_ctrl_shift_',
    } ] );

# DOUBLE CLIC SUBSET
    $canva->CanvasBind( '<Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => '',
    } ] );

    $canva->CanvasBind( '<Alt-Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => 'alt_',
    } ] );
    
    $canva->CanvasBind( '<Control-Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'ctrl_',
    } ] );

    $canva->CanvasBind( '<Shift-Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'shift_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Control-Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'alt_ctrl_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Shift-Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'alt_shift_',
    } ] );
    
    $canva->CanvasBind( '<Control-Shift-Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'ctrl_shift_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Control-Shift-Double-Button-1>', [
         \&redirect_x_y, $hash_ref->{'double_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'alt_ctrl_shift_',
    } ] );
    
# RIGHT CLIC SUBSET
    $canva->CanvasBind( '<Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => '',
    } ] );

    $canva->CanvasBind( '<Alt-Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => 'alt_',
    } ] );
    
    $canva->CanvasBind( '<Control-Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'ctrl_',
    } ] );

    $canva->CanvasBind( '<Shift-Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'shift_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Control-Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'alt_ctrl_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Shift-Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'alt_shift_',
    } ] );
    
    $canva->CanvasBind( '<Control-Shift-Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'ctrl_shift_',
    } ] );
    
    $canva->CanvasBind( '<Alt-Control-Shift-Button-3>', [
         \&redirect_x_y, $hash_ref->{'right_clic'}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'alt_ctrl_shift_',
    } ] );


# MOUSE WHEEL SUBSET
    $canva->CanvasBind( '<MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'}, 
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => '',
    ] );

    $canva->CanvasBind( '<Alt-MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'},
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => 'alt_',
    ] );
    
    $canva->CanvasBind( '<Control-MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'},
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'ctrl_',
    ] );

    $canva->CanvasBind( '<Shift-MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'},
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'shift_',
    ] );
    
    $canva->CanvasBind( '<Alt-Control-MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'},
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'alt_ctrl_',
    ] );
    
    $canva->CanvasBind( '<Alt-Shift-MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'},
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'alt_shift_',
    ] );
    
    $canva->CanvasBind( '<Control-Shift-MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'},
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'ctrl_shift_',
    ] );
    
    $canva->CanvasBind( '<Alt-Control-Shift-MouseWheel>', [
        \&redirect, $hash_ref->{'mouse_wheel_event'},
            'unit' => Ev('D'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'alt_ctrl_shift_',
    ] );

# MOTION SUBSET
    $canva->CanvasBind( '<Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => '',
    } ] );
        
    $canva->CanvasBind( '<Alt-Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => 'alt_',
    } ] );

    $canva->CanvasBind( '<Control-Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'ctrl_',
    } ] );

    $canva->CanvasBind( '<Shift-Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'shift_',
    } ] );

    $canva->CanvasBind( '<Alt-Control-Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'alt_ctrl_',
    } ] );

    $canva->CanvasBind( '<Alt-Shift-Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'alt_shift_',
    } ] );

    $canva->CanvasBind( '<Control-Shift-Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'ctrl_shift_',
    } ] );

    $canva->CanvasBind( '<Alt-Control-Shift-Motion>', [
         \&redirect_x_y, $hash_ref->{motion}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'alt_ctrl_shift_',
    } ] );

# DRAG SUBSET
    $canva->CanvasBind( '<B1-Motion>', [
         \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => '',
    } ] );

    $canva->CanvasBind( '<Alt-B1-Motion>', [
        \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 0, },
            'meta' => 'alt_',
    } ] );

    $canva->CanvasBind( '<Control-B1-Motion>', [
         \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'ctrl_',
    } ] );

    $canva->CanvasBind( '<Shift-B1-Motion>', [
        \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'shift_',
    } ] );

    $canva->CanvasBind( '<Alt-Control-B1-Motion>', [
        \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 0, },
            'meta' => 'alt_ctrl_',
    } ] );

    $canva->CanvasBind( '<Alt-Shift-B1-Motion>', [
        \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 1, },
            'meta' => 'alt_shift_',
    } ] );

    $canva->CanvasBind( '<Control-Shift-B1-Motion>', [
        \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'ctrl_shift_',
    } ] );

    $canva->CanvasBind( '<Alt-Control-Shift-B1-Motion>', [
        \&redirect_x_y, $hash_ref->{drag}, Ev('x'), Ev('y'), {
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 1, },
            'meta' => 'alt_ctrl_shift_',
    } ] );


    $canva->CanvasBind( '<Configure>',
        [ \&resize, $hash_ref->{resize}, Ev('w'), Ev('h') ] );

# KEY_PRESS SUBSET
    $canva->CanvasBind( '<KeyPress>' =>
        [ \&redirect,$hash_ref->{key_press}, 
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'ctrl'  => 0, 'alt'   => 0, 'shift' => 0},
            'meta'      => '',
        ]
    );
    $canva->CanvasBind( '<Alt-KeyPress>' => 
        [ \&redirect,$hash_ref->{key_press}, 
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 0},
            'meta'      => 'alt_',
        ]
    );
    $canva->CanvasBind( '<Control-KeyPress>' => 
        [ \&redirect,$hash_ref->{key_press}, 
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 0},
            'meta'      => 'ctrl_',
        ]
    );
    $canva->CanvasBind( '<Shift-KeyPress>' => 
        [ \&redirect, $hash_ref->{key_press},
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 0, 'shift' => 1},
            'meta'      => 'shift_',
        ]
    );
    $canva->CanvasBind( '<Control-Shift-KeyPress>' => 
        [ \&redirect, $hash_ref->{key_press},
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'alt'   => 0, 'ctrl'  => 1, 'shift' => 1 },
            'meta'      => 'ctrl_shift_',
        ]
    );
    $canva->CanvasBind( '<Control-Alt-KeyPress>' => 
        [ \&redirect, $hash_ref->{key_press},
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 0},
            'meta'      => 'alt_ctrl_',
        ]
    );

    $canva->CanvasBind( '<Shift-Alt-KeyPress>' => 
        [ \&redirect, $hash_ref->{key_press},
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 0, 'shift' => 1},
            'meta'      => 'alt_shift_',
        ]
    );

    $canva->CanvasBind( '<Shift-Alt-Control-KeyPress>' => 
        [ \&redirect, $hash_ref->{key_press},
            'key'       => Ev('K'),
            'text'      => Ev('A'),
            'uni'       => Ev('N'),
            'ascii'     => Ev('k'),
            'meta_hash' => { 'alt'   => 1, 'ctrl'  => 1, 'shift' => 1},
            'meta'      => 'alt_ctrl_shift_',
        ]
    );
    
    $canva->xviewMoveto(0);
    $canva->yviewMoveto(0);

    #$mw->repeat(10, [ $hash_ref->{repeat}, $editor{refaddr $canva} ] );
}

sub launch_loop {
    my ( $self, $sub, $seconds ) = @_;

   #print "Lancement d'une boucle seconds = $seconds\n";
    
   return $self->[TOP_LEVEL]->repeat( $seconds * 1000, $sub );
}

sub set_repeat_id {
    my ( $self, $id ) = @_;
    $repeat_id = $id;
}

sub redirect {
    my ( $canva, $sub_ref, @data ) = @_;

    my $editor_ref = $editor{ refaddr $canva};
    my %info = @data;
    #my $return = $sub_ref->( $editor_ref, @data );
    my $return = $sub_ref->( $editor_ref, \%info );
    $return = 'event not yet traced' if ( ! defined $return );
    Text::Editor::Easy->trace_end_of_user_event( $return );
}

sub redirect_x_y {
    my ( $canva, $sub_ref, $x, $y, $info_ref ) = @_;

    my $editor_ref = $editor{ refaddr $canva};
    $info_ref->{'x'} = $x;
    $info_ref->{'y'} = $y;
    
    my $return = $sub_ref->( $editor_ref, $info_ref );
    $return = 'event not yet traced' if ( ! defined $return );
    Text::Editor::Easy->trace_end_of_user_event( $return );
}

sub key_press {
    my ( $canva, $self, $sub_ref, $key, $ascii ) = @_;
    my $editor_ref = $editor{ refaddr $canva};

    if ( $key eq "Control_L" or $key eq "Control_R" ) {
        return;
    }
    if ( $key eq "Alt_L" ) {
        return;
    }
    if ( $key eq "Shift_L" or $key eq "Shift_R" ) {
        return;
    }

    my $return = $sub_ref->(
        $editor_ref,
        $key, $ascii,
        {
            'ctrl'  => 0,
            'alt'   => 0,
            'shift' => 0,
        }
    );

    # Tk->break ne marche pas car le déplacement du canevas s'effectue avant :
    # touches up, down, right et left
    $canva->xviewMoveto(0);
    $canva->yviewMoveto(0);
    $return = 'event not yet traced' if ( ! defined $return );
    Text::Editor::Easy->trace_end_of_user_event ( $return );
}

sub create_main_window {
    my ( $width, $height, $x, $y, $title, $sub_ref_destroy ) = @_;
    my $mw = MainWindow->new( -title => $title );
    
    if ( ref $sub_ref_destroy ) {
        #print "subref_destroy : $sub_ref_destroy, ", ref $sub_ref_destroy, "\n";
        #$mw->bind( '<Destroy>', [ \&destroy, $mw ] );
        $mw->bind( 'MainWindow', '<Destroy>', [ \&destroy, $sub_ref_destroy ] );
    #$canva->CanvasBind( '<Configure>', [ \&resize, $hash_ref->{resize}, Ev('w'), Ev('h') ] );

    }
    
    if ( defined $width and $height ) {
        if ( defined $x and $y ) {
            $mw->geometry("${width}x$height+$x+$y");
        }
        else {
            $mw->geometry("${width}x$height");
        }
    }
    #$mw->geometry("${width}x$height+$x+$y");
    return $mw;
}

sub destroy {
    my ( $mw, $sub_ref ) = @_;

    print "MW = $mw ", ref $mw, ", sub_ref = $sub_ref\n";
    my $geometry = $mw->geometry;
    my ( $width, $height, $x, $y ) = $geometry =~ /((?:-|)\d+)x((?:-|)\d+)\+((?:-|)\d+)\+((?:-|)\d+)/;
    print "Geométrie : ", $mw->geometry, "\n";
    print "Dans destroy\n";
    $sub_ref->( $width, $height, $x, $y );
}

sub get_geometry {
    my ($self) = @_;

    my $geometry = $self->[TOP_LEVEL]->geometry;
    my ( $width, $height, $x, $y ) = $geometry =~ /((?:-|)\d+)x((?:-|)\d+)\+((?:-|)\d+)\+((?:-|)\d+)/;
    return ( $width, $height, $x, $y, $geometry );
}

sub set_geometry {
    my ( $self, $width, $height, $x, $y ) = @_;

    $self->[TOP_LEVEL]->geometry("${width}x$height+$x+$y");
}

sub change_title {
    my ( $self, $title ) = @_;

    $self->[TOP_LEVEL]->configure( -title => $title );
}

sub create_scrollbar {
    my ( $mw, $call_back_ref, $position ) = @_;

    my $scrollbar =
      $mw->Scrollbar( -command => $call_back_ref, )
      ->pack( -side => $position, -fill => 'y' );
    return $scrollbar;    # inutile mais plus prudent en cas d'ajout...
}

sub create_canva {
    my ( $mw, $color, $zone_ref ) = @_;
    my %zone_local;
    if ( !defined $zone_ref ) {
        %zone_local = (
            'size' => {
                -x         => 0,
                -y         => 0,
                -relwidth  => 1,
                -relheight => 1,
            },
            'name'     => 'none'
        );
        Text::Editor::Easy->reference_zone( \%zone_local );
        $zone_ref = \%zone_local;
    }
    else {
        %zone_local = %$zone_ref;
    }

    #print "DAns create canva : ", $zone_ref->{'name'}, "\n";
    my $size_ref = $zone_local{'size'};
    
    my $canva = $mw->EditorCanva(
        -background => $color,
        #)->pack( -expand => 1, -fill => 'both' );
    )->place( -in => $mw, %{ $size_ref } );
    
    #print "\n\nDump des évènement gérés :\n";
    #Tk::Widget::bindDump( $mw );
    #print "Fin du dump :\n\n";
    
    $canva->CanvasLower;
    return ( $canva, $zone_ref );
}

sub create_font {
    my ( $graphic, $hash_ref ) = @_;
    my @underline;
    if ( $hash_ref->{underline} ) {
        @underline = ( "-underline", 1 );
    }
    my @slant = ( "-slant", "roman" );
    if ( $hash_ref->{slant} ) {
        @slant = ( "-slant", $hash_ref->{slant} );
    }
    return $graphic->[TOP_LEVEL]->fontCreate(
        -family => $hash_ref->{family},
        -size   => $hash_ref->{size},
        -weight => $hash_ref->{weight},
        @underline,
        @slant,
    );
}

sub clipboard_get {
    my ( $self ) = @_;
        
    my $string = $self->[TOP_LEVEL]->SelectionGet( 
        -selection => "CLIPBOARD" ,
        -type => "STRING"
    );
    
    # Null character not managed by Tk (?)
    # My former regular exp didn't work ===> s/x00.*$//
    my @lines = split( /\n/, $string, -1 );
    my $buffer = q{};
    my $line = shift( @lines );
    for my $indice ( 0..length($line)-1 ) {
        my $char = substr( $line, $indice, 1 );
        if ( ord($char) == 0 ) {
            return $buffer;
        }
        $buffer .= $char;
    }

    CONCAT: for my $line ( @lines ) {
        $buffer .= "\n";
        for my $indice ( 0..length($line)-1 ) {
            my $char = substr( $line, $indice, 1 );
            if ( ord($char) == 0 ) {
                return $buffer;
            }
            $buffer .= $char;
        }
    }
    return $buffer;
}

sub clipboard_set {
    my ( $self, $string ) = @_;
        
    #print "Dans clipboard_set de Tk_glue |$self|$string|\n";
    # usefull ?
    $self->[TOP_LEVEL]->clipboardClear;

    $self->[TOP_LEVEL]->clipboardAppend('--', $string);
    return 1;
}

sub manage_event {

    #my ( $self ) = @_;
    #print "On rentre dans la mainloop\n";
    MainLoop;
}

# After initialisation

sub length_text {
    my ( $self, $text, $font ) = @_;
    
    if ( $text =~ /^(-+)/ ) {
        # Le texte "-d" est malheureusement vu comme une option "display_of" de la méthode fontMeasure dans Tk
        # L'appel Tk font->measure ne marchant pas mieux (pas du tout !), il faut décomposer toutes les chaînes qui commencent par un "-"
        my $length = 0;
        $length += $self->[CANVA]->fontMeasure( $font, "$1" );
        $text = substr ( $text, length($1) );
        $length += $self->[CANVA]->fontMeasure( $font, $text );
        return $length;
    }
        
    return $self->[CANVA]->fontMeasure( $font, $text );
}

sub set_scrollbar {
    my ( $self, $top, $bottom ) = @_;

    #$self->[SCROLLBAR]->set ( $top, $bottom);
    return ( $top, $bottom );
}

sub get_scrollbar {
    my ($self) = @_;

    #return $self->[SCROLLBAR]->get;
}

my $line_offset = 3;

sub create_text_and_mark_it {
    my ( $self, $hash_ref ) = @_;

    my $id = $self->[CANVA]->createText(
        $hash_ref->{abs},
        $hash_ref->{ord},

        #-tag    => ['text', 'just_created'] ,
        -tag    => $hash_ref->{tag},
        -text   => $hash_ref->{text},
        -anchor => $hash_ref->{anchor},
        -font   => $hash_ref->{font},
        -fill   => $hash_ref->{color},
    );
    my ( $x1, $y1, $x2, $y2 ) = $self->[CANVA]->bbox($id);

#    $self->[CANVA]->bind('text', <KeyPress>, sub {}) ;
#    $self->[TOP_LEVEL]->bind('Tk::text', <KeyPress>, sub {}) ;

    #return ( $id, $x2 - $x1 - 2, $y2 - $y1 - 2);
    return ( $id, $x2 - $x1 - 2, $y2 - $y1 + $line_offset );

}

sub size_id {
    my ( $self, $id ) = @_;

    my ( $x1, $y1, $x2, $y2 ) = $self->[CANVA]->bbox($id);

    #return ( $x2 - $x1 - 2, $y2 - $y1 - 2);
    return ( $x2 - $x1 - 2, $y2 - $y1 + $line_offset );
}

sub increase_line_offset {
    $line_offset += 1;
}

sub decrease_line_offset {
    $line_offset -= 1;
}

sub create_text {
    my ( $self, $hash_ref ) = @_;

    my $id = $self->[CANVA]->createText(
        $hash_ref->{abs},
        $hash_ref->{ord},
        -tag    => 'text',
        -text   => $hash_ref->{text},
        -anchor => $hash_ref->{anchor},
        -font   => $hash_ref->{font},
        -fill   => $hash_ref->{color},
    );
    my ( $x1, $y1, $x2, $y2 ) = $self->[CANVA]->bbox($id);

    #$self->[CANVA]->bind('text', <KeyPress>, sub {}) ;
    #$self->[TOP_LEVEL]->bind('Tk::text', <KeyPress>, sub {}) ;

    return ( $id, $x2 - $x1 - 2, $y2 - $y1 - 2 );

}

sub delete_mark_from_text {
    my ($self) = @_;

    $self->[CANVA]->dtag( 'just_created', 'just_created' );
}

sub delete_tag {
    my ( $self, $tag ) = @_;

    $self->[CANVA]->dtag( $tag, $tag );
}

sub change_text_item_property {
    my ( $self, $text_id, $text ) = @_;

    $self->[CANVA]->itemconfigure( $text_id, -text, $text );
}

sub delete_text_item {
    my ( $self, $text_id ) = @_;

    $self->[CANVA]->delete($text_id);
}

sub position_cursor_in_text_item {
    my ( $self, $text_id, $position ) = @_;

    #$self->[CANVA]->CanvasFocus;
    $self->[CANVA]->focus($text_id);
    $self->[CANVA]->icursor( $text_id, $position );
}

sub canva_focus {
    my ($self) = @_;

    $self->[CANVA]->CanvasFocus;
}

sub at_top {
    my ($self) = @_;

    $self->[CANVA]->CanvasRaise;
    #my %local_zone = %{ $self->[ZONE] };
    my $zone_name = $self->[ZONE];

    #print "Appel de at_top pour l'objet graphique $self, nom de zone : $zone_name\n";

    return if ( ! defined $zone_name );

    $zone{ $zone_name } = $self;

    my %local_zone = %{ $global_zone{$zone_name} };
    
    $self->[CANVA]->place( -in => $self->[TOP_LEVEL], %{ $local_zone{'size'} } );

    #$self->[CANVA]->CanvasFocus;
}

sub focus {
    my ($self) = @_;

    at_top($self);
    $self->[CANVA]->CanvasFocus;
}

sub get_zone {
    my ($self) = @_;

    return $self->[ZONE];
}

sub get_graphic_focused_in_zone {
    my ( $self, $zone ) = @_;

    if ( !defined $zone ) {
        print STDERR
"Zone must be defined when calling Text::Editor::Graphic::Tk_gue::get_graphic_focused_in_zone\nCan't return Text::Editor::Easy who has focus in an undefined zone\n";
        return;
    }
    return $zone{$zone};
}

sub get_editor_focused_in_zone {
    my ( $self, $zone ) = @_;

    if ( !defined $zone ) {
        print STDERR
"Zone must be defined when calling Text::Editor::Graphic::Tk_gue::get_graphic_focused_in_zone\nCan't return Text::Editor::Easy who has focus in an undefined zone\n";
        return;
    }
    my $graphic = $zone{$zone};
    #print "Dans get_editor_focused_in_zone : zone $zone, graphic = $graphic|", $graphic->[CANVA], "\n";
    if ( ! defined $graphic or ! defined ( refaddr $graphic->[CANVA] ) ) {
        #print STDERR "Can't find focused canva in zone $zone\n";
        return;
    }
    my $editor = $editor{ refaddr ($graphic->[CANVA]) };
    if ( wantarray ) {
        return ( $graphic, $editor );
    }
    else {
        return $editor;
    }
}

sub forget {
    my ($self) = @_;

    return if ( ! $self->[CANVA] );
    $self->[CANVA]->placeForget;
}

sub resize {
    my ( $canva, $sub_ref, $height, $width ) = @_;

    #$canva->configure( -scrollregion => [ 2, 2, $width - 2, $height - 2] );
    $canva->configure( -scrollregion => [ 1, 1, $width - 1, $height - 1 ] );

    my $editor_ref = $editor{ refaddr $canva};

    #print "Avant appel resize : $editor_ref\n";
    #print "\t$editor_ref->[8]\n";
    #print "\t$editor_ref\n";
    $sub_ref->( $editor_ref, $height, $width );
}

sub move_tag {
    my ( $self, $tag, $x, $y ) = @_;

    $self->[CANVA]->move( $tag, $x, $y );
}

sub destroy_find {
    my ( $find, $self ) = @_;

    undef $self->[FIND][TOP_LEVEL];
}

sub change_reference {

    # Avant d'appeler cette fonction, faire le ménage sur le canevas
    my ( $self, $edit_ref, $file_name ) = @_;

    $editor{ refaddr $self->[CANVA] } = $edit_ref;
    $self->[TOP_LEVEL]->configure( -title => $file_name );
}

sub edit_ref {
    my ( $self ) = @_;
    
    return $editor{ refaddr $self->[CANVA] };
}

sub get_displayed_editor {
    my ($editor) = @_;

    my $canva = $editor->[CANVA];
    return $editor{ refaddr $canva };
}

sub set_font_size {
    my ( $self, $font, $size ) = @_;

    $font->delete;
    $font->configure( -size => $size );
}

sub line_height {
    return 30;
}

sub margin {
    return 10;
}

sub clear_screen {
    my ($self) = @_;

    $self->[CANVA]->delete('text');
}

sub key_release {
    my ( undef, $self, $key ) = @_;

    if ( $key eq "Control_L" or $key eq "Control_R" ) {
        return;
    }
    if ( $key eq "Alt_L" ) {
        return;
    }
    if ( $key eq "Shift_L" or $key eq "Shift_R" ) {
        return;
    }
}

sub move_bottom {
    my ( $self, $how_much ) = @_;

    #print "TK glue : move bottom de $how_much\n";
    $self->[CANVA]->move( 'bottom', 0, $how_much * 17 );
}

sub add_tag {
    my ( $self, $tag, $id, $debug ) = @_;
    
#    if ( $debug ) {
#        print "\$self $self, \$canva ", $self->[CANVA], " \$tag $tag, \$id $id\n";
#    }        
    $self->[CANVA]->addtag( $tag, 'withtag', $id );
#    if ( $debug ) {
#        print "Fin de add_tag\n";
#    }        
}

sub select {
    my ( $self, $x1, $y1, $x2, $y2, $color, $tag ) = @_;

    if ( !defined $color ) {
        $color = 'yellow';
    }

    #print "$x1|$y1|$x2|$y2|\n";
    my @tag = ( '-tag'  => 'select' );
    if ( defined $tag ) {
        #print "Tag défini : $tag\n";
        @tag = ( '-tag'  => [ 'select', $tag ] );
    }

    $self->[CANVA]->createRectangle(
        $x1, $y1, $x2, $y2,
        -fill => $color,
        @tag
    );
    $self->[CANVA]->lower( 'select', 'text' );
}

sub delete_select {
    my ($self) = @_;

    #print "Suppression des zones sélectionnées...\n";

    $self->[CANVA]->delete('select');
}

sub delete_whose_tag {
    my ($self, $tag) = @_;

    return if ( ! defined $tag );

    $self->[CANVA]->delete($tag);
}

sub get_mw {
    my ($self) = @_;

    return $self->[TOP_LEVEL];
}

sub cursor_set_shape {
        my ( $self, $type ) = @_;
        
        #$self->[CANVA]->configure(-cursor => 'sb_h_double_arrow');
        $self->[CANVA]->configure(-cursor => $type);
        #$self->[CANVA]->configure(-cursor => 'top_left_arrow');
}

sub cursor_get_shape {
    my ( $self ) = @_;
        
        #$self->[CANVA]->configure(-cursor => 'sb_h_double_arrow');
    return $self->[CANVA]->cget('-cursor');
}

sub kill {
    my ( $self ) = @_;
    
    $self->[CANVA]->destroy;

    delete $editor{ refaddr($self->[CANVA]) };
    undef $self->[CANVA];
    delete $graphic{ refaddr $self};
}

sub zone_update {
    my ( $self, $name, $hash_ref ) = @_;
    
    print "Dans Tk_glue zone_update : name = $name\n";
    $self = get_graphic_focused_in_zone ( $self, $name );
    $global_zone{$name} = $hash_ref;
    
    if ( ! defined $self ) {
        print STDERR "No 'Text::Editor::Easy::Graphic' instance found on top of zone named $name\n";
        return;
    }
    $self->forget;
    $self->at_top;
}

sub put_at_top {
    my ( $self ) = @_;
    
    $self->[CANVA]->CanvasRaise;
}

sub set_background {
    my ( $self, $color ) = @_;
    
    eval {
        $self->[CANVA]->configure( -background => $color );
    }
}

sub background {
    my ( $self ) = @_;
    
    return $self->[CANVA]->cget('-background');
}
    

=head1 COPYRIGHT & LICENSE

Copyright 2008 - 2009 Sebastien Grommier, all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut

1;