#!/usr/local/bin/perl -w

use Tk;
use Tk::DropSite qw(Sun);
use Tk::DragDrop qw(Sun);
require Tk::TextUndo;
require Tk::FileSelect;
require Tk::Menubar;
use Tk::ErrorDialog;

my $top = MainWindow->new();

$top->bind('Tk::TextUndo','<Alt-KeyPress>','NoOp');
$top->bind('Tk::TextUndo','<Escape>',['tag','remove','sel','1.0','end']);

my $mb = $top->Menubar;

$top->optionAdd('*TextUndo.Background' => '#fff5e1');

my $fs  = $top->Component(FileSelect => 'fs',-width => 25, -height => 8,
                       '-accept'   => sub 
                                     { my $file = shift ; 
                                       return 1 unless -e $file;
                                       return (-r $file) && (-T $file);  
                                     },
                       Name => 'fs', -filter => '*');

my $t = $top->Scrolled(TextUndo, -wrap => 'none', -scrollbars => 'osre');

my $dd = $t->DragDrop(-event => '<Meta-B1-Motion>');
$dd->configure(-startcommand => 
               sub
                {
                 return 1 unless (eval { $t->tagNextrange(sel => '1.0','end')});
                 $dd->configure(-text => $t->get('sel.first','sel.last')); 
                });
                
$t->DropSite(-motioncommand => 
              sub 
               { my ($x,$y) = @_;
                 $t->markSet(insert => "\@$x,$y");
               },
              -dropcommand => 
              sub 
               { my ($seln,$x,$y) = @_;
                 $t->markSet(insert => "\@$x,$y");
                 $t->insert(insert => $t->SelectionGet(-selection => $seln));
               }
             );

$mb->Menubutton(-text => '~File', -menuitems => 
                  [[Button => '~Open',
                   -command => sub { my $file = $fs->Show(-popover => $top, -create => 0, -verify => ['-r']);
                                      $t->Load($file) if (defined $file);
                                   }]]);

$mb->Menubutton(-text => '~File', -menuitems => 
                 [['Button' => '~Save', -command => [ $t , 'Save' ]],
                  ['Button' => 'Save ~As', -command =>
                      sub { 
                           my $file = $fs->Show(-popover => $top, -create => 1, -verify => ['-w']);
                           $t->Save($file) if (defined $file);
                          }],
                  ['Button' => '~Empty', -command => [ $t,'delete','1.0','end']],
                  '',['Button' => 'E~xit', -command => [ \&CheckSave, $t ]],
                 ]);

$mb->Menubutton(-text => '~Edit', -menuitems =>
                [
                 ['Button' => '~Undo',  -command => [$t, 'undo']],'',
                 ['Button' => '~Copy',  -command => [$t, 'clipboardCopy']],
                 ['Button' => 'Cu~t',   -command => [$t, 'clipboardCut']],
                 ['Button' => '~Paste', -command => [$t, 'clipboardPaste']],
                 '',['Button' => 'Select All', -command => [$t, 'selectAll']],
                ]);

$mb->Menubutton(-text => '~Search', -menuitems =>
                [
                 ['Button' => '~Find', -command => [\&AskFind, $t]],
                 ['Button' => '~Replace', -command => [\&AskReplace, $t]],
                ]);

$mb->Menubutton(-text => '~View', -menuitems =>
                [
                 ['Button' => '~Line...', -command => [\&AskLine,$t]],
                ]);

$mb->Menubutton(-text => '~Help', -side => 'right');


$t->pack(-expand => 1, -fill => 'both');

$top->protocol('WM_DELETE_WINDOW',[\&CheckSave,$t]);

if (@ARGV) {
    if (! -e $ARGV[0]) {
        open(FILE,">$ARGV[0]") or die "Could not open $ARGV[0]: $!";
        close(FILE) or die "There was trouble with $ARGV[0]: $!";
    }
    $t->Load($ARGV[0]);
    $t->toplevel->title($t->FileName);
}

$t->bind('<F3>',\&DoFind);

$t->update;
$t->focus;

MainLoop;

sub CheckSave
{
 my $t = shift;
 if ($t->numberChanges)
  {
   my $d = $t->toplevel->Dialog(-text => $t->FileName."\nFile has Changed\nSave Edits ?",
                                -buttons => ['Yes','No','Cancel'], -popover => $t);
   my $rep = $d->Show;
   return if $rep eq 'Cancel';
   if ($rep eq 'Yes')
    {
     $t->Save or return;  
    }
  }
 $t->toplevel->destroy;
}

my $str;

sub DoFind
{
 my $t = shift;
 $str = shift if (@_);
 my $posn = $t->index('insert+1c');
 $t->tag('remove','sel','1.0','end');
 local $_;
 while ($t->compare($posn,'<','end'))
  {
   my ($line,$col) = split(/\./,$posn);
   $_ = $t->get("$line.0","$posn lineend");
   pos($_) = $col; 
   if (/\G(.*)$str/g)
    {
     $col += length($1);
     $posn = "$line.$col";
     $t->SetCursor($posn);
     $t->tag('add','sel',$posn,"$line.".pos($_)); 
     $t->focus;
     return; 
    }
   $posn = $t->index("$posn lineend + 1c");
  } 
}

sub AskFind
{
 my ($t) = @_;
 unless (exists $t->{'AskFind'})
  {
   my $d = $t->{'AskFind'} = $t->Toplevel(-popover => 'cursor', -popanchor => 'nw');
   $d->title('Find...');
   $d->withdraw;
   $d->transient($t->toplevel);
   my $e = $d->Entry->pack;
   $e->bind('<Return>', sub { $d->withdraw; DoFind($t,$e->get); });
   $d->protocol(WM_DELETE_WINDOW =>[withdraw => $d]);
  }
 $t->{'AskFind'}->Popup;
 $t->update;
 $t->{'AskFind'}->focusNext;
}

sub AskLine
{
 my ($t) = @_;
 unless (exists $t->{'AskLine'})
  {
   my $d = $t->{'AskLine'} = $t->Toplevel(-popover => 'cursor', -popanchor => 'nw');
   $d->title('Goto Line ...');
   $d->withdraw;
   $d->transient($t->toplevel);
   my $e = $d->Entry->pack;
   $e->bind('<Return>', 
     sub 
      {
       my $e = shift;
       $d->withdraw;
       my $posn = $e->get.'.0';
       $t->SetCursor($posn);
       $t->focus;
      });
   $d->protocol(WM_DELETE_WINDOW =>[withdraw => $d]);
  }
 $t->{'AskLine'}->Popup;
 $t->update;
 $t->{'AskLine'}->focusNext;

}
__END__

=head1 NAME 

ptked - an editor in Perl/Tk 

=head1 SYNOPSIS

S<  >B<ptked> [I<file-to-edit>]

=head1 DESCRIPTION 

B<ptked> is a simple text editor based on perl/Tk's TextUndo widget.

=cut 




