package Lire::UI::ListWidget;
use strict;
use base qw/ Curses::UI::Container Lire::UI::Widget /;
use Carp;
use Curses;
use Curses::UI::Common;
use Locale::TextDomain 'lire';
use Lire::Utils qw/ check_object_param text_for_width /;
use Lire::UI::Utils qw/ layout_buttonbox /;
use Lire::UI::ScalarListWidget;
use Lire::UI::CompoundListWidget;
use Lire::UI::PolyListWidget;
use vars qw/@CARP_NOT/;
@CARP_NOT = qw/Curses::UI::Container/;
my %bindings = ( KEY_IC() => 'add-element',
"\cc" => "copy-element",
KEY_DC() => 'del-element',
"J" => 'move-element-down',
"K" => 'move-element-up',
);
my %routines = ( 'add-element' => \&add_element,
'copy-element' => \©_element,
'move-element' => \&move_element,
'move-element-up' => \&move_element_up,
'move-element-down' => \&move_element_down,
'del-element' => \&del_element );
sub new {
my $class = shift;
my %userargs = @_;
keys_to_lowercase(\%userargs);
check_object_param( $userargs{'value'}, 'value', 'Lire::Config::List' );
my $spec = $userargs{'value'}->spec();
my @comp_names = $spec->component_names();
my $component = @comp_names ? $spec->get( $comp_names[0] ) : undef;
if ( $class eq __PACKAGE__) {
croak "'" . $spec->name() . "' should contain at least one component"
unless $component;
if ( @comp_names > 1 ) {
return new Lire::UI::PolyListWidget( @_ );
} elsif ( $component->isa( 'Lire::Config::ScalarSpec' ) ) {
return new Lire::UI::ScalarListWidget( @_ );
} else {
return new Lire::UI::CompoundListWidget( @_ );
}
}
my %userlistargs = ();
foreach my $p ( qw/-title -titlereverse -titlefullwidth / ) {
if ( exists $userargs{$p} ) {
$userlistargs{$p} = $userargs{$p};
delete $userargs{$p};
}
}
my $self = $class->Curses::UI::Container::new( %userargs,
'component' => $component,
'-bindings' => {%bindings},
'-routines' => {%routines},
'-releasefocus' => 1,
);
my $list_widget = $self->add( 'list', 'Listbox',
%userlistargs,
'-onselchange' => \&_sel_change_cb,
'-vscrollbar' => 1,
'-border' => 1,
'-selected' => 0 );
$self->refresh_view();
$self->add_contained_widgets();
$self->layout();
return $self;
}
sub extra_widget_height {
return 0;
}
sub layout_contained_objects {
my $self = $_[0];
return $self unless $self->getobj( 'list' );
my $list = $self->getobj( 'list' );
$list->{'-width'} = $self->canvaswidth();
$list->{'-height'} =
$self->canvasheight() - $self->extra_widget_height() - 1;
$list->{'-title'} = text_for_width( $self->title(),
$self->canvaswidth() - 4 )
if ( $self->title() );
$self->layout_buttons();
return $self->SUPER::layout_contained_objects();
}
sub layout_buttons {
my $self = $_[0];
my $buttons = $self->getobj( 'buttons' );
$buttons->{'-buttons'}[0]{'-label'} = __( 'Add' );
$buttons->{'-buttons'}[2]{'-label'} = __( 'Copy' );
$buttons->{'-buttons'}[3]{'-label'} = __( 'Delete' );
$buttons->{'-buttons'}[4]{'-label'} = __( 'Up' );
$buttons->{'-buttons'}[5]{'-label'} = __( 'Down' );
layout_buttonbox( $self, $buttons, 1, 1 );
$buttons->{'-y'} = $self->canvasheight() - 1;
return;
}
sub add_contained_widgets {
my $self = $_[0];
$self->add_buttons_widget();
return;
}
sub add_buttons_widget {
my $self = $_[0];
$self->add( 'buttons', 'Buttonbox',
'-releasefocus' => 1,
'-buttons' => [ { '-label' => __( 'Add' ),
'-onpress' => sub { $self->do_routine( 'add-element' ) } },
{ '-label' => __( 'Copy' ),
'-onpress' => sub { $self->do_routine( 'copy-element' ) } },
{ '-label' => __( 'Delete' ),
'-onpress' => sub { $self->do_routine( 'del-element' ) } },
{ '-label' => __( 'Up' ),
'-onpress' => sub { $self->do_routine( 'move-element-up' ) } },
{ '-label' => __( 'Down' ),
'-onpress' => sub { $self->do_routine( 'move-element-down' ) } },
] );
return;
}
sub title {
return shift->getobj( 'list' )->title( @_ );
}
# Routines
sub add_element {
my $self = $_[0];
my $instance = $self->new_value();
if ( $instance ) {
my $list = $self->getobj( 'list' );
$self->{'value'}->append( $instance, $list->{'-selected'} );
$list->{'-ypos'} = ( defined $list->{'-selected'}
? $list->{'-selected'} + 1 : 0 );
$self->refresh_view();
$self->run_event( 'onvaluechanged' );
}
return;
}
sub copy_element {
my $self = $_[0];
my $list = $self->getobj( 'list' );
return unless defined $list->{'-selected'};
my $instance = $self->{'value'}->get( $list->{'-selected'} )->clone();
$self->{'value'}->append( $instance, $list->{'-selected'} );
$list->{'-ypos'} = $list->{'-selected'} + 1;
$self->refresh_view();
$self->run_event( 'onvaluechanged' );
return;
}
sub move_element_up {
$_[0]->move_element( -1 );
return;
}
sub move_element_down {
$_[0]->move_element( 1 );
return;
}
sub move_element {
my ( $self, $offset ) = @_;
my $list = $self->getobj( 'list' );
return unless defined $list->{'-selected'};
my $new_idx = $list->{'-selected'} + $offset;
$new_idx = 0
if $new_idx < 0;
$new_idx = $#{$list->{'-values'}}
if $new_idx > $#{$list->{'-values'}};
return if $new_idx == $list->{'-selected'};
$self->{'value'}->move( $list->{'-selected'}, $new_idx );
$list->{'-ypos'} = $new_idx;
$self->refresh_view();
$self->run_event( 'onvaluechanged' );
return;
}
sub refresh_view {
my $self = $_[0];
my $list_widget = $self->getobj( 'list' );
my $values = [ $self->{'value'}->elements() ];
my %labels = map { $_, $_->as_label() } $self->{'value'}->elements();
if ( scalar @$values == 0 ) {
$values = [ __( '-- empty list --' ) ];
$list_widget->focusable( 0 );
$list_widget->{'-selected'} = undef;
} else {
$list_widget->focusable( 1 );
$list_widget->{'-selected'} = $list_widget->{'-ypos'};
}
$list_widget->{'-values'} = $values;
$list_widget->{'-labels'} = \%labels;
$list_widget->draw();
return;
}
sub del_element {
my $self = $_[0];
my $list_widget = $self->getobj( 'list' );
return unless $list_widget->focusable();
$self->{'value'}->remove( $list_widget->{'-ypos'} );
my $nbr = scalar $self->{'value'}->elements() - 1;
if ( $list_widget->{'-selected'} > $nbr ) {
$list_widget->{'-ypos'} = $nbr;
}
$self->refresh_view();
$self->run_event( 'onvaluechanged' );
return;
}
sub _sel_change_cb {
my $list_widget = $_[0];
$list_widget->{'-selected'} = $list_widget->{'-ypos'};
$list_widget->run_event( '-onchange' );
return;
}
1;
syntax highlighted by Code2HTML, v. 0.9.1