home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Editores / Perl5 / perl / lib / site / Tk / Widget.pm < prev    next >
Encoding:
Perl POD Document  |  1997-08-10  |  24.8 KB  |  990 lines

  1. # Copyright (c) 1995-1997 Nick Ing-Simmons. All rights reserved.
  2. # This program is free software; you can redistribute it and/or
  3. # modify it under the same terms as Perl itself.
  4. package Tk::Widget;
  5. require Tk;
  6. use AutoLoader;
  7. require DynaLoader;
  8. use strict;
  9.  
  10. use Carp;
  11.  
  12. @Tk::Widget::ISA = qw(DynaLoader Tk);
  13.  
  14. # stubs for 'autoloaded' widget classes
  15. sub Button;
  16. sub Canvas;
  17. sub Checkbutton;
  18. sub Entry;
  19. sub Frame;
  20. sub Label;
  21. sub Listbox;
  22. sub Menu;
  23. sub Menubutton;
  24. sub Message;
  25. sub Scale;
  26. sub Scrollbar;
  27. sub Radiobutton;
  28. sub Text;
  29. sub Toplevel;
  30.  
  31. sub Pixmap;
  32. sub Bitmap;
  33. sub Photo;
  34.  
  35. sub ScrlListbox;
  36. sub Optionmenu; 
  37.  
  38. sub import
  39. {
  40.  my $package = shift;
  41.  carp "use Tk::Widget () to pre-load widgets is deprecated" if (@_ && $^W);
  42.  my $need;
  43.  foreach $need (@_)
  44.   {
  45.    unless (defined &{$need})
  46.     {
  47.      require "Tk/${need}.pm"; 
  48.     }
  49.    croak "Cannot locate $need" unless (defined &{$need});
  50.   }
  51. }
  52.  
  53. # Some tidy-ness functions for winfo stuff
  54.  
  55. sub True  { 1 }
  56. sub False { 0 }
  57.  
  58. use Tk::Submethods( 'grab' =>  [qw(current status release -global)],
  59.                     'focus' => [qw(-force -lastfor)],
  60.                     'pack'  => [qw(configure forget info propagate slaves)],
  61.                     'grid'  => [qw(bbox columnconfigure configure forget info location propagate rowconfigure size slaves)],
  62.                     'form'  => [qw(check configure forget grid info slaves)],
  63.                     'after' => [qw(cancel idle)],
  64.                     'place' => [qw(configure forget info slaves)],
  65.                     'wm'    => [qw(capture release)]
  66.                   );
  67.  
  68. *IsMenu       = \&False;
  69. *IsMenubutton = \&False;
  70.  
  71. Direct Tk::Submethods ( 'winfo' => [qw(cells class colormapfull depth exists
  72.                geometry height id ismapped manager name parent reqheight
  73.                reqwidth rootx rooty screen screencells screendepth screenheight
  74.                screenmmheight screenmmwidth  screenvisual screenwidth visual
  75.                visualsavailable  vrootheight viewable vrootwidth vrootx vrooty
  76.                width x y toplevel children pixels pointerx pointery pointerxy
  77.                server fpixels rgb )]);
  78.  
  79. sub DESTROY
  80. {
  81.  my $w = shift;
  82.  $w->destroy if ($w->IsWidget);
  83. }
  84.  
  85. sub Install 
  86. {
  87.  # Dynamically loaded widgets add their core commands 
  88.  # to the Tk base class here 
  89.  my ($package,$mw) = @_;
  90. }
  91.  
  92. sub ClassInit
  93. {
  94.  # Carry out class bindings (or whatever)
  95.  my ($package,$mw) = @_;
  96.  return $package;
  97. }
  98.  
  99. sub CreateArgs
  100. {
  101.  my ($package,$parent,$args) = @_;
  102.  # Remove from hash %$args any configure-like
  103.  # options which only apply at create time (e.g. -colormap for Frame)
  104.  # return these as a list of -key => value pairs
  105.  # Augment same hash with default values for missing mandatory options,
  106.  # allthough this can be done later in InitObject.
  107.  
  108.  # Honour -class => if present, we have hacked Tk_ConfigureWidget to 
  109.  # allow -class to be passed to any widget.                         
  110.  my @result = ();
  111.  my $class = delete $args->{'-class'};                     
  112.  ($class) = $package =~ /([A-Z][A-Z0-9_]*)$/i unless (defined $class);
  113.  push(@result, '-class' => "\u$class") if (defined $class);
  114.  return @result;
  115. }
  116.  
  117. sub InitObject
  118. {
  119.  my ($obj,$args) = @_;
  120.  # per object initialization, for example populating 
  121.  # with sub-widgets, adding a few object bindings to augment
  122.  # inherited class bindings, changing binding tags.
  123.  # Also another chance to mess with %$args before configure...
  124. }
  125.  
  126. sub SetBindtags
  127. {
  128.  my ($obj) = @_;
  129.  $obj->bindtags([ref($obj),$obj,$obj->toplevel,'all']);
  130. }
  131.  
  132. sub new
  133. {
  134.  local $SIG{'__DIE__'} = \&Carp::croak;
  135.  my $package = shift;
  136.  my $parent  = shift;
  137.  $package->InitClass($parent);
  138.  $parent->BackTrace("Odd number of args to $package->new(...)") unless ((@_ % 2) == 0);
  139.  my %args  = @_;
  140.  my @args  = $package->CreateArgs($parent,\%args);
  141.  my $cmd   = $package->Tk_cmd;
  142.  my $pname = $parent->PathName;
  143.  $pname    = "" if ($pname eq ".");
  144.  my $leaf  = delete $args{'Name'};
  145.  my $lname;
  146.  if (defined $leaf)
  147.   {
  148.    $lname = $pname . "." . $leaf;
  149.   }
  150.  else
  151.   {
  152.    ($leaf) = "\L$package" =~ /([a-z][a-z0-9_]*)$/;
  153.    $lname  = $pname . "." . $leaf;
  154.    # create a hash indexed by leaf name to speed up 
  155.    # creation of a lot of sub-widgets of the same type
  156.    # e.g. entries in Table
  157.    my $key = "_#$leaf";
  158.    $parent->{$key} = 0 unless (exists $parent->{$key});
  159.    while (defined ($parent->Widget($lname)))
  160.     {
  161.      $lname = $pname . "." . $leaf . ++$parent->{$key};
  162.     }
  163.   }
  164.  my $obj = &$cmd($parent, $lname, @args);
  165.  bless $obj,$package;
  166.  $obj->InitObject(\%args);
  167.  $obj->configure(%args) if (%args);
  168.  $obj->SetBindtags;
  169.  return $obj;
  170. }
  171.  
  172. sub DelegateFor
  173. {
  174.  my ($w,$method) = @_;
  175.  while(exists $w->{Delegates})
  176.   {
  177.    my $delegate = $w->{Delegates};
  178.    my $widget = $delegate->{$method};
  179.    $widget = $delegate->{DEFAULT} unless (defined $widget);
  180.    $widget = $w->Subwidget($widget) if (defined $widget && !ref $widget);
  181.    last unless (defined $widget);
  182.    last if $widget == $w;
  183.    $w = $widget;
  184.   }
  185.  return $w;
  186. }
  187.  
  188. sub Delegates
  189. {
  190.  my $cw = shift;
  191.  if (exists $cw->{'Delegates'})
  192.   {
  193.    my $specs = $cw->{'Delegates'};
  194.    while (@_)
  195.     {
  196.      my $key = shift;
  197.      my $val = shift;
  198.      $specs->{$key} = $val;
  199.     }
  200.   }
  201.  else
  202.   {
  203.    $cw->{'Delegates'} = { @_ };
  204.   }
  205.  return $cw->{'Delegates'}
  206. }
  207.  
  208. sub Construct
  209. {
  210.  my ($base,$name) = @_;
  211.  my $class = (caller(0))[0];
  212.  no strict 'refs';
  213.  
  214.  # DelegateFor  trickyness is to allow Frames and other derived things
  215.  # to force creation in a delegate e.g. a ScrlText with embeded windows
  216.  # need those windows to be children of the Text to get clipping right
  217.  # and not of the Frame which contains the Text and the scrollbars.
  218.  
  219.  *{$base.'::'."$name"}  = sub { $class->new(shift->DelegateFor('Construct'),@_) };
  220.  *{$base.'::Is'.$name}  = \&False;
  221.  *{$class.'::Is'.$name} = \&True;
  222. }
  223.  
  224. sub IS
  225. {
  226.  return (defined $_[1]) && $_[0] == $_[1];
  227. }
  228.  
  229. sub AUTOLOAD
  230. {
  231.  # Take a copy into a 'my' variable so we can recurse
  232.  my $what = $Tk::Widget::AUTOLOAD;
  233.  my $save = $@;
  234.  my $name;
  235.  # Braces used to preserve $1 et al.
  236.  {
  237.   my ($pkg,$func) = $what =~ /(.*)::([^:]+)$/;
  238.   confess("Attempt to load '$what'") unless defined $pkg;
  239.   $pkg =~ s#::#/#g;
  240.   if (defined($name=$INC{"$pkg.pm"}))
  241.    {
  242.     $name =~ s#^(.*)$pkg\.pm$#$1auto/$pkg/$func.al#;
  243.    }
  244.   else
  245.    {
  246.     $name = "auto/$what.al";
  247.     $name =~ s#::#/#g;
  248.    }
  249.  }
  250.  # This may fail, catch error and prevent user's __DIE__ handler
  251.  # from triggering as well...
  252.  eval {local $SIG{'__DIE__'}; require $name};
  253.  if ($@)
  254.   {
  255.    croak $@ unless ($@ =~ /Can't locate \Q$name\E/);
  256.    my($package,$method) = ($what =~ /^(.*)::([^:]*)$/);
  257.    if ($package eq 'Tk::Widget' && $method ne '__ANON__')
  258.     {
  259.      # carp "Assuming 'require Tk::$method;'" if ($^W);
  260.      require "Tk/$method.pm";
  261.     }
  262.    else 
  263.     {
  264.      if (ref $_[0] && $method !~ /^(ConfigSpecs|Delegates)/ )
  265.       {                                    
  266.        my $delegate = $_[0]->Delegates;    
  267.        if (%$delegate || tied %$delegate)                     
  268.         {                                  
  269.          my $widget = $delegate->{$method};
  270.          $widget = $delegate->{DEFAULT} unless (defined $widget);
  271.          if (defined $widget)              
  272.           {                                
  273.            my $subwidget = (ref $widget) ? $widget : $_[0]->Subwidget($widget);
  274.            if (defined $subwidget)         
  275.             {                              
  276.              no strict 'refs';
  277.              # print "AUTOLOAD: $what\n";
  278.              *{$what} = sub { shift->Delegate($method,@_) }; 
  279.             }                              
  280.            else                            
  281.             {                              
  282.              croak "No delegate subwidget '$widget' for $what";
  283.             }                              
  284.           }                                
  285.         }                                  
  286.        if (!defined(&$what) && $method =~ /^[A-Z]\w+$/ && ref($_[0]) && $_[0]->isa('Tk::Widget'))
  287.         {
  288.          $what = "Tk::Widget::$method";
  289.          carp "Assuming 'require Tk::$method;'" if ($^W);
  290.          require "Tk/$method.pm";
  291.         }
  292.       }                                    
  293.     }
  294.   }
  295.  $@ = $save;
  296.  $DB::sub = $what; # Tell debugger what is going on...
  297.  goto &$what;
  298. }
  299.  
  300. *isa = \&True if ($] <= 5.003);
  301.  
  302. *configure_self = \&Tk::configure;
  303. *cget_self = \&Tk::cget;
  304.  
  305. sub _Destroyed
  306.  my $w = shift;
  307.  my $a = delete $w->{'_Destroy_'};
  308.  return unless ref $a;
  309.  while (@$a)
  310.   {
  311.    eval {local $SIG{'__DIE__'}; pop(@$a)->Call };
  312.   }
  313. }
  314.  
  315. sub privateData
  316. {
  317.  my $w = shift;
  318.  my $p = shift || caller;
  319.  $w->{$p} ||= {};
  320. }
  321.  
  322. 1;                     
  323.  
  324. __END__
  325.  
  326. sub grabSave
  327. {
  328.  my ($w) = @_;
  329.  my $grab = $w->grabCurrent;
  330.  return sub {} if (!defined $grab);
  331.  my $method = ($grab->grabStatus eq 'global') ? 'grabGlobal' : 'grab';
  332.  return sub { eval {local $SIG{'__DIE__'};  $grab->$method() } };
  333. }
  334.  
  335. sub focusCurrent
  336. {
  337.  my ($w) = @_;
  338.  $w->Tk::focus('-displayof'); 
  339. }
  340.  
  341. sub focusSave
  342. {
  343.  my ($w) = @_;
  344.  my $focus = $w->focusCurrent;
  345.  return sub {} if (!defined $focus);
  346.  return sub { eval {local $SIG{'__DIE__'};  $focus->focus } };
  347. }
  348.  
  349. sub OnDestroy
  350. {
  351.  my $w = shift;
  352.  $w->{'_Destroy_'} = [] unless (exists $w->{'_Destroy_'});
  353.  push(@{$w->{'_Destroy_'}},Tk::Callback->new(@_));
  354. }
  355.  
  356. # This is supposed to replicate Tk::after behaviour,
  357. # but does auto-cancel when widget is deleted.
  358.  
  359.  
  360. sub after
  361. {
  362.  require Tk::After;
  363.  my $w = shift;
  364.  my $t = shift;
  365.  if (@_)
  366.   {
  367.    return Tk::After->new($w,$t,'once',@_) if ($t ne 'cancel');
  368.    while (@_)
  369.     {
  370.      my $what = shift;
  371.      if (ref $what)
  372.       {
  373.        $what->cancel;
  374.       }
  375.      else
  376.       {
  377.        carp "dubious cancel of $what";
  378.        $w->Tk::after('cancel' => $what);
  379.       }
  380.     }
  381.   }
  382.  else
  383.   {
  384.    $w->Tk::after($t);
  385.   }
  386. }
  387.  
  388. sub repeat
  389. {
  390.  require Tk::After;
  391.  my $w = shift;
  392.  my $t = shift;
  393.  return Tk::After->new($w,$t,'repeat',@_);
  394. }
  395.  
  396. sub Inherit
  397. {
  398.  carp "Inherit is deprecated - use SUPER::";
  399.  my $w = shift;
  400.  my $method = shift;
  401.  my ($class) = caller;
  402.  *{$class.'::Inherit::ISA'} = \@{$class.'::ISA'} unless (defined @{$class.'::Inherit::ISA'});
  403.  $class .= '::Inherit::';
  404.  $class .= $method;
  405.  return $w->$class(@_);
  406. }
  407.  
  408. sub InheritThis
  409. {
  410.  carp "InheritThis is deprecated - use SUPER::";
  411.  my $w      = shift;
  412.  my $what   = (caller(1))[3];
  413.  my ($class,$method) = $what =~ /^(.*)::([^:]+)$/;
  414.  *{$class.'::Inherit::ISA'} = \@{$class.'::ISA'} unless (defined @{$class.'::Inherit::ISA'});
  415.  $class .= '::Inherit::';
  416.  $class .= $method;
  417.  return $w->$class(@_);
  418. }
  419.  
  420. sub FindMenu
  421. {
  422.  # default FindMenu is that there no menu.
  423.  return undef;
  424. }
  425.  
  426. sub XEvent { shift->{"_XEvent_"} }
  427.  
  428. sub propertyRoot
  429. {
  430.  my $w = shift;
  431.  return $w->property(@_,'root');
  432. }
  433.  
  434. # atom, atomname, containing, interps, pathname 
  435. # don't work this way - there is no window arg
  436. # So we pretend there was an call the C versions from Tk.xs
  437.  
  438. sub atom       { shift->InternAtom(@_)  }
  439. sub atomname   { shift->GetAtomName(@_) }
  440. sub containing { shift->Containing(@_)  }
  441.  
  442.  
  443. # interps not done yet
  444. # pathname not done yet
  445.  
  446. # walk and descendants adapted from Stephen's composite
  447. # versions as they only use core features they can go here.
  448. # hierachy is reversed in that descendants calls walk rather
  449. # than vice versa as this avoids building a list.
  450. # Walk should possibly be enhanced so allow early termination
  451. # like '-prune' of find.
  452.  
  453. sub Walk 
  454. {
  455.  # Traverse a widget hierarchy while executing a subroutine.
  456.  my($cw, $proc, @args) = @_;
  457.  my $subwidget;
  458.  foreach $subwidget ($cw->children) 
  459.   {
  460.    $subwidget->Walk($proc,@args);
  461.    &$proc($subwidget, @args);
  462.   }
  463. } # end walk
  464.  
  465. sub Descendants
  466. {
  467.  # Return a list of widgets derived from a parent widget and all its
  468.  # descendants of a particular class.  
  469.  # If class is not passed returns the entire widget hierarchy.
  470.  
  471.  my($widget, $class) = @_;
  472.  my(@widget_tree)    = ();
  473.  
  474.  $widget->Walk(
  475.                sub { my ($widget,$list,$class) = @_;
  476.                      push(@$list, $widget) if  (!defined($class) or $class eq $widget->class);
  477.                    }, 
  478.                \@widget_tree, $class
  479.               );
  480.  return @widget_tree;
  481.  
  482. sub Palette
  483. {
  484.  my $w = shift->MainWindow;
  485.  unless (exists $w->{_Palette_})
  486.   {
  487.    my %Palette = ();
  488.    my $c = $w->Checkbutton();
  489.    my $e = $w->Entry();
  490.    my $s = $w->Scrollbar();
  491.    $Palette{"activeBackground"}    = ($c->configure("-activebackground"))[3] ;
  492.    $Palette{"activeForeground"}    = ($c->configure("-activeforeground"))[3];
  493.    $Palette{"background"}          = ($c->configure("-background"))[3];
  494.    $Palette{"disabledForeground"}  = ($c->configure("-disabledforeground"))[3];
  495.    $Palette{"foreground"}          = ($c->configure("-foreground"))[3];
  496.    $Palette{"highlightBackground"} = ($c->configure("-highlightbackground"))[3];
  497.    $Palette{"highlightColor"}      = ($c->configure("-highlightcolor"))[3];
  498.    $Palette{"insertBackground"}    = ($e->configure("-insertbackground"))[3];
  499.    $Palette{"selectColor"}         = ($c->configure("-selectcolor"))[3];
  500.    $Palette{"selectBackground"}    = ($e->configure("-selectbackground"))[3];
  501.    $Palette{"selectForeground"}    = ($e->configure("-selectforeground"))[3];
  502.    $Palette{"troughColor"}         = ($s->configure("-troughcolor"))[3];
  503.    $c->destroy;
  504.    $e->destroy;
  505.    $s->destroy;
  506.    $w->{_Palette_} = \%Palette;
  507.   }
  508.  return $w->{_Palette_};
  509. }
  510.  
  511.  
  512. # tk_setPalette --
  513. # Changes the default color scheme for a Tk application by setting
  514. # default colors in the option database and by modifying all of the
  515. # color options for existing widgets that have the default value.
  516. #
  517. # Arguments:
  518. # The arguments consist of either a single color name, which
  519. # will be used as the new background color (all other colors will
  520. # be computed from this) or an even number of values consisting of
  521. # option names and values. The name for an option is the one used
  522. # for the option database, such as activeForeground, not -activeforeground.
  523. sub setPalette
  524. {
  525.  my $w = shift->MainWindow;
  526.  my %new = (@_ == 1) ? (background => $_[0]) : @_;
  527.  my $priority = delete($new{'priority'}) || 'widgetDefault';
  528.  my $i;
  529.  
  530.  # Create an array that has the complete new palette. If some colors
  531.  # aren't specified, compute them from other colors that are specified.
  532.  
  533.  die "must specify a background color" if (!exists $new{background});
  534.  $new{"foreground"} = "black" unless (exists $new{foreground});
  535.  my @bg = $w->rgb($new{"background"});
  536.  my @fg = $w->rgb($new{"foreground"});
  537.  my $darkerBg = sprintf("#%02x%02x%02x",9*$bg[0]/2560,9*$bg[1]/2560,9*$bg[2]/2560);
  538.  foreach $i ("activeForeground","insertBackground","selectForeground","highlightColor")
  539.   {
  540.    $new{$i} = $new{"foreground"} unless (exists $new{$i});
  541.   }
  542.  unless (exists $new{"disabledForeground"})
  543.   {
  544.    $new{"disabledForeground"} = sprintf("#%02x%02x%02x",(3*$bg[0]+$fg[0])/1024,(3*$bg[1]+$fg[1])/1024,(3*$bg[2]+$fg[2])/1024);
  545.   }
  546.  $new{"highlightBackground"} = $new{"background"} unless (exists $new{"highlightBackground"});
  547.  
  548.  unless (exists $new{"activeBackground"})
  549.   {
  550.    my @light;
  551.    # Pick a default active background that is lighter than the
  552.    # normal background. To do this, round each color component
  553.    # up by 15% or 1/3 of the way to full white, whichever is
  554.    # greater.
  555.    foreach $i (0, 1, 2)
  556.     {
  557.      $light[$i] = $bg[$i]/256;
  558.      my $inc1 = $light[$i]*15/100;
  559.      my $inc2 = (255-$light[$i])/3;
  560.      if ($inc1 > $inc2)
  561.       {
  562.        $light[$i] += $inc1
  563.       }
  564.      else
  565.       {
  566.        $light[$i] += $inc2
  567.       }
  568.      $light[$i] = 255 if ($light[$i] > 255);
  569.     }
  570.    $new{"activeBackground"} = sprintf("#%02x%02x%02x",@light);
  571.   }
  572.  $new{"selectBackground"} = $darkerBg unless (exists $new{"selectBackground"});
  573.  $new{"troughColor"} = $darkerBg unless (exists $new{"troughColor"});
  574.  $new{"selectColor"} = "#b03060" unless (exists $new{"selectColor"});
  575.  
  576.  # Before doing this, make sure that the Tk::Palette variable holds
  577.  # the default values of all options, so that tkRecolorTree can
  578.  # be sure to only change options that have their default values.
  579.  # If the variable exists, then it is already correct (it was created
  580.  # the last time this procedure was invoked). If the variable
  581.  # doesn't exist, fill it in using the defaults from a few widgets.
  582.  my $Palette = $w->Palette;
  583.  
  584.  # Walk the widget hierarchy, recoloring all existing windows.
  585.  $w->RecolorTree(\%new);
  586.  # Change the option database so that future windows will get the
  587.  # same colors.
  588.  my $option;
  589.  foreach $option (keys %new)
  590.   {
  591.    $w->option("add","*$option",$new{$option},$priority);
  592.    # Save the options in the global variable Tk::Palette, for use the
  593.    # next time we change the options.
  594.    $Palette->{$option} = $new{$option};
  595.   }
  596. }
  597.  
  598. # tkRecolorTree --
  599. # This procedure changes the colors in a window and all of its
  600. # descendants, according to information provided by the colors
  601. # argument. It only modifies colors that have their default values
  602. # as specified by the Tk::Palette variable.
  603. #
  604. # Arguments:
  605. # w - The name of a window. This window and all its
  606. # descendants are recolored.
  607. # colors - The name of an array variable in the caller,
  608. # which contains color information. Each element
  609. # is named after a widget configuration option, and
  610. # each value is the value for that option.
  611. sub RecolorTree
  612. {
  613.  my ($w,$colors) = @_;
  614.  my $dbOption;
  615.  local ($@);
  616.  my $Palette = $w->Palette;
  617.  foreach $dbOption (keys %$colors)
  618.   {
  619.    my $option = "-\L$dbOption";
  620.    my $value;
  621.    eval {local $SIG{'__DIE__'}; $value = $w->cget($option) };
  622.    if (defined $value)
  623.     {
  624.      if ($value eq $Palette->{$dbOption})
  625.       {
  626.        $w->configure($option,$colors->{$dbOption})
  627.       }
  628.     }
  629.   }
  630.  my $child;
  631.  foreach $child ($w->children)
  632.   {
  633.    $child->RecolorTree($colors);
  634.   }
  635. }
  636. # tkDarken --
  637. # Given a color name, computes a new color value that darkens (or
  638. # brightens) the given color by a given percent.
  639. #
  640. # Arguments:
  641. # color - Name of starting color.
  642. # perecent - Integer telling how much to brighten or darken as a
  643. # percent: 50 means darken by 50%, 110 means brighten
  644. # by 10%.
  645. sub Darken
  646. {
  647.  my ($w,$color,$percent) = @_;
  648.  my @l = $w->rgb($color);
  649.  my $red = $l[0]/256;
  650.  my $green = $l[1]/256;
  651.  my $blue = $l[2]/256;
  652.  $red = int($red*$percent/100);
  653.  $red = 255 if ($red > 255);
  654.  $green = int($green*$percent/100);
  655.  $green = 255 if ($green > 255);
  656.  $blue = int($blue*$percent/100);
  657.  $blue = 255 if ($blue > 255);
  658.  sprintf("#%02x%02x%02x",$red,$green,$blue)
  659. }
  660. # tk_bisque --
  661. # Reset the Tk color palette to the old "bisque" colors.
  662. #
  663. # Arguments:
  664. # None.
  665. sub bisque
  666. {
  667.  shift->setPalette("activeBackground" => "#e6ceb1",
  668.                "activeForeground" => "black",
  669.                "background" => "#ffe4c4",
  670.                "disabledForeground" => "#b0b0b0",
  671.                "foreground" => "black",
  672.                "highlightBackground" => "#ffe4c4",
  673.                "highlightColor" => "black",
  674.                "insertBackground" => "black",
  675.                "selectColor" => "#b03060",
  676.                "selectBackground" => "#e6ceb1",
  677.                "selectForeground" => "black",
  678.                "troughColor" => "#cdb79e"
  679.               );
  680. }
  681.  
  682. sub PrintConfig
  683. {
  684.  require Tk::Pretty;
  685.  my ($w) = (@_);
  686.  my $c;
  687.  foreach $c ($w->configure)
  688.   {
  689.    print Tk::Pretty::Pretty(@$c),"\n";
  690.   }
  691.  
  692. sub Busy
  693. {
  694.  my ($w,%args) = @_;
  695.  return unless $w->viewable;
  696.  $args{'-cursor'} = 'watch' unless (exists $args{'-cursor'});
  697.  unless (exists $w->{'Busy'})
  698.   {
  699.    my %old = ();           
  700.    my $key;                
  701.    my @tags = $w->bindtags;
  702.    foreach $key (keys %args)
  703.     {
  704.      $old{$key} = $w->Tk::cget($key);
  705.     }
  706.    $old{'bindtags'} = \@tags;
  707.    $old{'grab'}     = $w->grabSave;
  708.    unless ($w->Tk::bind('Busy'))
  709.     {                     
  710.      $w->Tk::bind('Busy','<KeyPress>','bell');
  711.      $w->Tk::bind('Busy','<ButtonPress>','bell');
  712.     }                     
  713.    $w->bindtags(['Busy']);
  714.    $w->{'Busy'} = \%old;
  715.   }
  716.  $w->Tk::configure(%args);
  717.  eval {local $SIG{'__DIE__'};  $w->grab };
  718.  $w->update;
  719. }
  720.  
  721. sub Unbusy
  722. {
  723.  my ($w) = @_;
  724.  $w->grabRelease;
  725.  my $old = delete $w->{'Busy'};
  726.  if (defined $old)
  727.   {
  728.    my $grab = delete $old->{'grab'};
  729.    $w->update;  # flush events that happened with Busy bindings
  730.    $w->bindtags(delete $old->{'bindtags'});
  731.    $w->Tk::configure(%{$old}); 
  732.    $w->update;
  733.    &$grab;
  734.   }
  735. }
  736.  
  737. sub waitVisibility
  738. {
  739.  my ($w) = shift;
  740.  $w->tkwait('visibility',$w);
  741. }
  742.  
  743. sub waitVariable
  744. {
  745.  my ($w) = shift;
  746.  $w->tkwait('variable',@_);
  747. }
  748.  
  749. sub waitWindow
  750. {
  751.  my ($w) = shift;
  752.  $w->tkwait('window',$w);
  753. }
  754.  
  755. sub EventWidget
  756. {
  757.  my ($w) = @_;
  758.  return $w->{'_EventWidget_'};
  759. }
  760.  
  761. sub Popwidget
  762. {
  763.  my ($ew,$method,$w,@args) = @_;
  764.  $w->{'_EventWidget_'} = $ew;
  765.  $w->$method(@args);
  766. }
  767.  
  768. sub ColorOptions
  769. {
  770.  my ($w,$args) = @_;
  771.  my $opt;
  772.  $args = {} unless (defined $args);
  773.  foreach $opt (qw(-foreground -background -disabledforeground
  774.                   -activebackground -activeforeground
  775.               ))
  776.   {
  777.    $args->{$opt} = $w->cget($opt) unless (exists $arg{$opt})
  778.   }
  779.  return (wantarray) ? %$args : $args;
  780. }
  781.  
  782. sub XscrollBind
  783. {
  784.  my ($mw,$class) = @_;
  785.  $mw->bind($class,'<Left>',         ['xview','scroll',-1,'units']);
  786.  $mw->bind($class,'<Control-Left>', ['xview','scroll',-1,'pages']);
  787.  $mw->bind($class,'<Control-Prior>',['xview','scroll',-1,'pages']);
  788.  $mw->bind($class,'<Right>',        ['xview','scroll',1,'units']);
  789.  $mw->bind($class,'<Control-Right>',['xview','scroll',1,'pages']);
  790.  $mw->bind($class,'<Control-Next>', ['xview','scroll',1,'pages']);
  791.  
  792.  $mw->bind($class,'<Home>',         ['xview','moveto',0]);
  793.  $mw->bind($class,'<End>',          ['xview','moveto',1]);
  794. }
  795.  
  796. sub PriorNextBind
  797. {
  798.  my ($mw,$class) = @_;
  799.  $mw->bind($class,'<Next>',     ['yview','scroll',1,'pages']);
  800.  $mw->bind($class,'<Prior>',    ['yview','scroll',-1,'pages']);
  801. }
  802.  
  803. sub YscrollBind
  804. {
  805.  my ($mw,$class) = @_;
  806.  $mw->PriorNextBind($class);
  807.  $mw->bind($class,'<Up>',       ['yview','scroll',-1,'units']);
  808.  $mw->bind($class,'<Down>',     ['yview','scroll',1,'units']);
  809. }
  810.  
  811. sub XYscrollBind
  812. {
  813.  my ($mw,$class) = @_;
  814.  $mw->YscrollBind($class);
  815.  $mw->XscrollBind($class);
  816. }
  817.  
  818. sub ScrlListbox
  819. {
  820.  my $parent = shift; 
  821.  return $parent->Scrolled('Listbox',-scrollbars => 'w', @_);
  822. }
  823.  
  824. sub AddBindTag
  825. {
  826.  my ($w,$tag) = @_;
  827.  my $t;
  828.  my @tags = $w->bindtags;
  829.  foreach $t (@tags)
  830.   {
  831.    return if $t eq $tag;
  832.   }
  833.  $w->bindtags([@tags,$tag]);
  834. }
  835.  
  836. sub Callback
  837. {
  838.  my $w = shift;
  839.  my $name = shift;
  840.  my $cb = $w->cget($name);
  841.  return $cb->Call(@_) if (defined $cb);
  842.  return (wantarray) ? () : undef;
  843. }
  844.  
  845. sub packAdjust
  846. {
  847.  print 'packAdjust(',join(',',@_),")\n";
  848.  require Tk::Adjuster;
  849.  my ($w,%args) = @_;
  850.  my $delay = delete($args{'-delay'});
  851.  $delay = 1 unless (defined $delay);
  852.  $w->pack(%args);
  853.  %args = $w->packInfo;
  854.  my $adj = Tk::Adjuster->new($args{'-in'},
  855.             -widget => $w, -delay => $delay, -side => $args{'-side'});
  856.  $adj->packed($w,%args);
  857.  return $w;
  858. }
  859.  
  860. sub gridAdjust
  861. {
  862.  require Tk::Adjuster;
  863.  my ($w,%args) = @_;
  864.  my $delay = delete($args{'-delay'});
  865.  $delay = 1 unless (defined $delay);
  866.  $w->grid(%args);
  867.  %args = $w->gridInfo;
  868.  my $adj = Tk::Adjuster->new($args{'-in'},-widget => $w, -delay => $delay);
  869.  $adj->gridded($w,%args);
  870.  return $w;
  871. }
  872.  
  873. sub place
  874. {
  875.  local $SIG{'__DIE__'} = \&Carp::croak;
  876.  my $w = shift;
  877.  if (@_ && $_[0] =~ /^(?:configure|forget|info|slaves)$/x)
  878.   {
  879.    $w->Tk::place(@_);
  880.   }
  881.  else
  882.   {
  883.    # Two things going on here:
  884.    # 1. Add configure on the front so that we can drop leading '-' 
  885.    $w->Tk::place('configure',@_);
  886.    # 2. Return the widget rather than nothing
  887.    return $w;
  888.   }
  889. }
  890.  
  891. sub pack
  892. {
  893.  local $SIG{'__DIE__'} = \&Carp::croak;
  894.  my $w = shift;
  895.  if (@_ && $_[0] =~ /^(?:configure|forget|info|propagate|slaves)$/x)
  896.   {
  897.    $w->Tk::pack(@_);
  898.   }
  899.  else
  900.   {
  901.    # Two things going on here:
  902.    # 1. Add configure on the front so that we can drop leading '-' 
  903.    $w->Tk::pack('configure',@_);
  904.    # 2. Return the widget rather than nothing
  905.    return $w;
  906.   }
  907. }
  908.  
  909. sub grid
  910. {
  911.  local $SIG{'__DIE__'} = \&Carp::croak;
  912.  my $w = shift;
  913.  if (@_ && $_[0] =~ /^(?:bbox|columnconfigure|configure|forget|info|location|propagate|rowconfigure|size|slaves)$/x)
  914.   {
  915.    my $opt = shift;
  916.    Tk::grid($opt,$w,@_);
  917.   }
  918.  else
  919.   {
  920.    # Two things going on here:
  921.    # 1. Add configure on the front so that we can drop leading '-' 
  922.    Tk::grid('configure',$w,@_);
  923.    # 2. Return the widget rather than nothing
  924.    return $w;
  925.   }
  926. }
  927.  
  928. sub form
  929. {
  930.  local $SIG{'__DIE__'} = \&Carp::croak;
  931.  my $w = shift;
  932.  if (@_ && $_[0] =~ /^(?:configure|check|forget|grid|info|slaves)$/x)
  933.   {
  934.    $w->Tk::form(@_);
  935.   }
  936.  else
  937.   {
  938.    # Two things going on here:
  939.    # 1. Add configure on the front so that we can drop leading '-' 
  940.    $w->Tk::form('configure',@_);
  941.    # 2. Return the widget rather than nothing
  942.    return $w;
  943.   }
  944. }
  945.  
  946. sub Scrolled
  947. {
  948.  my ($parent,$kind,%args) = @_;
  949.  my @args = Tk::Frame->CreateArgs($parent,\%args);
  950.  my $name = delete $args{'Name'};
  951.  push(@args,'Name' => $name) if (defined $name);
  952.  my $cw = $parent->Frame(@args);
  953.  @args = ();
  954.  my $k;
  955.  # Need to consider other 'Frame' configure options...
  956.  foreach $k ('-scrollbars',map($_->[0],$cw->configure))
  957.   {
  958.    push(@args,$k,delete($args{$k})) if (exists $args{$k})
  959.   }
  960.  $cw->ConfigSpecs('-scrollbars' => ['METHOD','scrollbars','Scrollbars','se'],
  961.                   '-background' => ['CHILDREN','background','Background',undef], 
  962.                  );
  963.  my $w  = $cw->$kind(%args);
  964.  %args = @args;
  965.  $cw->AddScrollbars($w);
  966.  $cw->Default("\L$kind" => $w);
  967.  $cw->ConfigDefault(\%args);
  968.  $cw->configure(%args);
  969.  return $cw;
  970. }
  971.  
  972. sub Populate
  973. {
  974.  my ($cw,$args) = @_;
  975. }
  976.  
  977. sub ForwardEvent
  978. {
  979.  my $self = shift;
  980.  my $to   = shift;
  981.  $to->PassEvent($self->XEvent);
  982. }
  983.  
  984.  
  985.  
  986.  
  987.