Curses-UI

 view release on metacpan or  search on metacpan

lib/Curses/UI/Listbox.pm  view on Meta::CPAN


my %bindings = (
    KEY_LEFT()           => 'loose-focus',
    "h"                  => 'loose-focus',
    CUI_TAB()            => 'loose-focus',
    KEY_BTAB()           => 'loose-focus',
    KEY_ENTER()          => 'option-select',
    KEY_RIGHT()          => 'option-select',
    "l"                  => 'option-select',
    CUI_SPACE()          => 'option-select',
    "1"                  => 'option-check',
    "y"                  => 'option-check',
    "0"                  => 'option-uncheck',
    "n"                  => 'option-uncheck',
    KEY_DOWN()           => 'option-next',
    "j"                  => 'option-next',
    KEY_NPAGE()          => 'option-nextpage',
    KEY_UP()             => 'option-prev',
    "k"                  => 'option-prev',
    KEY_PPAGE()          => 'option-prevpage',
    KEY_HOME()           => 'option-first',
    "\cA"                => 'option-first',
    KEY_END()            => 'option-last',
    "\cE"                => 'option-last',
    "/"                  => 'search-forward',
    "?"                  => 'search-backward',
);

sub new ()
{
    my $class = shift;

    my %userargs = @_;
    keys_to_lowercase(\%userargs);

    my %args = ( 
        -values     => [],    # values to show
        -labels     => {},    # optional labels for the values 
        -active     => 0,     # the activated value
        -width      => undef, # the width of the listbox
        -height     => undef, # the height of the listbox
        -x          => 0,     # the hor. pos. rel. to parent
        -y          => 0,     # the vert. pos. rel. to parent
        -multi      => 0,     # multiselection possible?
        -radio      => 0,     # show radio buttons? Only for ! -multi
        -selected   => undef, # the selected item
        -wraparound => 0,     # wraparound on first/last item
        -onchange   => undef, # onChange event handler
	-onselchange=> undef, # onSelectionChange event handler

	-bg         => -1,
        -fg         => -1,
        
        %userargs,

        -routines   => {%routines},
        -bindings   => {%bindings},

        -yscrpos    => 0,     # Value init
        -focus      => 0,     # Value init
        -nocursor   => 1,     # This widget does not use a cursor
    );

    if ($args{-multi})
    {
        $args{-radio} = 0;
        $args{-selected} = {} 
	    unless ref $args{-selected} eq 'HASH';
        $args{-ypos} = 0;
    } else {
        $args{-ypos} = defined $args{-selected} ? $args{-selected} : 0;
    }

    my $this = $class->SUPER::new( %args );    
    $this->layout_content();

    if ($Curses::UI::ncurses_mouse) {
        $this->set_mouse_binding('mouse-button1', BUTTON1_CLICKED());
        $this->set_mouse_binding('mouse-button1', BUTTON1_DOUBLE_CLICKED());
    }

    return $this;
}

sub onChange(;$) { shift()->set_event('-onchange', shift()) }

sub onSelectionChange(;$) { shift()->set_event('-onselchange', shift()) };

sub values(;$)
{
    my $this = shift;
    my $values = shift;

    if (defined $values && ! ref $values) {
	$values = [ $values, @_ ];
    }
 
    if (defined $values and ref $values eq 'ARRAY') {
	# Clear and go to first item if we get new data
	$this->clear_selection();    

        $this->{-values} = $values;
	$this->option_first() if defined $values;

        # Make this widget non-focusable if there are
        # no values in it.
        $this->focusable(scalar(@{$values}));
    }

    return $this->{-values}
}

sub insert_at()
{
    
    my $this = shift;
    my $pos = shift;
    my $values = shift;

    # Clear and go to first item if we get new data
    $this->clear_selection();

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

    my $value = $this->{-values}->[$idx];
    my $label = $value;
    $label = $this->{-labels}->{$label} 
        if defined $this->{-labels}->{$label};
    $label =~ s/\t/ /g; # do not show TABs
    
    return $label;
}


sub get_active_value($;)
{
    my $this = shift;
    my $id = $this->{-ypos};
    my $value = $this->{'-values'}->[$id];    
    return $value;
}

sub get_active_id($;)
{
    my $this = shift;
    return $this->{-ypos};;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw the widget
    $this->SUPER::draw(1) or return $this;

    $this->layout_content;

     # Let there be color
    if ($Curses::UI::color_support) {
	my $co = $Curses::UI::color_object;
	my $pair = $co->get_color_pair(
			     $this->{-fg},
			     $this->{-bg});

	$this->{-canvasscr}->attron(COLOR_PAIR($pair));

    }

    # No values? 
    if (not @{$this->{-values}})
    {
        $this->{-canvasscr}->attron(A_DIM);    
        $this->{-canvasscr}->addstr(0,0,'- no values -');
        $this->{-canvasscr}->attroff(A_DIM);    

    # There are values. Show them!
    } else {
        my $start_idx = $this->{-yscrpos};
        my $end_idx = $this->{-yscrpos} + $this->canvasheight - 1;
        $end_idx = $this->{-max_selected} 
            if $end_idx > $this->{-max_selected};

        my $y = 0;
        my $cursor_y = 0;
        my $cursor_x = 0;
        for my $i ($start_idx .. $end_idx)
        {
            # The label to print.
            my $label = $this->getlabel($i);

            # Clear up label.
            $label =~ s/\n|\r//g;

            # Needed space for prefix.
            my $prefix_len = 
                (($this->{-multi} or $this->{-radio}) ? 4 : 0);

            # Chop length if needed.
            $label = $this->text_chop($label, ($this->canvaswidth-$prefix_len));

            # Show current entry in reverse mode and 
            # save cursor position.
            if ($this->{-ypos} == $i and $this->{-focus})
            {
                $this->{-canvasscr}->attron(A_REVERSE);
                $cursor_y = $y;    
                $cursor_x = $this->canvaswidth-1;
            }

            # Show selected element bold. 
            if (   (    not $this->{-multi}
                    and defined $this->{-selected}
                    and $this->{-selected} == $i)
                or (    $this->{-multi} 
                    and defined $this->{-selected}
                    and $this->{-selected}->{$i}) ) {
		    $this->{-canvasscr}->attron(A_BOLD);
            }
            
            # Make full line reverse or blank
            $this->{-canvasscr}->addstr(
                $y, $prefix_len, 
                " "x($this->canvaswidth-$prefix_len)
            );

            # Show label
            $this->text_draw($y, $prefix_len, $label);

            $this->{-canvasscr}->attroff(A_REVERSE);
            $this->{-canvasscr}->attroff(A_BOLD);

            # Place a [X] for selected value in multi mode.
            $this->{-canvasscr}->attron(A_BOLD) if $this->{-focus};
            if ($this->{-multi}) {
                if (defined $this->{-selected} and    
                    $this->{-selected}->{$i}) {
		    $this->{-canvasscr}->addstr($y, 0, '[X]');
                } else {
                    $this->{-canvasscr}->addstr($y, 0, '[ ]');
                }
            }

            # Place a <o> for selected value in radio mode.
            elsif ($this->{-radio}) {
                if (defined $this->{-selected} 
                    and $i == $this->{-selected}) {
                    $this->{-canvasscr}->addstr($y, 0, '<o>');
                } else {
                    $this->{-canvasscr}->addstr($y, 0, '< >');
                }
            }
            $this->{-canvasscr}->attroff(A_BOLD) if $this->{-focus};

            $y++;
        }

        $cursor_x = 1 if $this->{-multi} or $this->{-radio};
        $this->{-canvasscr}->move($cursor_y, $cursor_x);
    }

    $this->{-canvasscr}->noutrefresh();
    doupdate() unless $no_doupdate;

    return $this;
}

sub option_last()
{
    my $this = shift;
    $this->{-ypos} = $this->{-max_selected};
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub option_nextpage()
{
    my $this = shift;
    if ($this->{-ypos} >= $this->{-max_selected}) { 
        $this->dobeep;
        return $this;
    }
    if ($this->{-ypos} + $this->canvasheight - 1 >= $this->{-max_selected}) { 
    	$this->{-ypos} = $this->{-max_selected};
		} else {
    	$this->{-ypos} += $this->canvasheight - 1;
		}
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub option_prevpage()
{
    my $this = shift;
    if ($this->{-ypos} <= 0) {
        $this->dobeep;
        return $this;
    }
    if ($this->{-ypos} - $this->canvasheight - 1 < 0) {
    	$this->{-ypos} = 0;
		} else {
    	$this->{-ypos} -= $this->canvasheight - 1;
		}
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub clear_selection()
{
    my $this = shift;
    if ($this->{-multi}) {
	my $selection = $this->{-selected};
	return unless defined $selection;
	foreach my $id (keys %$selection) {
	    $selection->{$id} = 0;
	}

lib/Curses/UI/Listbox.pm  view on Meta::CPAN


=item * B<get_active_value> ( )

This method will return the value of the currently active (i.e 
highlighted line).

=item * B<get_active_id> ( )

This method will return the index of the currently active (i.e 
highlighted line).

=item * B<set_selection> ( LIST )

This method marks the items at the positions specified in LIST
as selected. In a multi-select listbox you can set multiple items 
with giving multiple values, in a single-select listbox only the
last item in LIST will be selected

=item * B<clear_selection> ( )

This method clears the selected objects of a multi and radiobutton
listbox.

=item * B<values> ( ARRAYREF )

This method sets the values to use. 

=item * B<insert_at> < POS, ARRAYREF|SCALAR >

This method adds ARRAYREF or SCALAR into the list of values at
pos.

=item * B<labels> [ HASHREF ]

This method sets the labels to use. 

=item * B<add_labels> [ HASHREF ]

This method adds the given labels to the already defined ones.

=item * B<onChange> ( CODEREF )

This method can be used to set the B<-onchange> event handler
(see above) after initialization of the listbox. 

=item * B<onSelectionChange> ( CODEREF )

This method can be used to set the B<-onselchange> event handler
(see above) after initialization of the listbox. 


=back




=head1 DEFAULT BINDINGS

=over 4

=item * <B<cursor-left>>, <B<h>>, <B<tab>>

Call the 'loose-focus' routine. This will have the widget 
loose its focus.

=item * <B<cursor-right>, <B<l>>, <B<enter>>, <B<space>>

Call the 'option-select' routine. This will select the
active item in the listbox.

=item * <B<1>>, <B<y>>

Call the 'option-check' routine. If the listbox is a 
multi-select listbox, the active item will become checked
and the next item will become active.

=item * <B<0>>, <B<n>>

Call the 'option-uncheck' routine. If the listbox is a 
multi-select listbox, the active item will become unchecked
and the next item will become active.

=item * <B<cursor-down>>, <B<j>>

Call the 'option-next' routine. This will make the next
item of the list active.

=item * <B<cursor-up>>, <B<k>>

Call the 'option-prev' routine. This will make the previous
item of the list active.

=item * <B<page-up>>

Call the 'option-prevpage' routine. This will make the item
on the previous page active.

=item * <B<page-down>>

Call the 'option-nextpage' routine. This will make the item
on the next page active.

=item * <B<home>>, <B<CTRL+A>>

Call the 'option-first' routine. This will make the first
item of the list active.

=item * <B<end>>, <B<CTRL+E>>

Call the 'option-last' routine. This will make the last
item of the list active.

=item * <B</>>

Call the 'search-forward' routine. This will make a 'less'-like
search system appear in the listbox. A searchstring can be
entered. After that the user can search for the next occurance
using the 'n' key or the previous occurance using the 'N' key.

=item * <B<?>>

Call the 'search-backward' routine. This will do the same as
the 'search-forward' routine, only it will search in the 
opposite direction.

=back 





=head1 SEE ALSO

L<Curses::UI|Curses::UI>, 
L<Curses::UI::Widget|Curses::UI::Widget>, 
L<Curses::UI::Common|Curses::UI::Common>




=head1 AUTHOR

Copyright (c) 2001-2002 Maurice Makaay. All rights reserved.

Maintained by Marcus Thiesen (marcus@cpan.thiesenweb.de)

This package is free software and is provided "as is" without express
or implied warranty. It may be used, redistributed and/or modified



( run in 0.827 second using v1.01-cache-2.11-cpan-39bf76dae61 )