package Lire::UI::CompoundWidget; 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 max/; use vars qw/ @CARP_NOT %bindings %routines /; @CARP_NOT = qw/ Curses::UI::Container /; %bindings = ( KEY_PPAGE() => 'pageup', KEY_NPAGE() => 'pagedown' ); %routines = ( 'pageup' => \&help_pageup, 'pagedown' => \&help_pagedown ); sub new { my $class = shift; my %userargs = @_; keys_to_lowercase(\%userargs); check_object_param( $userargs{'value'}, 'value', 'Lire::Config::Dictionary' ); my $self = $class->Curses::UI::Container::new( %userargs, '-bindings' => \%bindings, '-routines' => \%routines ); if ( $self->shown_components() ) { $self->_setup_value_widgets(); $self->_setup_help_viewer(); } else { $self->_setup_empty_label(); } $self->layout(); return $self; } sub _setup_empty_label { my $self = $_[0]; $self->add('empty_label', 'Label', '-text'=>__('-- This option does not have any attributes --')); return; } sub _setup_value_widgets { my $self = $_[0]; foreach my $comp ( $self->shown_components() ) { my $name = $comp->name(); $self->add( "${name}_label", 'Label', '-text' => $name, '-bold' => 1, '-textalignment' => 'right' ); $self->add( "${name}_widget", 'Lire::UI::Widget', 'value' => $self->{'value'}->get( $name ), '-onfocus' => \&_child_focus_cb, 'onvaluechanged' => sub { $self->run_event( 'onvaluechanged' ) }, ); } return; } sub shown_components { my $self = $_[0]; grep { ! $_->obsolete() } $self->{'value'}->spec()->components(); } # FIXME: this is hackish sub _help_onfocus_cb { my $help = $_[0]; my $self = $help->parent(); if ( $help->{'_tag'} ) { $self->focus_next(); $help->{'_tag'} = 0; } else { $self->parent()->focus_next(); $help->{'_tag'} = 1; } return; } sub _setup_help_viewer { my $self = $_[0]; return unless $self->shown_components(); $self->add( 'help_summary', 'Label', '-bold' => 1 ); my $viewer = $self->add( 'help_viewer', 'TextViewer', '-wrapping' => 1, '-vscrollbar' => 1, '_tag' => 0 ); $viewer->onFocus( \&_help_onfocus_cb ); return; } sub help_viewer_width { return int( ($_[0]->canvaswidth() - 2) * 0.4 ); } sub layout_value_widgets { my $self = $_[0]; $self->{'_label_width'} = $self->_max_label_size(); $self->{'_widget_width'} = ( $self->canvaswidth() - $self->{'_label_width'} - $self->help_viewer_width() - 2 ); my $y = 0; my $left = $self->shown_components(); if ( $left * 2 - 1> $self->canvasheight() ) { $Curses::UI::screen_too_small++; return; } foreach my $comp ( $self->shown_components() ) { my $label = $self->getobj( $comp->name() . '_label' ); $label->{'-x'} = 0; $label->{'-y'} = $y; $label->{'-width'} = $self->{'_label_width'}; my $widget = $self->getobj( $comp->name() . "_widget" ); $widget->{'-x'} = $self->{'_label_width'} + 1; $widget->{'-y'} = $y; $widget->{'-width'} = $self->{'_widget_width'}; $widget->{'-height'} = int( ($self->canvasheight() - $y - ($left - 1)) / $left ); $widget->layout(); $y += $widget->{'-height'} + 1; $left--; } return; } sub layout_help_viewer { my $self = $_[0]; my $help_width = $self->help_viewer_width(); my $x = $self->{'_label_width'} + $self->{'_widget_width'} + 2; my $summary = $self->getobj( 'help_summary' ); $summary->{'-x'} = $x; $summary->{'-y'} = 0; $summary->{'-width'} = $help_width; my $viewer = $self->getobj( 'help_viewer' ); $viewer->{'-x'} = $x; $viewer->{'-y'} = 2; $viewer->{'-width'} = $help_width; return; } sub layout_contained_objects { my $self = $_[0]; return $self unless $self->getobj( 'help_viewer' ); $self->layout_value_widgets(); $self->layout_help_viewer(); return $self->SUPER::layout_contained_objects(); } sub refresh_view { my $self = $_[0]; foreach my $comp ( $self->shown_components() ) { my $name = $comp->name(); die "$name: $self" unless $self->isa( 'Lire::UI::CompoundWidget' ); $self->getobj( "${name}_widget" )->refresh_view(); } return; } sub _max_label_size { my $self = $_[0]; my $avail = int( ( $self->canvaswidth()-2 ) * 0.25 ); my @labels = map { $_->name() } $self->shown_components(); my $max = max( map { length $_ } @labels ); return ( $max < $avail ? $max : $avail ); } # Routines sub help_pageup { my $self = $_[0]; my $help_viewer = $self->getobj( 'help_viewer' ); $help_viewer->cursor_pageup(); $help_viewer->draw(); return; } sub help_pagedown { my $self = $_[0]; my $help_viewer = $self->getobj( 'help_viewer' ); $help_viewer->cursor_pagedown(); $help_viewer->draw(); return; } # callbacks sub _child_focus_cb { my $widget = $_[0]; my $self = $widget->parent(); my $value = $widget->{'value'}; $self->getobj( 'help_summary' )->text( $value->summary() ); my $help_viewer = $self->getobj( 'help_viewer' ); $help_viewer->cursor_up( undef, $help_viewer->{'-yscrpos'} ) if ( $help_viewer->{'-yscrpos'} > 1 ); $help_viewer->text( $value->text_description() || __( 'No help available.' ) ); return; } 1;