diff options
Diffstat (limited to 'perl-install/interactive/newt.pm')
-rw-r--r-- | perl-install/interactive/newt.pm | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/perl-install/interactive/newt.pm b/perl-install/interactive/newt.pm new file mode 100644 index 000000000..da18c198a --- /dev/null +++ b/perl-install/interactive/newt.pm @@ -0,0 +1,254 @@ +package interactivew::newt; # $Id$ + +use diagnostics; +use strict; +use vars qw(@ISA); + +@ISA = qw(interactive); + +use interactive; +use common; +use log; +use Newt::Newt; #- !! provides Newt and not Newt::Newt + +my ($width, $height) = (80, 25); +my @wait_messages; + +sub new() { + Newt::Init; + Newt::Cls; + Newt::SetSuspendCallback; + ($width, $height) = Newt::GetScreenSize; + open STDERR,">/dev/null" if $::isStandalone && !$::testing; + 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($_[1]) } +END { end() } + +sub myTextbox { + my $allow_scroll = shift; + + my $width = $width - 9; + my @l = map { /(.{1,$width})/g } map { split "\n" } @_; + my $h = min($height - 13, int @l); + my $flag = 1 << 6; + if ($h < @l) { + if ($allow_scroll) { + $flag |= 1 << 2; #- NEWT_FLAG_SCROLL + } else { + # remove the text, no other way! + @l = @l[0 .. $h-1]; + } + } + my $mess = Newt::Component::Textbox(1, 0, my $w = max(map { length } @l) + 1, $h, $flag); + $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_fromW { + my ($o, $common, $l, $l2) = @_; + my $ignore; #-to handle recursivity + my $old_focus = -2; + + #-the widgets + my (@widgets, $total_size); + + my $set_all = sub { + $ignore = 1; + $_->{set}->(${$_->{e}{val}}) foreach @widgets; +# $_->{w}->set_sensitive(!$_->{e}{disabled}()) foreach @widgets; + $ignore = 0; + }; + my $get_all = sub { + ${$_->{e}{val}} = $_->{get}->() foreach @widgets; + }; + my $create_widget = sub { + my ($e, $ind) = @_; + + $e->{type} = 'list' if $e->{type} =~ /(icon|tree)list/; + + #- combo doesn't exist, fallback to a sensible default + $e->{type} = $e->{not_edit} ? 'list' : 'entry' if $e->{type} eq 'combo'; + + my $changed = sub { + return if $ignore; + return $old_focus++ if $old_focus == -2; #- handle special first case + $get_all->(); + + #- TODO: this is very rough :( + $common->{callbacks}{$old_focus == $ind ? 'changed' : 'focus_out'}->($ind); + + $set_all->(); + $old_focus = $ind; + }; + + my ($w, $real_w, $set, $get, $expand, $size); + if ($e->{type} eq 'bool') { + $w = Newt::Component::Checkbox(-1, -1, $e->{text} || '', checkval(${$e->{val}}), " *"); + $set = sub { $w->CheckboxSetValue(checkval($_[0])) }; + $get = sub { $w->CheckboxGetValue == ord '*' }; + } elsif ($e->{type} eq 'button') { + $w = Newt::Component::Button(-1, -1, simplify_string(may_apply($e->{format}, ${$e->{val}}))); + } elsif ($e->{type} =~ /list/) { + my ($h, $wi) = (@$l == 1 && $height > 30 ? 10 : 5, 20); + my $scroll = @{$e->{list}} > $h ? 1 << 2 : 0; + $size = min(int @{$e->{list}}, $h); + + $w = Newt::Component::Listbox(-1, -1, $h, $scroll); #- NEWT_FLAG_SCROLL + foreach (@{$e->{list}}) { + my $t = simplify_string(may_apply($e->{format}, $_)); + $w->ListboxAddEntry($t, $_); + $wi = max($wi, length $t); + } + $w->ListboxSetWidth(min($wi + 3, $width - 7)); # 3 added for the scrollbar (?) + $get = sub { $w->ListboxGetCurrent }; + $set = sub { + my ($val) = @_; + map_index { + $w->ListboxSetCurrent($::i) if $val eq $_; + } @{$e->{list}}; + }; + } else { + $w = Newt::Component::Entry(-1, -1, '', 20, ($e->{hidden} && 1 << 11) | 1 << 2); + $get = sub { $w->EntryGetValue }; + $set = sub { $w->EntrySet($_[0], 1) }; + } + $total_size += $size || 1; + + #- !! callbacks must be kept otherwise perl will free them !! + #- (better handling of addCallback needed) + + { e => $e, w => $w, real_w => $real_w || $w, expand => $expand, callback => $changed, + get => $get || sub { ${$e->{val}} }, set => $set || sub {} }; + }; + @widgets = map_index { $create_widget->($_, $::i) } @$l; + + $_->{w}->addCallback($_->{callback}) foreach @widgets; + + $set_all->(); + + my $grid = Newt::Grid::CreateGrid(3, max(1, int @$l)); + map_index { + $grid->GridSetField(0, $::i, 1, ${Newt::Component::Label(-1, -1, $_->{e}{label})}, 0, 0, 1, 0, 1, 0); + $grid->GridSetField(1, $::i, 1, ${$_->{real_w}}, 0, 0, 0, 0, 1, 0); + } @widgets; + + my $listg = do { + my $height = 18; + #- use a scrolled window if there is a lot of checkboxes (aka + #- ask_many_from_list) or a lot of widgets in general (aka + #- options of a native PostScript printer in printerdrake) + #- !! works badly together with list's (lists are one widget, so a + #- big list window will not switch to scrollbar mode) :-( + if ((((grep { $_->{type} eq 'bool' } @$l) > 6) || + ((@$l) > 3)) && $total_size > $height) { + $grid->GridPlace(1, 1); #- Uh?? otherwise the size allocated is bad + + my $scroll = Newt::Component::VerticalScrollbar(-1, -1, $height, 9, 10); + my $subf = $scroll->Form('', 0); + $subf->FormSetHeight($height); + $subf->FormAddGrid($grid, 0); + Newt::Grid::HCloseStacked($subf, separator(1, $height), $scroll); + } else { + $grid; + } + }; + my ($buttons, $ok, $cancel) = Newt::Grid::ButtonBar(simplify_string($common->{ok} || _("Ok")), + if_($common->{cancel}, simplify_string($common->{cancel}))); + + my $form = Newt::Component::Form(\undef, '', 0); + my $window = Newt::Grid::GridBasicWindow(first(myTextbox(@widgets == 0, @{$common->{messages}})), $listg, $buttons); + $window->GridWrappedWindow($common->{title} || ''); + $form->FormAddGrid($window, 1); + + my $check = sub { + my ($f) = @_; + + $get_all->(); + my ($error, $focus) = $f->(); + + if ($error) { + $set_all->(); + } + !$error; + }; + + my ($destroyed, $canceled); + do { + my $r = do { + local $::setstep = 1; + $form->RunForm; + }; + $canceled = $cancel && $$r == $$cancel; + + if (my ($button) = grep { $$r == ${$_->{w}} } @widgets) { + $get_all->(); + my $v = do { + local $::setstep = 1; + $button->{e}{clicked_may_quit}(); + }; + $form->FormDestroy; + Newt::PopWindow; + return $v || &ask_fromW; + } + } until ($check->($common->{callbacks}{$canceled ? 'canceled' : 'complete'})); + + $form->FormDestroy; + Newt::PopWindow; + !$canceled; +} + + +sub waitbox { + my ($title, $messages) = @_; + my ($t, $w, $h) = myTextbox(1, @$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) = @_; + my $wait = pop @wait_messages; +# log::l("interactive_newt does not handle none stacked wait-messages") if $w->{form} != $wait; + Newt::PopWindow; +} + +sub simplify_string { + my ($s) = @_; + $s =~ s/\n/ /g; + $s = substr($s, 0, 40); #- truncate if too long + $s; +} + +1; |