package interactive_newt; # $Id$ use diagnostics; use strict; use vars qw(@ISA); @ISA = qw(interactive); use interactive; use common qw(:common :functional); use log; use Newt::Newt; #- !! provides Newt and not Newt::Newt my $width = 80; my $height = 25; my @wait_messages; sub new() { Newt::Init; Newt::Cls; Newt::SetSuspendCallback; open STDERR,">/dev/null" if $::isStandalone; bless {}, $_[0]; } sub enter_console { Newt::Suspend } sub leave_console { Newt::Resume } sub suspend { Newt::Suspend } sub resume { Newt::Resume } sub end() { Newt::Finished } sub exit() { end; exit($_[0]) } END { end() } sub myTextbox { my @l = map { split "\n" } @_; my $mess = Newt::Component::Textbox(1, 0, my $w = max(map { length } @l) + 1, my $h = @l, 1 << 6); $mess->TextboxSetText(join("\n", @_)); $mess, $w + 1, $h; } sub separator($$) { my $blank = Newt::Component::Form(\undef, '', 0); $blank->FormSetWidth ($_[0]); $blank->FormSetHeight($_[1]); $blank; } sub checkval($) { $_[0] && $_[0] ne ' ' ? '*' : ' ' } sub ask_from_listW { my ($o, $title_, $messages, $l, $def) = @_; my ($title, @okcancel) = ref $title_ ? @$title_ : ($title_, _("Ok"), _("Cancel")); my $mesg = join("\n", @$messages); my $len = 0; $len += length($_) foreach @$l; if (@$l == 1) { Newt::WinMessage($title, @$l, $mesg); $l->[0]; #- because newt will not try to remove window if bigger than screen ! } elsif (@$l == 2 && $len < 64) { $l->[Newt::WinChoice($title, @$l, $mesg) - 1]; #- because newt will not try to remove window if bigger than screen ! } elsif (@$l == 3 && $len < 64) { $l->[Newt::WinTernary($title, @$l, $mesg) - 1]; } else { my $special = !@okcancel; if ($special) { $l = [ @$l ]; @okcancel = pop @$l; } my $i; map_index { $i = $::i if $def eq $_ } @$l; my ($r, $e) = Newt::WinMenu($title, $mesg, 40, 5, 5, 8, $l, $i, @okcancel); $r > 1 and die "ask_from_list cancel"; if ($special) { $r ? $okcancel[0] : $l->[$e]; } else { $l->[$e]; } } } sub ask_many_from_listW { my ($o, $title, $messages, $l) = @_; my ($list, $val) = ($l->{labels}, $l->{ref}); my $height = min(int @$list, 18); my $sb = Newt::Component::VerticalScrollbar(-1, -1, $height, 9, 10); my $checklist = $sb->Form('', 0); $checklist->FormSetHeight($height); $checklist->FormSetBackground(9); my @l = map_index { Newt::Component::Checkbox(1, $::i + 1, $_, checkval(${$val->[$::i]} ||= ''), " *"); } @$list; $checklist->FormAddComponent($_) foreach @l; my $listg = Newt::Grid::HCloseStacked($checklist, $height < @$list ? (separator(1, $height), $sb) : ()); my ($buttons, $ok, $cancel) = Newt::Grid::ButtonBar(_("Ok"), _("Cancel")); my $form = Newt::Component::Form(\undef, '', 0); my $window = Newt::Grid::GridBasicWindow(first(myTextbox(@$messages)), $listg, $buttons); $window->GridWrappedWindow($title); $window->GridAddComponentsToForm($form, 1); my $r = $form->RunForm; $form->FormDestroy; Newt::PopWindow; $$r == $$cancel and return; mapn { my ($a, $b) = @_; $$a = $b->CheckboxGetValue == ord '*'; } $val, \@l; 1; } sub ask_from_entries_refW { my ($o, $title, $messages, $l, $val, %hcallback) = @_; my ($title_, @okcancel) = deref($title); my $ignore; #-to handle recursivity my $old_focus = -2; #-the widgets my @widgets = map { #- $_->{type} = "entry" if $_->{type} eq "list" && !$_->{not_edit}; ${$_->{val}} ||= ''; if ($_->{type} eq "list") { my $w = Newt::Component::Listbox(-1, -1, 1, 0); $w->ListboxSetWidth(20); $w->ListboxAddEntry($_) foreach @{$_->{list}}; $w; } elsif ($_->{type} eq "bool") { Newt::Component::Checkbox(-1, -1, $_->{text} || '', checkval(${$_->{val}}), " *"); } else { Newt::Component::Entry(-1, -1, '', 20, ($_->{hidden} && 1 << 1) | 1 << 2); } } @$val; my @updates = mapn { my ($w, $ref) = @_; sub { ${$ref->{val}} = $ref->{type} eq "bool" ? $w->CheckboxGetValue == ord '*' : $ref->{type} eq "list" ? $w->ListboxGetCurrent : $w->EntryGetValue; }; } \@widgets, $val; my @updates_inv = mapn { my ($w, $ref) = @_; sub { my $val = ${$ref->{val}}; $ignore = 1; if ($ref->{type} eq "bool") { $w->CheckboxSetValue(checkval($val)); } elsif ($ref->{type} eq "list") { map_index { $w->ListboxSetCurrent($::i) if $val eq $_; } @{$ref->{list}}; } else { $w->EntrySet($val, 1); } $ignore = 0; }; } \@widgets, $val; &$_ foreach @updates_inv; #- !! callbacks must be kept in a list otherwise perl will free them !! #- (better handling of addCallback needed) my @callbacks = map_index { my $ind = $::i; sub { return if $ignore; #-handle recursive deadlock return $old_focus++ if $old_focus == -2; #- handle special first case &$_ foreach @updates; #- TODO: this is very rough :( if ($old_focus == $ind) { $hcallback{changed}->($ind) if $hcallback{changed}; } else { $hcallback{focus_out}->($ind) if $hcallback{focus_out}; } &$_ foreach @updates_inv; $old_focus = $ind; }; } @widgets; map_index { $_->addCallback($callbacks[$::i]) } @widgets; my $grid = Newt::Grid::CreateGrid(3, int @$l); map_index { $grid->GridSetField(0, $::i, 1, ${Newt::Component::Label(-1, -1, $_)}, 0, 0, 1, 0, 1, 0); $grid->GridSetField(1, $::i, 1, ${$widgets[$::i]}, 0, 0, 0, 0, 1, 0); } @$l; my ($buttons, $ok, $cancel) = Newt::Grid::ButtonBar(@okcancel); my $form = Newt::Component::Form(\undef, '', 0) or die; my $window = Newt::Grid::GridBasicWindow(first(myTextbox(@$messages)), $grid, $buttons); $window->GridWrappedWindow($title_); $window->GridAddComponentsToForm($form, 1); run: my $r = $form->RunForm; &$_ foreach @updates; if ($$r != $$cancel && $hcallback{complete}) { my ($error, $focus) = $hcallback{complete}->(); #-update all the value &$_ foreach @updates_inv; goto run if $error; } $form->FormDestroy; Newt::PopWindow; $$r != $$cancel; } sub waitbox($$) { my ($title, $messages) = @_; my ($t, $w, $h) = myTextbox(@$messages); my $f = Newt::Component::Form(\undef, '', 0); Newt::CenteredWindow($w, $h, $title); $f->FormAddComponent($t); $f->DrawForm; Newt::Refresh; $f->FormDestroy; push @wait_messages, $f; $f; } sub wait_messageW($$$) { my ($o, $title, $messages) = @_; { form => waitbox($title, $messages), title => $title }; } sub wait_message_nextW { my ($o, $messages, $w) = @_; $o->wait_message_endW($w); $o->wait_messageW($w->{title}, $messages); } sub wait_message_endW { my ($o, $w) = @_; log::l("interactive_newt does not handle none stacked wait-messages") if $w->{form} != pop @wait_messages; Newt::PopWindow; } sub kill { } 1;