Tk-JListbox
view release on metacpan or search on metacpan
JListbox.pm view on Meta::CPAN
foreach my $item(@$menuref){
$string = $item->[0];
$callback = $item->[1];
$binding = $item->[2];
$index = $item->[3];
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Use auto-vivification here to create a key for each button based on
# the name of the button, preceded by an 'm_'.
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if(!defined($dw->{"m_$string"})){
$dw->{"m_$string"} = $popupmenu->Button(
-text => "$string\t$binding",
-underline => $index,
-command => [$callback, $dw],
);
}
$dw->bind($binding, \$callback);
my $button = $dw->{"m_$string"};
$button->configure(-relief=>'flat', -padx=>0, -pady=>0, -anchor=>'w');
$button->pack(-expand=>1, -fill=>'x');
$button->bind("<Enter>", sub{
if($_[0]->cget('-state') ne "disabled"){
$_[0]->configure(-relief=>'raised')
}
}
);
$button->bind('<Leave>', sub{$_[0]->configure(-relief=>'flat')});
}
$dw->JsetState;
$popupmenu->geometry(sprintf("+%d+%d", $dw->rootx, $dw->rooty));
$popupmenu->deiconify;
$dw->grab;
}
# Withdraw the popup menu if it is raised.
sub lowerPopup{
my $dw = shift;
my $popup = $dw->cget(-popupmenu);
my $state = $popup->state;
if($state ne 'withdrawn'){ $popup->withdraw }
else{ return }
$dw->grabRelease;
}
# Set the bindings for the popup menu.
sub setBindings{
my $dw = shift;
$dw->bind('<Button-3>', sub{ $dw->JraisePopup });
$dw->bind('<Button-1>', sub{ $dw->lowerPopup });
}
# Copy the selected elements to the clipboard;
sub Jcopy{
my $dw = shift;
my $popup = $dw->cget(-popupmenu);
my @selection = $dw->curselection;
if(@selection ne ""){
$dw->clipboardClear;
foreach my $index(@selection){
my $string = $dw->get($index);
# Remove any leading or trailing whitespace
$string =~ s/^\s*//;
$string =~ s/\s*$//;
$dw->clipboardAppend('--', $string);
}
}
$popup->withdraw;
$dw->grabRelease;
}
# Cut the selection and copy it to the clipboard
sub Jcut{
my $dw = shift;
my $popup = $dw->cget(-popupmenu);
my @selection = $dw->curselection;
if(@selection ne ""){
$dw->clipboardClear;
foreach my $index(@selection){
my $string = $dw->get($index);
# Remove any leading or trailing whitespace
$string =~ s/^\s*//;
$string =~ s/\s*$//;
$dw->clipboardAppend('--', $string);
# Remove the item
$dw->delete($index);
}
}
$popup->withdraw;
$dw->grabRelease;
}
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Paste a string into the Listbox. Prompt the user to see if they want to
# paste above or below the current selection.
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sub Jpaste{
my $dw = shift;
my $popup = $dw->cget(-popupmenu);
$popup->withdraw;
Tk::catch { $string = $dw->SelectionGet(-selection=>'CLIPBOARD') };
my $dialog = $dw->DialogBox(
-title => "Paste location...",
-buttons => ["OK", "Cancel"]
);
my $r_selection;
# Some spaces hardcoded for alignment purposes
foreach(" Above selection", " Below Selection",
" Left of Selection", "Right of Selection"){
$dialog->add(
'Radiobutton',
-text => $_,
-value => $_,
-variable => \$r_selection,
)->pack;
}
my $ans = $dialog->Show;
if($ans eq "OK"){
my $index = $dw->curselection;
$dw->Jinsert($index, $r_selection)
}
$dw->grabRelease;
}
sub Jinsert{
my($dw, $index, $side) = @_;
$side =~ s/.*?(\w+).*/$1/;
my $string = $dw->get($index);
my $flag = $dw->cget(-justifyVal);
# Clear whitespace
$string =~ s/^\s*//;
$string =~ s/\s*$//;
my $selection;
eval{ $selection = $dw->SelectionGet(-selection=>'CLIPBOARD') };
if($EVAL_ERROR){ return }
# Automatically insert 1 whitespace character
if($side eq "Right"){
$string .= " $selection";
$dw->delete($index);
$dw->insert($index, $string);
}
if($side eq "Left"){
$string = $selection . " $string";
$dw->delete($index);
$dw->insert($index, $string);
}
Tk::catch{ $string = $dw->SelectionGet(-selection=>'CLIPBOARD') };
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Pasting above or below requires storing the contents of the listbox
# in an array and then re-inserting them at the proper index.
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if($side eq "Below"){
my @items = $dw->get($index+1, 'end');
$dw->delete($index+1,'end');
$dw->insert($index+2,$string, @items);
}
if($side eq "Above"){
my @items = $dw->get($index, 'end');
$dw->delete($index, 'end');
$dw->insert($index, $string, @items);
}
# Keep current justification
$dw->justify($flag);
}
# Determine the various menu items should be 'normal' or 'disabled'
sub JsetState{
my $dw = shift;
my($selection, $clipboard);
eval { $selection = $dw->curselection };
Tk::catch{ $clipboard = $dw->SelectionGet(-selection=>'CLIPBOARD') };
my $menuref = $dw->cget(-menuitems);
# Set the default menu items to 'disabled', enabling them if appropriate
foreach my $item (@$menuref){
if($item->[0] =~ /Cut|Copy|Paste/){
$dw->{"m_$item->[0]"}->configure(-state=>'disabled');
}
}
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Only set state to 'normal' for default items if clipboard is
# not empty or selection is present.
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if( (defined($selection)) && ($clipboard) && ($dw->{m_Paste})){
$dw->{m_Paste}->configure(-state=>'normal');
}
if( (defined($selection)) && ($dw->{m_Cut})){
$dw->{m_Cut}->configure(-state=>'normal');
}
if( (defined($selection)) && ($dw->{m_Copy})){
$dw->{m_Copy}->configure(-state=>'normal');
}
} #END setState()
1;
__END__
=head1 JListbox
JListbox - justify text within a Listbox
=head1 SYNOPSIS
use JListbox;
$dw = $parent->JListbox(-justify=>'center', -popupmenu=>1);
$dw->pack;
=head1 DESCRIPTION
JListbox is identical to a Listbox, but has two addtional options: -justify
and -popupmenu.
=head3 -justify
Possible values for '-justify' are 'left', 'center' and 'right'. The default
is 'left'. All text within the Listbox will be justified according to the
option you set.
The widget automatically checks for variable or fixed width fonts
and adjusts accordingly.
You cannot justify individual entries separately (as of version .02).
Your text will remain justified appropriately, even if you
set the '-expand' and '-fill' options.
The justification ability is provided via plain old pixel and
character counting (depending on whether you are using a variable or
fixed width font). There have been no underlying changes in the C code
to the Tcl Listbox.
=head3 -popupmenu
If the -popupmenu option is used, a "Cut, Copy, Paste" menu will appear when
the user right-clicks anywhere on the JListbox.
The "Cut" option will remove the item from the JListbox, copy it to the
clipboard and the remaining items will shift up automatically.
The "Copy" option simply copies the selected value to the clipboard.
The "Paste" option, if selected, will bring up a Dialog window that gives the
user the option to paste (insert) above or below the selected item, as well as
on the same line, either to the left or right of the selected item.
One whitespace character is automatically separates the pasted value if the
'left' or 'right' option is chosen.
If you wish to modify the popup menu itself, you can retrieve it using the
Subwidget method with 'popupmenu' as the widget name.
$menu = $dw->Subwidget('popupmenu');
=head1 KNOWN BUGS
If using a variable width font, you may encounter a problem with the last
character disappearing off the right side of the listbox when you use
right justify. I think I fixed this, so let me know if you have any problems.
If the text you insert into the listbox includes characters that have
special meaning in regular expressions (e.g. '*', '?'), you will need to
escape them using the '\' character or your app may crash.
e.g. $dw->insert('end', "What did you say\?");
=head1 PLANNED CHANGES
Fix the regular expression issue mentioned above.
Allow individual entries to be justified.
Add the 'addMenuItem' and 'deleteMenuItem' methods to allow greater
configurability of the right-click menu.
=head1 AUTHOR
Daniel J. Berger
djberg96@hotmail.com
Thanks goes to Damion K. Wilson for his help with creating widgets.
=head1 SEE ALSO
Listbox
=cut
( run in 2.863 seconds using v1.01-cache-2.11-cpan-84e82930d8c )