package Tk::HList; use vars qw($VERSION); $VERSION = sprintf '4.%03d', q$Revision: #14 $ =~ /\D(\d+)\s*$/; use Tk qw(Ev $XS_VERSION); use base qw(Tk::Widget); Construct Tk::Widget 'HList'; sub Tk::Widget::ScrlHList { shift->Scrolled('HList'=>@_) } bootstrap Tk::HList; sub Tk_cmd { \&Tk::hlist } sub CreateArgs { my ($package,$parent,$args) = @_; my @result = $package->SUPER::CreateArgs($parent,$args); my $columns = delete $args->{-columns}; push(@result, '-columns' => $columns) if (defined $columns); return @result; } Tk::Methods qw(add addchild anchor column delete dragsite dropsite entrycget entryconfigure geometryinfo indicator header hide item info nearest see select selection show xview yview); use Tk::Submethods ( 'delete' => [qw(all entry offsprings siblings)], 'header' => [qw(configure cget create delete exists size)], 'indicator' => [qw(configure cget create delete exists size)], 'info' => [qw(anchor bbox children data dragsite dropsite exists hidden item next parent prev selection)], 'item' => [qw(configure cget create delete exists)], 'selection' => [qw(clear get includes set)], 'anchor' => [qw(clear set)], 'column' => [qw(width)], 'hide' => [qw(entry)], ); sub ClassInit { my ($class,$mw) = @_; $mw->bind($class,'',[ 'Button1' ] ); $mw->bind($class,'',[ 'ShiftButton1' ] ); $mw->bind($class,'','Control_ButtonRelease_1'); $mw->bind($class,'','ButtonRelease_1'); $mw->bind($class,'','NoOp'); $mw->bind($class,'',[ 'Button1Motion' ] ); $mw->bind($class,'',[ 'AutoScan' ] ); $mw->bind($class,'',['Double1']); $mw->bind($class,'','Control_B1_Motion'); $mw->bind($class,'',['CtrlButton1']); $mw->bind($class,'',['CtrlButton1']); $mw->bind($class,'','B1_Enter'); $mw->bind($class,'',['UpDown', 'prev']); $mw->bind($class,'',['UpDown', 'next']); $mw->bind($class,'',['ShiftUpDown', 'prev']); $mw->bind($class,'',['ShiftUpDown', 'next']); $mw->bind($class,'', ['LeftRight', 'left']); $mw->bind($class,'',['LeftRight', 'right']); $mw->PriorNextBind($class); $mw->MouseWheelBind($class); $mw->bind($class,'', ['KeyboardActivate']); $mw->bind($class,'', ['KeyboardBrowse']); $mw->bind($class,'', ['KeyboardHome']); $mw->bind($class,'', ['KeyboardEnd']); $mw->YMouseWheelBind($class); $mw->XMouseWheelBind($class); return $class; } sub Control_ButtonRelease_1 { } sub ButtonRelease_1 { my $w = shift; my $Ev = $w->XEvent; $w->CancelRepeat if($w->cget('-selectmode') ne 'dragdrop'); $w->ButtonRelease1($Ev); } sub Control_B1_Motion { } sub B1_Enter { my $w = shift; my $Ev = $w->XEvent; $w->CancelRepeat if($w->cget('-selectmode') ne 'dragdrop'); } sub Button1 { my $w = shift; my $Ev = $w->XEvent; delete $w->{'shiftanchor'}; delete $w->{tixindicator}; $w->focus() if($w->cget('-takefocus')); my $mode = $w->cget('-selectmode'); if ($mode eq 'dragdrop') { # $w->Send_WaitDrag($Ev->y); return; } my $ent = $w->GetNearest($Ev->y, 1); if (!defined($ent) || !length($ent)) { $w->selectionClear; $w->anchorClear; return; } my @info = $w->info('item',$Ev->x, $Ev->y); if (@info) { die 'Assert' unless $info[0] eq $ent; } else { @info = $ent; } if (defined($info[1]) && $info[1] eq 'indicator') { $w->{tixindicator} = $ent; $w->Callback(-indicatorcmd => $ent, ''); } else { my $browse = 0; if ($mode eq 'single') { $w->anchorSet($ent); } elsif ($mode eq 'browse') { $w->anchorSet($ent); $w->selectionClear; $w->selectionSet($ent); $browse = 1; } elsif ($mode eq 'multiple') { $w->selectionClear; $w->anchorSet($ent); $w->selectionSet($ent); $browse = 1; } elsif ($mode eq 'extended') { $w->anchorSet($ent); $w->selectionClear; $w->selectionSet($ent); $browse = 1; } if ($browse) { $w->Callback(-browsecmd => @info); } } } sub ShiftButton1 { my $w = shift; my $Ev = $w->XEvent; my $to = $w->GetNearest($Ev->y, 1); delete $w->{'shiftanchor'}; delete $w->{tixindicator}; return unless (defined($to) and length($to)); my $mode = $w->cget('-selectmode'); if($mode eq 'extended' or $mode eq 'multiple') { my $from = $w->info('anchor'); if(defined $from) { $w->selectionClear; $w->selectionSet($from, $to); } else { $w->anchorSet($to); $w->selectionClear; $w->selectionSet($to); } } } sub GetNearest { my ($w,$y,$undefafterend) = @_; my $ent = $w->nearest($y); if (defined $ent) { if ($undefafterend) { my $borderwidth = $w->cget('-borderwidth'); my $highlightthickness = $w->cget('-highlightthickness'); my $bottomy = ($w->infoBbox($ent))[3]; $bottomy += $borderwidth + $highlightthickness; if ($w->header('exist', 0)) { $bottomy += $w->header('height'); } if ($y > $bottomy) { #print "$y > $bottomy\n"; return undef; } } my $state = $w->entrycget($ent, '-state'); return $ent if (!defined($state) || $state ne 'disabled'); } return undef; } sub ButtonRelease1 { my ($w, $Ev) = @_; delete $w->{'shiftanchor'}; my $mode = $w->cget('-selectmode'); if($mode eq 'dragdrop') { # $w->Send_DoneDrag(); return; } my ($x, $y) = ($Ev->x, $Ev->y); my $ent = $w->GetNearest($y, 1); if (!defined($ent) and $mode eq 'single') { my $ent = $w->info('selection'); if (defined $ent) { $w->anchorSet($ent); } } return unless (defined($ent) and length($ent)); if (exists $w->{tixindicator}) { return unless delete($w->{tixindicator}) eq $ent; my @info = $w->info('item',$Ev->x, $Ev->y); if(defined($info[1]) && $info[1] eq 'indicator') { $w->Callback(-indicatorcmd => $ent, ''); } else { $w->Callback(-indicatorcmd => $ent, ''); } return; } if($mode eq 'single' || $mode eq 'browse') { $w->anchorSet($ent); $w->selectionClear; $w->selectionSet($ent); } elsif($mode eq 'multiple') { $w->selectionSet($ent); } elsif($mode eq 'extended') { $w->selectionSet($ent); } $w->Callback(-browsecmd =>$ent); } sub Button1Motion { my $w = shift; my $Ev = $w->XEvent; return unless defined $Ev; delete $w->{'shiftanchor'}; my $mode = $w->cget('-selectmode'); if ($mode eq 'dragdrop') { # $w->Send_StartDrag(); return; } my $ent; if (defined $w->info('anchor')) { $ent = $w->GetNearest($Ev->y); } else { $ent = $w->GetNearest($Ev->y, 1); } return unless (defined($ent) and length($ent)); if(exists $w->{tixindicator}) { my $event_type = $w->{tixindicator} eq $ent ? '' : ''; $w->Callback(-indicatorcmd => $w->{tixindicator}, $event_type ); return; } if ($mode eq 'single') { $w->anchorSet($ent); } elsif ($mode eq 'multiple' || $mode eq 'extended') { my $from = $w->info('anchor'); if(defined $from) { $w->selectionClear; $w->selectionSet($from, $ent); } else { $w->anchorSet($ent); $w->selectionClear; $w->selectionSet($ent); } } if ($mode ne 'single') { $w->Callback(-browsecmd =>$ent); } } sub Double1 { my $w = shift; my $Ev = $w->XEvent; delete $w->{'shiftanchor'}; my $ent = $w->GetNearest($Ev->y, 1); return unless (defined($ent) and length($ent)); $w->anchorSet($ent) unless(defined $w->info('anchor')); $w->selectionSet($ent); $w->Callback(-command => $ent); } sub CtrlButton1 { my $w = shift; my $Ev = $w->XEvent; delete $w->{'shiftanchor'}; my $ent = $w->GetNearest($Ev->y, 1); return unless (defined($ent) and length($ent)); my $mode = $w->cget('-selectmode'); if($mode eq 'extended') { $w->anchorSet($ent) unless( defined $w->info('anchor') ); if($w->select('includes', $ent)) { $w->select('clear', $ent); } else { $w->selectionSet($ent); } $w->Callback(-browsecmd =>$ent); } } sub UpDown { my $w = shift; my $spec = shift; my $done = 0; my $anchor = $w->info('anchor'); delete $w->{'shiftanchor'}; unless( defined $anchor ) { $anchor = ($w->info('children'))[0] || ''; return unless (defined($anchor) and length($anchor)); if($w->entrycget($anchor, '-state') ne 'disabled') { # That's a good anchor $done = 1; } else { # We search for the first non-disabled entry (downward) $spec = 'next'; } } my $ent = $anchor; # Find the prev/next non-disabled entry # while(!$done) { $ent = $w->info($spec, $ent); last unless( defined $ent ); next if( $w->entrycget($ent, '-state') eq 'disabled' ); next if( $w->info('hidden', $ent) ); last; } unless( defined $ent ) { $w->yview('scroll', $spec eq 'prev' ? -1 : 1, 'unit'); return; } $w->anchorSet($ent); $w->see($ent); if($w->cget('-selectmode') ne 'single') { $w->selectionClear; $w->selection('set', $ent); $w->Callback(-browsecmd =>$ent); } } sub ShiftUpDown { my $w = shift; my $spec = shift; my $mode = $w->cget('-selectmode'); return $w->UpDown($spec) if($mode eq 'single' || $mode eq 'browse'); my $anchor = $w->info('anchor'); return $w->UpDown($spec) unless (defined($anchor) and length($anchor)); my $done = 0; $w->{'shiftanchor'} = $anchor unless( $w->{'shiftanchor'} ); my $ent = $w->{'shiftanchor'}; while( !$done ) { $ent = $w->info($spec, $ent); last unless( defined $ent ); next if( $w->entrycget($ent, '-state') eq 'disabled' ); next if( $w->info('hidden', $ent) ); last; } unless( $ent ) { $w->yview('scroll', $spec eq 'prev' ? -1 : 1, 'unit'); return; } $w->selectionClear; $w->selection('set', $anchor, $ent); $w->see($ent); $w->{'shiftanchor'} = $ent; $w->Callback(-browsecmd =>$ent); } sub LeftRight { my $w = shift; my $spec = shift; delete $w->{'shiftanchor'}; my $anchor = $w->info('anchor'); unless(defined $anchor) { $anchor = ($w->info('children'))[0] || ''; } my $done = 0; my $ent = $anchor; while(!$done) { my $e = $ent; if($spec eq 'left') { $ent = $w->info('parent', $e); $ent = $w->info('prev', $e) unless(defined $ent && $w->entrycget($ent, '-state') ne 'disabled') } else { $ent = ($w->info('children', $e))[0]; $ent = $w->info('next', $e) unless(defined $ent && $w->entrycget($ent, '-state') ne 'disabled') } last unless( defined $ent ); last if($w->entrycget($ent, '-state') ne 'disabled'); } unless( defined $ent ) { $w->xview('scroll', $spec eq 'left' ? -1 : 1, 'unit'); return; } $w->anchorSet($ent); $w->see($ent); if($w->cget('-selectmode') ne 'single') { $w->selectionClear; $w->selectionSet($ent); $w->Callback(-browsecmd =>$ent); } } sub KeyboardHome { my $w = shift; $w->yview('moveto' => 0); $w->xview('moveto' => 0); } sub KeyboardEnd { my $w = shift; $w->yview('moveto' => 1); $w->xview('moveto' => 0); } sub KeyboardActivate { my $w = shift; my $anchor = $w->info('anchor'); return unless (defined($anchor) and length($anchor)); if($w->cget('-selectmode')) { $w->selectionClear; $w->selectionSet($anchor); } $w->Callback(-command => $anchor); } sub KeyboardBrowse { my $w = shift; my $anchor = $w->info('anchor'); return unless (defined($anchor) and length($anchor)); if ($w->indicatorExists($anchor)) { $w->Callback(-indicatorcmd => $anchor); } if($w->cget('-selectmode')) { $w->selectionClear; $w->selectionSet($anchor); } $w->Callback(-browsecmd =>$anchor); } sub AutoScan { my ($w,$x,$y) = @_; return if ($w->cget('-selectmode') eq 'dragdrop'); if (@_ < 3) { my $Ev = $w->XEvent; return unless defined $Ev; $y = $Ev->y; $x = $Ev->x; } if($y >= $w->height) { $w->yview('scroll', 1, 'units'); } elsif($y < 0) { $w->yview('scroll', -1, 'units'); } elsif($x >= $w->width) { $w->xview('scroll', 2, 'units'); } elsif($x < 0) { $w->xview('scroll', -2, 'units'); } else { return; } $w->RepeatId($w->SUPER::after(50,[ AutoScan => $w, $x, $y ])); $w->Button1Motion; } sub children { # Tix has core-tk window(s) which are not a widget(s) # the generic code returns these as an "undef" my $w = shift; my @info = grep(defined($_),$w->winfo('children')); @info; } 1;