home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / ActivePerl-5.8.4.810-MSWin32-x86.msi / _3931055eb36d7d7e2599914b473b8b02 < prev    next >
Encoding:
Text File  |  2004-06-01  |  26.8 KB  |  986 lines

  1. # Copyright (c) 1999 Greg London. 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.  
  5. # code for bindings taken from Listbox.pm
  6.  
  7. # comments specifying method functionality taken from
  8. # "Perl/Tk Pocket Reference" by Stephen Lidie.
  9.  
  10. #######################################################################
  11. # this module uses a text module as its base class to create a list box.
  12. # this will allow list box functionality to also have all the functionality
  13. # of the Text widget.
  14. #
  15. # note that most methods use an element number to indicate which
  16. # element in the list to work on.
  17. # the exception to this is the tag and mark methods which
  18. # are dual natured. These methods may accept either the
  19. # normal element number, or they will also take a element.char index,
  20. # which would be useful for applying tags to part of a line in the list.
  21. #
  22. #######################################################################
  23.  
  24. package Tk::TextList;
  25.  
  26. use strict;
  27. use vars qw($VERSION);
  28. $VERSION = '4.005'; # $Id: //depot/Tkutf8/TextList/TextList.pm#5 $
  29.  
  30. #XXXdel: use Tk::Reindex qw(Tk::ROText); #XXXdel: ReindexedROText);
  31.  
  32. use base qw(Tk::Derived Tk::ReindexedROText );
  33.  
  34. use Tk qw (Ev);
  35.  
  36. #XXX del: use base qw(Tk::ReindexedROText);
  37.  
  38. Construct Tk::Widget 'TextList';
  39.  
  40. #######################################################################
  41. # the following line causes Populate to get called
  42. # @ISA = qw(Tk::Derived ... );
  43. #######################################################################
  44. sub Populate
  45. {
  46.  my ($w,$args)=@_;
  47.  my $option=delete $args->{'-selectmode'};
  48.  $w->SUPER::Populate($args);
  49.  $w->ConfigSpecs( -selectmode  => ['PASSIVE','selectMode','SelectMode','browse'],
  50.           -takefocus   => ['PASSIVE','takeFocus','TakeFocus',1],
  51.           -spacing3    => ['SELF', undef, undef, 3],
  52.           -insertwidth => ['SELF', undef, undef, 0],
  53.         );
  54.  
  55. }
  56.  
  57. #######################################################################
  58. #######################################################################
  59. sub ClassInit
  60. {
  61.  my ($class,$mw) = @_;
  62.  
  63.  # Standard Motif bindings:
  64.  $mw->bind($class,'<1>',['BeginSelect',Ev('index',Ev('@'))]);
  65.  $mw->bind($class,'<B1-Motion>',['Motion',Ev('index',Ev('@'))]);
  66.  $mw->bind($class,'<ButtonRelease-1>','ButtonRelease_1');
  67.  
  68.  $mw->bind($class,'<Shift-1>',['BeginExtend',Ev('index',Ev('@'))]);
  69.  $mw->bind($class,'<Control-1>',['BeginToggle',Ev('index',Ev('@'))]);
  70.  
  71.  $mw->bind($class,'<B1-Leave>',['AutoScan',Ev('x'),Ev('y')]);
  72.  $mw->bind($class,'<B1-Enter>','CancelRepeat');
  73.  $mw->bind($class,'<Up>',['UpDown',-1]);
  74.  $mw->bind($class,'<Shift-Up>',['ExtendUpDown',-1]);
  75.  $mw->bind($class,'<Down>',['UpDown',1]);
  76.  $mw->bind($class,'<Shift-Down>',['ExtendUpDown',1]);
  77.  
  78.  $mw->XscrollBind($class);
  79.  $mw->PriorNextBind($class);
  80.  
  81.  $mw->bind($class,'<Control-Home>','Cntrl_Home');
  82.  
  83.  $mw->bind($class,'<Shift-Control-Home>',['DataExtend',0]);
  84.  $mw->bind($class,'<Control-End>','Cntrl_End');
  85.  
  86.  $mw->bind($class,'<Shift-Control-End>',['DataExtend','end']);
  87.  $class->clipboardOperations($mw,'Copy');
  88.  $mw->bind($class,'<space>',['BeginSelect',Ev('index','active')]);
  89.  $mw->bind($class,'<Select>',['BeginSelect',Ev('index','active')]);
  90.  $mw->bind($class,'<Control-Shift-space>',['BeginExtend',Ev('index','active')]);
  91.  $mw->bind($class,'<Shift-Select>',['BeginExtend',Ev('index','active')]);
  92.  $mw->bind($class,'<Escape>','Cancel');
  93.  $mw->bind($class,'<Control-slash>','SelectAll');
  94.  $mw->bind($class,'<Control-backslash>','Cntrl_backslash');
  95.  ;
  96.  # Additional Tk bindings that aren't part of the Motif look and feel:
  97.  $mw->bind($class,'<2>',['scan','mark',Ev('x'),Ev('y')]);
  98.  $mw->bind($class,'<B2-Motion>',['scan','dragto',Ev('x'),Ev('y')]);
  99.  
  100.  $mw->bind($class,'<FocusIn>' , ['tagConfigure','_ACTIVE_TAG', -underline=>1]);
  101.  $mw->bind($class,'<FocusOut>', ['tagConfigure','_ACTIVE_TAG', -underline=>0]);
  102.  
  103.  return $class;
  104. }
  105.  
  106. #######################################################################
  107. # set the active element to index
  108. # "active" is a text "mark" which underlines the marked text.
  109. #######################################################################
  110. sub activate
  111. {
  112.  my($w,$element)=@_;
  113.  $element= $w->index($element).'.0';
  114.  $w->SUPER::tag('remove', '_ACTIVE_TAG', '1.0','end');
  115.  $w->SUPER::tag('add', '_ACTIVE_TAG',
  116.    $element.' linestart', $element.' lineend');
  117.  $w->SUPER::mark('set', 'active', $element);
  118. }
  119.  
  120.  
  121. #######################################################################
  122. # bbox returns a list (x,y,width,height) giving an approximate
  123. # bounding box of character given by index
  124. #######################################################################
  125. sub bbox
  126. {
  127.  my($w,$element)=@_;
  128.  $element=$w->index($element).'.0' unless ($element=~/./);
  129.  return $w->SUPER::bbox($element);
  130. }
  131.  
  132. #######################################################################
  133. # returns a list of indices of all elements currently selected
  134. #######################################################################
  135. sub curselection
  136. {
  137.  my ($w)=@_;
  138.  my @ranges = $w->SUPER::tag('ranges', 'sel');
  139.  my @selection_list;
  140.  while (@ranges)
  141.   {
  142.    my ($first,$firstcol) = split(/\./,shift(@ranges));
  143.    my ($last,$lastcol) = split(/\./,shift(@ranges));
  144.  
  145.    #########################################################################
  146.    # if previous selection ended on the same line that this selection starts,
  147.    # then fiddle the numbers so that this line number isnt included twice.
  148.    #########################################################################
  149.    if (defined($selection_list[-1]) and ($first == $selection_list[-1]))
  150.     {
  151.      $first++; # count this selection starting from the next line.
  152.     }
  153.  
  154.    if ($lastcol==0)
  155.     {
  156.     $last-=1;
  157.     }
  158.  
  159.    #########################################################################
  160.    # if incrementing $first causes it to be greater than $last,
  161.    # then do nothing,
  162.    # else add (first .. last) to list
  163.    #########################################################################
  164.    unless ($first>$last)
  165.     {
  166.     push(@selection_list, $first .. $last);
  167.     }
  168.   }
  169.  return @selection_list;
  170. }
  171.  
  172.  
  173. #######################################################################
  174. # deletes range of elements from element1 to element2
  175. # defaults to element1
  176. #######################################################################
  177. sub delete
  178. {
  179.  my ($w, $element1, $element2)=@_;
  180.  $element1=$w->index($element1);
  181.  $element2=$element1 unless(defined($element2));
  182.  $element2=$w->index($element2);
  183.  $w->SUPER::delete($element1.'.0' , $element2.'.0 lineend');
  184. }
  185.  
  186. #######################################################################
  187. # deletes range of characters from index1 to index2
  188. # defaults to index1+1c
  189. # index is line.char notation.
  190. #######################################################################
  191. sub deleteChar
  192. {
  193.  my ($w, $index1, $index2)=@_;
  194.  $index1=$w->index($index1);
  195.  $index2=$index1.' +1c' unless(defined($index2));
  196.  $index2=$w->index($index2);
  197.  $w->SUPER::delete($index1, $index2);
  198. }
  199.  
  200. #######################################################################
  201. # returns as a list contents of elements from $element1 to $element2
  202. # defaults to element1.
  203. #######################################################################
  204. sub get
  205. {
  206.  my ($w, $element1, $element2)=@_;
  207.  $element1=$w->index($element1);
  208.  $element2=$element1 unless(defined($element2));
  209.  $element2=$w->index($element2);
  210.  my @getlist;
  211.  for(my $i=$element1; $i<=$element2; $i++)
  212.   {
  213.   push(@getlist, $w->SUPER::get($i.'.0 linestart', $i.'.0 lineend'));
  214.   }
  215.  
  216.  return @getlist;
  217. }
  218.  
  219. #######################################################################
  220. # return text between index1 and index2 which are line.char notation.
  221. # return value is a single string. index2 defaults to index1+1c
  222. # index is line.char notation.
  223. ######################################################################
  224. sub getChar
  225. {
  226.  my $w=shift;
  227.  return $w->SUPER::get(@_);
  228. }
  229.  
  230. #######################################################################
  231. # returns index in number notation
  232. # this method returns an element number, ie the 5th element.
  233. #######################################################################
  234. sub index
  235. {
  236.  my ($w,$element)=@_;
  237.  return undef unless(defined($element));
  238.  $element .= '.0' unless $element=~/\D/;
  239.  $element = $w->SUPER::index($element);
  240.  my($line,$col)=split(/\./,$element);
  241.  return $line;
  242. }
  243.  
  244. #######################################################################
  245. # returns index in line.char notation
  246. # this method returns an index specific to a character within an element
  247. #######################################################################
  248. sub indexChar
  249. {
  250.  my $w=shift;
  251.  return $w->SUPER::index(@_);
  252. }
  253.  
  254.  
  255. #######################################################################
  256. # inserts specified elements just before element at index
  257. #######################################################################
  258. sub insert
  259. {
  260.  my $w=shift;
  261.  my $element=shift;
  262.  $element=$w->index($element);
  263.  my $item;
  264.  while (@_)
  265.   {
  266.   $item = shift(@_);
  267.   $item .= "\n";
  268.   $w->SUPER::insert($element++.'.0', $item);
  269.   }
  270. }
  271.  
  272. #######################################################################
  273. # inserts string just before character at index.
  274. # index is line.char notation.
  275. #######################################################################
  276. sub insertChar
  277. {
  278.  my $w=shift;
  279.  $w->SUPER::insert(@_);
  280. }
  281.  
  282.  
  283.  
  284. #######################################################################
  285. # returns index of element nearest to y-coordinate
  286. #
  287. # currently not defined
  288. #######################################################################
  289. #sub nearest
  290. #{
  291. # return undef;
  292. #}
  293.  
  294. #######################################################################
  295. # Sets the selection anchor to element at index
  296. #######################################################################
  297. sub selectionAnchor
  298. {
  299.  my ($w, $element)=@_;
  300.  $element=$w->index($element);
  301.  $w->SUPER::mark('set', 'anchor', $element.'.0');
  302. }
  303.  
  304. #######################################################################
  305. #  deselects elements between index1 and index2, inclusive
  306. #######################################################################
  307. sub selectionClear
  308. {
  309.  my ($w, $element1, $element2)=@_;
  310.  $element1=$w->index($element1);
  311.  $element2=$element1 unless(defined($element2));
  312.  $element2=$w->index($element2);
  313.  $w->SUPER::tag('remove', 'sel', $element1.'.0', $element2.'.0 lineend +1c');
  314. }
  315.  
  316. #######################################################################
  317. # returns 1 if element at index is selected, 0 otherwise.
  318. #######################################################################
  319. sub selectionIncludes
  320. {
  321.  my ($w, $element)=@_;
  322.  $element=$w->index($element);
  323.  my @list = $w->curselection;
  324.  my $line;
  325.  foreach $line (@list)
  326.   {
  327.   if ($line == $element) {return 1;}
  328.   }
  329.  return 0;
  330. }
  331.  
  332. #######################################################################
  333. # adds all elements between element1 and element2 inclusive to selection
  334. #######################################################################
  335. sub selectionSet
  336. {
  337.  my ($w, $element1, $element2)=@_;
  338.  $element1=$w->index($element1);
  339.  $element2=$element1 unless(defined($element2));
  340.  $element2=$w->index($element2);
  341.  $w->SUPER::tag('add', 'sel', $element1.'.0', $element2.'.0 lineend +1c');
  342. }
  343.  
  344. #######################################################################
  345. # for ->selection(option,args) calling convention
  346. #######################################################################
  347. sub selection
  348. {
  349. # my ($w,$sub)=(shift,"selection".ucfirst(shift));
  350. # no strict 'refs';
  351. # # can't use $w->$sub, since it might call overridden method-- bleh
  352. # &($sub)($w,@_);
  353. }
  354.  
  355.  
  356. #######################################################################
  357. # adjusts the view in window so element at index is completely visible
  358. #######################################################################
  359. sub see
  360. {
  361.  my ($w, $element)=@_;
  362.  $element=$w->index($element);
  363.  $w->SUPER::see($element.'.0');
  364. }
  365.  
  366. #######################################################################
  367. # returns number of elements in listbox
  368. #######################################################################
  369. sub size
  370. {
  371.  my ($w)=@_;
  372.  my $element = $w->index('end');
  373.  # theres a weird thing with the 'end' mark sometimes being on a line
  374.  # with text, and sometimes being on a line all by itself
  375.  my ($text) = $w->get($element);
  376.  if (length($text) == 0)
  377.   {$element -= 1;}
  378.  return $element;
  379. }
  380.  
  381.  
  382.  
  383. #######################################################################
  384. # add a tag based on element numbers
  385. #######################################################################
  386. sub tagAdd
  387. {
  388.  my ($w, $tagName, $element1, $element2)=@_;
  389.  $element1=$w->index($element1);
  390.  $element1.='.0';
  391.  
  392.  $element2=$element1.' lineend' unless(defined($element2));
  393.  $element2=$w->index($element2);
  394.  $element2.='.0 lineend +1c';
  395.  
  396.  $w->SUPER::tag('add', $tagName, $element1, $element2);
  397. }
  398.  
  399. #######################################################################
  400. # add a tag based on line.char indexes
  401. #######################################################################
  402. sub tagAddChar
  403. {
  404.  my $w=shift;
  405.  $w->SUPER::tag('add',@_);
  406. }
  407.  
  408.  
  409. #######################################################################
  410. # remove a tag based on element numbers
  411. #######################################################################
  412. sub tagRemove
  413. {
  414.  my ($w, $tagName, $element1, $element2)=@_;
  415.  $element1=$w->index($element1);
  416.  $element1.='.0';
  417.  
  418.  $element2=$element1.' lineend' unless(defined($element2));
  419.  $element2=$w->index($element2);
  420.  $element2.='.0 lineend +1c';
  421.  
  422.  $w->SUPER::tag('remove', 'sel', $element1, $element2);
  423. }
  424.  
  425. #######################################################################
  426. # remove a tag based on line.char indexes
  427. #######################################################################
  428. sub tagRemoveChar
  429. {
  430.  my $w=shift;
  431.  $w->SUPER::tag('remove', @_);
  432. }
  433.  
  434.  
  435.  
  436.  
  437. #######################################################################
  438. # perform tagNextRange based on element numbers
  439. #######################################################################
  440. sub tagNextRange
  441. {
  442.  my ($w, $tagName, $element1, $element2)=@_;
  443.  $element1=$w->index($element1);
  444.  $element1.='.0';
  445.  
  446.  $element2=$element1 unless(defined($element2));
  447.  $element2=$w->index($element2);
  448.  $element2.='.0 lineend +1c';
  449.  
  450.  my $index = $w->SUPER::tag('nextrange', 'sel', $element1, $element2);
  451.  my ($line,$col)=split(/\./,$index);
  452.  return $line;
  453. }
  454.  
  455. #######################################################################
  456. # perform tagNextRange based on line.char indexes
  457. #######################################################################
  458. sub tagNextRangeChar
  459. {
  460.  my $w=shift;
  461.  $w->SUPER::tag('nextrange', @_);
  462. }
  463.  
  464. #######################################################################
  465. # perform tagPrevRange based on element numbers
  466. #######################################################################
  467. sub tagPrevRange
  468. {
  469.  my ($w, $tagName, $element1, $element2)=@_;
  470.  $element1=$w->index($element1);
  471.  $element1.='.0';
  472.  
  473.  $element2=$element1 unless(defined($element2));
  474.  $element2=$w->index($element2);
  475.  $element2.='.0 lineend +1c';
  476.  
  477.  my $index = $w->SUPER::tag('prevrange', 'sel', $element1, $element2);
  478.  my ($line,$col)=split(/\./,$index);
  479.  return $line;
  480. }
  481.  
  482. #######################################################################
  483. # perform tagPrevRange based on line.char indexes
  484. #######################################################################
  485. sub tagPrevRangeChar
  486. {
  487.  my $w=shift;
  488.  $w->SUPER::tag('prevrange', @_);
  489. }
  490.  
  491.  
  492.  
  493. #######################################################################
  494. # perform markSet based on element numbers
  495. #######################################################################
  496. sub markSet
  497. {
  498.  my ($w,$mark,$element1)=@_;
  499.  $element1=$w->index($element1);
  500.  $element1.='.0';
  501.  $w->SUPER::mark('set', $element1,$mark);
  502. }
  503.  
  504. #######################################################################
  505. # perform markSet based on line.char indexes
  506. #######################################################################
  507. sub markSetChar
  508. {
  509.  my $w=shift;
  510.  $w->SUPER::mark('set', @_);
  511. }
  512.  
  513. #######################################################################
  514. # perform markNext based on element numbers
  515. #######################################################################
  516. sub markNext
  517. {
  518.  my ($w,$element1)=@_;
  519.  $element1=$w->index($element1);
  520.  $element1.='.0';
  521.  return $w->SUPER::mark('next', $element1);
  522. }
  523.  
  524. #######################################################################
  525. # perform markNext based on line.char indexes
  526. #######################################################################
  527. sub markNextChar
  528. {
  529.  my $w=shift;
  530.  $w->SUPER::mark('next', @_);
  531. }
  532.  
  533.  
  534. #######################################################################
  535. # perform markPrevious based on element numbers
  536. #######################################################################
  537. sub markPrevious
  538. {
  539.  my ($w,$element1)=@_;
  540.  $element1=$w->index($element1);
  541.  $element1.='.0';
  542.  return $w->SUPER::mark('previous', $element1);
  543. }
  544.  
  545. #######################################################################
  546. # perform markPrevious based on line.char indexes
  547. #######################################################################
  548. sub markPreviousChar
  549. {
  550.  my $w=shift;
  551.  $w->SUPER::mark('previous', @_);
  552. }
  553.  
  554.  
  555.  
  556.  
  557. sub ButtonRelease_1
  558. {
  559.  my $w = shift;
  560.  my $Ev = $w->XEvent;
  561.  $w->CancelRepeat;
  562.  $w->activate($Ev->xy);
  563. }
  564.  
  565.  
  566. sub Cntrl_Home
  567. {
  568.  my $w = shift;
  569.  my $Ev = $w->XEvent;
  570.  $w->activate(0);
  571.  $w->see(0);
  572.  $w->selectionClear(0,'end');
  573.  $w->selectionSet(0)
  574. }
  575.  
  576.  
  577. sub Cntrl_End
  578. {
  579.  my $w = shift;
  580.  my $Ev = $w->XEvent;
  581.  $w->activate('end');
  582.  $w->see('end');
  583.  $w->selectionClear(0,'end');
  584.  $w->selectionSet('end')
  585. }
  586.  
  587.  
  588. sub Cntrl_backslash
  589. {
  590.  my $w = shift;
  591.  my $Ev = $w->XEvent;
  592.  if ($w->cget('-selectmode') ne 'browse')
  593.  {
  594.  $w->selectionClear(0,'end');
  595.  }
  596. }
  597.  
  598. # BeginSelect --
  599. #
  600. # This procedure is typically invoked on button-1 presses. It begins
  601. # the process of making a selection in the listbox. Its exact behavior
  602. # depends on the selection mode currently in effect for the listbox;
  603. # see the Motif documentation for details.
  604. #
  605. # Arguments:
  606. # w - The listbox widget.
  607. # el - The element for the selection operation (typically the
  608. # one under the pointer). Must be in numerical form.
  609. sub BeginSelect
  610. {
  611.  my $w = shift;
  612.  my $el = shift;
  613.  if ($w->cget('-selectmode') eq 'multiple')
  614.   {
  615.    if ($w->selectionIncludes($el))
  616.     {
  617.      $w->selectionClear($el)
  618.     }
  619.    else
  620.     {
  621.      $w->selectionSet($el)
  622.     }
  623.   }
  624.  else
  625.   {
  626.    $w->selectionClear(0,'end');
  627.    $w->selectionSet($el);
  628.    $w->selectionAnchor($el);
  629.    my @list = ();
  630.    $w->{'SELECTION_LIST_REF'} = \@list;
  631.    $w->{'PREVIOUS_ELEMENT'} = $el
  632.   }
  633.  $w->focus if ($w->cget('-takefocus'));
  634. }
  635. # Motion --
  636. #
  637. # This procedure is called to process mouse motion events while
  638. # button 1 is down. It may move or extend the selection, depending
  639. # on the listbox's selection mode.
  640. #
  641. # Arguments:
  642. # w - The listbox widget.
  643. # el - The element under the pointer (must be a number).
  644. sub Motion
  645. {
  646.  my $w = shift;
  647.  my $el = shift;
  648.  if (defined($w->{'PREVIOUS_ELEMENT'}) && $el == $w->{'PREVIOUS_ELEMENT'})
  649.   {
  650.    return;
  651.   }
  652.  
  653.  # if no selections, select current
  654.  if($w->curselection==0)
  655.   {
  656.   $w->activate($el);
  657.   $w->selectionSet($el);
  658.   $w->selectionAnchor($el);
  659.   $w->{'PREVIOUS_ELEMENT'}=$el;
  660.   return;
  661.   }
  662.  
  663.  my $anchor = $w->index('anchor');
  664.  my $mode = $w->cget('-selectmode');
  665.  if ($mode eq 'browse')
  666.   {
  667.    $w->selectionClear(0,'end');
  668.    $w->selectionSet($el);
  669.    $w->{'PREVIOUS_ELEMENT'} = $el;
  670.   }
  671.  elsif ($mode eq 'extended')
  672.   {
  673.    my $i = $w->{'PREVIOUS_ELEMENT'};
  674.    if ($w->selectionIncludes('anchor'))
  675.     {
  676.      $w->selectionClear($i,$el);
  677.      $w->selectionSet('anchor',$el)
  678.     }
  679.    else
  680.     {
  681.      $w->selectionClear($i,$el);
  682.      $w->selectionClear('anchor',$el)
  683.     }
  684.    while ($i < $el && $i < $anchor)
  685.     {
  686.      if (Tk::lsearch($w->{'SELECTION_LIST_REF'},$i) >= 0)
  687.       {
  688.        $w->selectionSet($i)
  689.       }
  690.      $i += 1
  691.     }
  692.    while ($i > $el && $i > $anchor)
  693.     {
  694.      if (Tk::lsearch($w->{'SELECTION_LIST_REF'},$i) >= 0)
  695.       {
  696.        $w->selectionSet($i)
  697.       }
  698.      $i += -1
  699.     }
  700.    $w->{'PREVIOUS_ELEMENT'} = $el
  701.   }
  702. }
  703. # BeginExtend --
  704. #
  705. # This procedure is typically invoked on shift-button-1 presses. It
  706. # begins the process of extending a selection in the listbox. Its
  707. # exact behavior depends on the selection mode currently in effect
  708. # for the listbox; see the Motif documentation for details.
  709. #
  710. # Arguments:
  711. # w - The listbox widget.
  712. # el - The element for the selection operation (typically the
  713. # one under the pointer). Must be in numerical form.
  714. sub BeginExtend
  715. {
  716.  my $w = shift;
  717.  my $el = shift;
  718.  
  719.  # if no selections, select current
  720.  if($w->curselection==0)
  721.   {
  722.   $w->activate($el);
  723.   $w->selectionSet($el);
  724.   $w->selectionAnchor($el);
  725.   $w->{'PREVIOUS_ELEMENT'}=$el;
  726.   return;
  727.   }
  728.  
  729.  if ($w->cget('-selectmode') eq 'extended' && $w->selectionIncludes('anchor'))
  730.   {
  731.    $w->Motion($el)
  732.   }
  733. }
  734. # BeginToggle --
  735. #
  736. # This procedure is typically invoked on control-button-1 presses. It
  737. # begins the process of toggling a selection in the listbox. Its
  738. # exact behavior depends on the selection mode currently in effect
  739. # for the listbox; see the Motif documentation for details.
  740. #
  741. # Arguments:
  742. # w - The listbox widget.
  743. # el - The element for the selection operation (typically the
  744. # one under the pointer). Must be in numerical form.
  745. sub BeginToggle
  746. {
  747.  my $w = shift;
  748.  my $el = shift;
  749.  if ($w->cget('-selectmode') eq 'extended')
  750.   {
  751.    my @list = $w->curselection();
  752.    $w->{'SELECTION_LIST_REF'} = \@list;
  753.    $w->{'PREVIOUS_ELEMENT'} = $el;
  754.    $w->selectionAnchor($el);
  755.    if ($w->selectionIncludes($el))
  756.     {
  757.      $w->selectionClear($el)
  758.     }
  759.    else
  760.     {
  761.      $w->selectionSet($el)
  762.     }
  763.   }
  764. }
  765. # AutoScan --
  766. # This procedure is invoked when the mouse leaves an entry window
  767. # with button 1 down. It scrolls the window up, down, left, or
  768. # right, depending on where the mouse left the window, and reschedules
  769. # itself as an "after" command so that the window continues to scroll until
  770. # the mouse moves back into the window or the mouse button is released.
  771. #
  772. # Arguments:
  773. # w - The entry window.
  774. # x - The x-coordinate of the mouse when it left the window.
  775. # y - The y-coordinate of the mouse when it left the window.
  776. sub AutoScan
  777. {
  778.  my $w = shift;
  779.  my $x = shift;
  780.  my $y = shift;
  781.  if ($y >= $w->height)
  782.   {
  783.    $w->yview('scroll',1,'units')
  784.   }
  785.  elsif ($y < 0)
  786.   {
  787.    $w->yview('scroll',-1,'units')
  788.   }
  789.  elsif ($x >= $w->width)
  790.   {
  791.    $w->xview('scroll',2,'units')
  792.   }
  793.  elsif ($x < 0)
  794.   {
  795.    $w->xview('scroll',-2,'units')
  796.   }
  797.  else
  798.   {
  799.    return;
  800.   }
  801.  $w->Motion($w->index("@" . $x . ',' . $y));
  802.  $w->RepeatId($w->after(50,'AutoScan',$w,$x,$y));
  803. }
  804. # UpDown --
  805. #
  806. # Moves the location cursor (active element) up or down by one element,
  807. # and changes the selection if we're in browse or extended selection
  808. # mode.
  809. #
  810. # Arguments:
  811. # w - The listbox widget.
  812. # amount - +1 to move down one item, -1 to move back one item.
  813. sub UpDown
  814. {
  815.  my $w = shift;
  816.  my $amount = shift;
  817.  $w->activate($w->index('active')+$amount);
  818.  $w->see('active');
  819.  my $selectmode = $w->cget('-selectmode');
  820.  if ($selectmode eq 'browse')
  821.   {
  822.    $w->selectionClear(0,'end');
  823.    $w->selectionSet('active')
  824.   }
  825.  elsif ($selectmode eq 'extended')
  826.   {
  827.    $w->selectionClear(0,'end');
  828.    $w->selectionSet('active');
  829.    $w->selectionAnchor('active');
  830.    $w->{'PREVIOUS_ELEMENT'} = $w->index('active');
  831.    my @list = ();
  832.    $w->{'SELECTION_LIST_REF'}=\@list;
  833.   }
  834. }
  835. # ExtendUpDown --
  836. #
  837. # Does nothing unless we're in extended selection mode; in this
  838. # case it moves the location cursor (active element) up or down by
  839. # one element, and extends the selection to that point.
  840. #
  841. # Arguments:
  842. # w - The listbox widget.
  843. # amount - +1 to move down one item, -1 to move back one item.
  844. sub ExtendUpDown
  845. {
  846.  my $w = shift;
  847.  my $amount = shift;
  848.  if ($w->cget('-selectmode') ne 'extended')
  849.   {
  850.    return;
  851.   }
  852.  $w->activate($w->index('active')+$amount);
  853.  $w->see('active');
  854.  $w->Motion($w->index('active'))
  855. }
  856. # DataExtend
  857. #
  858. # This procedure is called for key-presses such as Shift-KEndData.
  859. # If the selection mode isn't multiple or extend then it does nothing.
  860. # Otherwise it moves the active element to el and, if we're in
  861. # extended mode, extends the selection to that point.
  862. #
  863. # Arguments:
  864. # w - The listbox widget.
  865. # el - An integer element number.
  866. sub DataExtend
  867. {
  868.  my $w = shift;
  869.  my $el = shift;
  870.  my $mode = $w->cget('-selectmode');
  871.  if ($mode eq 'extended')
  872.   {
  873.    $w->activate($el);
  874.    $w->see($el);
  875.    if ($w->selectionIncludes('anchor'))
  876.     {
  877.      $w->Motion($el)
  878.     }
  879.   }
  880.  elsif ($mode eq 'multiple')
  881.   {
  882.    $w->activate($el);
  883.    $w->see($el)
  884.   }
  885. }
  886. # Cancel
  887. #
  888. # This procedure is invoked to cancel an extended selection in
  889. # progress. If there is an extended selection in progress, it
  890. # restores all of the items between the active one and the anchor
  891. # to their previous selection state.
  892. #
  893. # Arguments:
  894. # w - The listbox widget.
  895. sub Cancel
  896. {
  897.  my $w = shift;
  898.  if ($w->cget('-selectmode') ne 'extended' || !defined $w->{'PREVIOUS_ELEMENT'})
  899.   {
  900.    return;
  901.   }
  902.  my $first = $w->index('anchor');
  903.  my $last = $w->{'PREVIOUS_ELEMENT'};
  904.  if ($first > $last)
  905.   {
  906.   ($first,$last)=($last,$first);
  907.   }
  908.  $w->selectionClear($first,$last);
  909.  while ($first <= $last)
  910.   {
  911.    if (Tk::lsearch($w->{'SELECTION_LIST_REF'},$first) >= 0)
  912.     {
  913.      $w->selectionSet($first)
  914.     }
  915.    $first += 1
  916.   }
  917. }
  918. # SelectAll
  919. #
  920. # This procedure is invoked to handle the "select all" operation.
  921. # For single and browse mode, it just selects the active element.
  922. # Otherwise it selects everything in the widget.
  923. #
  924. # Arguments:
  925. # w - The listbox widget.
  926. sub SelectAll
  927. {
  928.  my $w = shift;
  929.  my $mode = $w->cget('-selectmode');
  930.  if ($mode eq 'single' || $mode eq 'browse')
  931.   {
  932.    $w->selectionClear(0,'end');
  933.    $w->selectionSet('active')
  934.   }
  935.  else
  936.   {
  937.    $w->selectionSet(0,'end')
  938.   }
  939. }
  940.  
  941. sub SetList
  942. {
  943.  my $w = shift;
  944.  $w->delete(0,'end');
  945.  $w->insert('end',@_);
  946. }
  947.  
  948. sub deleteSelected
  949. {
  950.  my $w = shift;
  951.  my $i;
  952.  foreach $i (reverse $w->curselection)
  953.   {
  954.    $w->delete($i);
  955.   }
  956. }
  957.  
  958. sub clipboardPaste
  959. {
  960.  my $w = shift;
  961.  my $element = $w->index('active') || $w->index($w->XEvent->xy);
  962.  my $str;
  963.  eval {local $SIG{__DIE__}; $str = $w->clipboardGet };
  964.  return if $@;
  965.  foreach (split("\n",$str))
  966.   {
  967.    $w->insert($element++,$_);
  968.   }
  969. }
  970.  
  971. sub getSelected
  972. {
  973.  my ($w) = @_;
  974.  my $i;
  975.  my (@result) = ();
  976.  foreach $i ($w->curselection)
  977.   {
  978.    push(@result,$w->get($i));
  979.   }
  980.  return (wantarray) ? @result : $result[0];
  981. }
  982.  
  983.  
  984.  
  985. 1;
  986.