package TUI; use strict; use warnings; use diagnostics; use Curses::UI; # Singleton my $_cui; sub init_cui { if ( !defined $_cui ) { $_cui = new Curses::UI( -color_support => 1, -mouse_support => 1, # -clear_on_exit => 1, ); } return $_cui; } sub select_from_list { my ( $title, $multiselect, @items ) = @_; die "No items to choose from" unless @items; my @values = $multiselect ? ( '__ALL__', @items ) : @items; my %labels = $multiselect ? ( '__ALL__' => '[ALL]', map { $_ => $_ } @items, ) : map { $_ => $_ } @items; my @selection; my @selection_order; # multiselect only: items in toggle order my $cui = init_cui(); my $win = $cui->add( 'root', 'Window', ); my $listbox; $listbox = $win->add( 'item_list', 'Listbox', -title => $title, -border => 1, -values => \@values, -labels => \%labels, -multi => $multiselect == 1, -radio => $multiselect == 0, -padbottom => 1, -onchange => sub { return unless $multiselect; my %now = map { $_ => 1 } $listbox->get(); # Append newly selected items in toggle order for my $item (@items) { if ( $now{$item} && !grep { $_ eq $item } @selection_order ) { push @selection_order, $item; } } # Drop deselected items @selection_order = grep { $now{$_} } @selection_order; }, ); $win->add( 'info', 'Label', -y => -1, -text => "Space/Enter = toggle, C = confirm, Q = quit", ); $listbox->clear_binding('loose-focus'); $listbox->set_binding( sub { my @picked = $listbox->get(); if ( $multiselect && grep { $_ eq '__ALL__' } @picked ) { @selection = @items; } elsif ($multiselect) { @selection = @selection_order; } else { @selection = @picked; } $cui->mainloopExit(); }, 'c', ); $listbox->set_binding( sub { @selection = (); $cui->mainloopExit(); }, 'q', ); $listbox->focus(); $cui->mainloop(); $cui->leave_curses(); $cui->delete('root'); return @selection; } 1;