Curses-UI

 view release on metacpan or  search on metacpan

examples/color_editor  view on Meta::CPAN

	      " ^Q Quit from the program ^S save file"
	    . " ^W toggle wrapping\n"
	    . " ^X Open the menu         ^O open file"
	    . " ^R toggle hard returns viewing",
);

# ----------------------------------------------------------------------
# Callback routines
# ----------------------------------------------------------------------
	
sub open_dialog()
{
	my $file = $cui->loadfilebrowser( 
		-file         => $currentfile,
		-bg           => "green",
		-fg           => "white",
		-bbg           => "green",
		-bfg           => "white",
		-tbg           => "green",
		-tfg           => "white",
	);

examples/color_editor  view on Meta::CPAN

		    close F;
		    $editor->text($text);
		    $editor->cursor_to_home;
	 	    $currentfile = $file;
		} else { 
		    $cui->error(-message => "Can't read file \"$file\":\n$!");
		}
	}
}

sub save_dialog()
{

	my $file = $cui->savefilebrowser(
		-file         => $currentfile,
		-bg           => "green",
		-fg           => "white",
		-bbg           => "green",
		-bfg           => "white",
		-tbg           => "green",
		-tfg           => "white",

examples/color_editor  view on Meta::CPAN

		$cui->dialog(-message => "File \"$file\"\nsuccessfully saved");
		$currentfile = $file;
	    } else {
		$cui->error(-message => "Error on closing file \"$file\":\n$!");
	    }
	} else {
	    $cui->error(-message => "Can't write to $file:\n$!");
	}
}

sub about_dialog()
{
	$cui->dialog(
		-title => 'About editor',
		-message => "Program : Curses::UI Editor\n"
	 		  . "Author  : Maurice Makaay\n"
		          . "          Marcus Thiesen\n"
			  . "\n"
			  . "The sole purpose of this editor\n"
			  . "is the demonstration of the perl\n"
		 	  . "Curses::UI widget set and the newly\n"
		          . "developed color support.\n",
		-bg           => "white",
		-fg           => "red",
		-bbg           => "white",
		-bfg           => "red",
		-tbg           => "white",
		-tfg           => "red",
	);
}
		
sub exit_dialog()
{
	my $return = $cui->dialog(
			-title     => "Are you sure???", 
			-buttons   => ['yes', 'no'],
			-message => "Do you really want to quit?",
            	        -tbg => "white",
			-tfg => "red",
            	        -bg => "white",
			-fg => "red",
            	        -bbg => "white",

examples/demo-widgets  view on Meta::CPAN

# Demo index
my $current_demo = 1;

# Demo windows
my %w = ();

# ----------------------------------------------------------------------
# Create a menu
# ----------------------------------------------------------------------

sub select_demo($;)
{
    my $nr = shift;
    $current_demo = $nr;
    $w{$current_demo}->focus;
}

my $file_menu = [
    { -label => 'Quit program',       -value => sub {exit(0)}        },
],

examples/demo-widgets  view on Meta::CPAN

);

$w{2}->add(
    'buttonlabel', 'Label',
    -y => 7,
    -width => -1,
    -bold => 1,
    -text => "Press a button please...",
);

sub button_callback($;)
{
    my $this = shift;
    my $label = $this->parent->getobj('buttonlabel');
    $label->text("You pressed: " . $this->get);
}

$w{2}->add(
    undef, 'Buttonbox',
    -y => 5,    
    -buttons => [

examples/demo-widgets  view on Meta::CPAN

    undef, 'Label',
    -text => "The listbox can be used for selecting on or more options\n"
	   . "out of a predefined list of options. <SPACE> and <ENTER> will\n"
	   . "change the current selected option for a normal listbox and a\n"
	   . "radiobuttonbox, They will toggle the state of the active option in\n"
	   . "a multi-select listbox. In a multi-select listbox you can also\n"
	   . "use <Y> and <N> to check or uncheck options. Press </> for a\n"
	   . "'less'-like search through the list."
);

sub listbox_callback()
{
    my $listbox = shift;
    my $label = $listbox->parent->getobj('listboxlabel');
    my @sel = $listbox->get;
    @sel = ('<none>') unless @sel;
    my $sel = "selected: " . join (", ", @sel);
    $label->text($listbox->title . " $sel");
}

$w{5}->add(

examples/demo-widgets  view on Meta::CPAN

            -x => 15, -y => 6,  -showvalue    => 1 );

$w{7}->add( undef, "Label", -y => 10, -text => "No centerline");
$w{7}->add( 'p2', 'Progressbar', -max => 60, 
            -x => 15, -y => 9, -nocenterline => 1 );

$w{7}->add( undef, "Label", -y => 13, -text => "No percentage");
$w{7}->add( 'p3', 'Progressbar', -max => 60, 
            -x => 15, -y => 12, -nopercentage => 1 );

sub progressbar_timer_callback($;)
{
    my $cui = shift;
    my @l = localtime;
    $w{7}->getobj('p1')->pos($l[2]);
    $w{7}->getobj('p2')->pos($l[1]);
    $w{7}->getobj('p3')->pos($l[0]);
    $w{7}->getobj('progressbarlabel')->text(
         sprintf("%02d:%02d:%02d", @l[2,1,0])
    );
}

examples/demo-widgets  view on Meta::CPAN

# ----------------------------------------------------------------------
# Setup bindings and focus 
# ----------------------------------------------------------------------

# Bind <CTRL+Q> to quit.
$cui->set_binding( sub{ exit }, "\cQ" );

# Bind <CTRL+X> to menubar.
$cui->set_binding( sub{ shift()->root->focus('menu') }, "\cX" );

sub goto_next_demo()
{
    $current_demo++;
    $current_demo = @screens if $current_demo > @screens;
    $w{$current_demo}->focus;
}
$cui->set_binding( \&goto_next_demo, "\cN" );

sub goto_prev_demo()
{
    $current_demo--;
    $current_demo = 1 if $current_demo < 1;
    $w{$current_demo}->focus;
}

$cui->set_binding( \&goto_prev_demo, "\cP" );

$w{$current_demo}->focus;

examples/editor  view on Meta::CPAN

	      " ^Q Quit from the program ^S save file"
	    . " ^W toggle wrapping\n"
	    . " ^X Open the menu         ^O open file"
	    . " ^R toggle hard returns viewing",
);

# ----------------------------------------------------------------------
# Callback routines
# ----------------------------------------------------------------------
	
sub open_dialog()
{
	my $file = $cui->loadfilebrowser( 
		-file         => $currentfile,
	);

	if (defined $file) 
	{
		if (open F, "<$file") {
		    my $text = "";
		    while (<F>) { $text .= $_ }
		    close F;
		    $editor->text($text);
		    $editor->cursor_to_home;
	 	    $currentfile = $file;
		} else { 
		    $cui->error(-message => "Can't read file \"$file\":\n$!");
		}
	}
}

sub save_dialog()
{

	my $file = $cui->savefilebrowser(
		-file         => $currentfile,
	);
	return unless defined $file;

	if (open F, ">$file") {
	    print F $editor->text;
	    if (close F) {
		$cui->dialog(-message => "File \"$file\"\nsuccessfully saved");
		$currentfile = $file;
	    } else {
		$cui->error(-message => "Error on closing file \"$file\":\n$!");
	    }
	} else {
	    $cui->error(-message => "Can't write to $file:\n$!");
	}
}

sub about_dialog()
{
	$cui->dialog(
		-title => 'About editor',
		-message => "Program : Curses::UI Editor\n"
	 		  . "Author  : Maurice Makaay\n"
			  . "\n"
			  . "The sole purpose of this editor\n"
			  . "is the demonstration of my perl\n"
		 	  . "Curses::UI widget set."
	);
}
		
sub exit_dialog()
{
	my $return = $cui->dialog(
			-title     => "Are you sure???", 
			-buttons   => ['yes', 'no'],
			-message => "Do you really want to quit?"
	);

	exit(0) if $return;
}

examples/pop3_reader  view on Meta::CPAN

my $pop3       = undef;
my $connection = undef;

# We do not want STDERR to clutter our screen.
open STDERR, ">/dev/null";

# ----------------------------------------------------------------------
# setup(): Setup the connection
# ----------------------------------------------------------------------

sub check_connection($;)
{
	my $buttons = shift;
	my $conwin  = $buttons->parent;
	my $cui     = $conwin->root;

	foreach my $key ('username','password','host','port') 
	{
		my $obj = $conwin->getobj($key);
		my $value = $obj->get;
		$connection->{$key} = $value;

examples/pop3_reader  view on Meta::CPAN

		if ($value =~ /^\s*$/) {
			$cui->error("Missing value for $key field");
			$obj->focus;
			return;
		}
	}

	return 1;
}

sub setup_connection()
{
	my $conwin = $cui->add(
		'connection_window', 'Window',
		-border => 1,
		-ipad => 2,
		-height => 15,
		-width => 60,
		-centered => 1,
		-title => "POP3 connection",
	);	 

examples/pop3_reader  view on Meta::CPAN

	);

	$conwin->modalfocus;
	$cui->delete('connection_window')
}

# ----------------------------------------------------------------------
# pop3_connect(): Connect to the POP3 server and exit if it fails
# ----------------------------------------------------------------------

sub pop3_connect()
{
	$cui->progress(
		-message => "Connecting to the POP3 server...",
		-max => 4,
		-pos => 1,
	);

	my $error = 0;

	$pop3 = Net::POP3->new(

examples/pop3_reader  view on Meta::CPAN


	$cui->noprogress;

	return !$error;
}

# ----------------------------------------------------------------------
# The inbox screen
# ----------------------------------------------------------------------

sub build_inbox()
{
	my $list = $pop3->list();
	my @ids = sort {$a<=>$b} keys %$list;

	my $msg = "Retrieving headers";
	$cui->progress(
		-max => scalar(@ids),
		-message => $msg,
	);

examples/pop3_reader  view on Meta::CPAN

	);
	
	$ml->set_binding(sub{exit(0)}, "\cC", "\cQ");
	$ml->set_routine('option-select', \&view_message);
}

# ----------------------------------------------------------------------
# view_message(): callback routine for the inbox list
# ----------------------------------------------------------------------

sub view_message()
{
	my $this = shift;	

	# Get the selected message id.
	$this->{-selected} = $this->{-ypos};
	my $id = $this->get;
	$this->{-selected} = undef;
	
	# Retrieve the message from the POP3 server.
	$cui->status("Retrieving message $id from the POP3 server...");

examples/tutorial  view on Meta::CPAN

);

my $win1 = $cui->add(
		     'win1', 'Window',
		     -border => 1,
		     -y    => 1,
		     -bfg  => 'red',
		     );


sub exit_dialog()
{
	my $return = $cui->dialog(
			-message   => "Do you really want to quit?",
			-title     => "Are you sure???", 
			-buttons   => ['yes', 'no'],

	);

	exit(0) if $return;
}

lib/Curses/UI.pm  view on Meta::CPAN


    # Walk through all contained objects and let them
    # layout themselves.
    $self->layout_contained_objects;
    $self->draw();

    $Curses::UI::initialized = 1;
    return $self;
}

sub layout_new()
{
    my $self = shift;

    $Curses::UI::screen_too_small = 0;

    # find the terminal size.
    my ($cols,$lines) = GetTerminalSize;
    $ENV{COLS}  = $cols;
    $ENV{LINES} = $lines;

lib/Curses/UI.pm  view on Meta::CPAN

    return $self;
}


# ----------------------------------------------------------------------
# Event handling
# ----------------------------------------------------------------------


# TODO: document
sub do_one_event(;$)
{
    my $self = shift;
    my $object = shift;
    $object = $self unless defined $object;

    eval {curs_set($self->{-cursor_mode})};

    # gpm mouse?
    if ($Curses::UI::gpm_mouse) {
	$self->handle_gpm_mouse_event($object);

lib/Curses/UI.pm  view on Meta::CPAN


    # Update the screen.
    doupdate();

    return $self;
}

# TODO: document

# TODO: document
sub add_callback()
{
    my $self = shift;
    my $id   = shift;
    my $code = shift;

    $self->fatalerror(
        "add_callback(): is is not set"
    ) unless defined $id;

    $self->fatalerror(
        "add_callback(): callback is no CODE reference"
    ) unless defined $code and ref $code eq 'CODE';

    $self->{-added_code}->{$id} = $code;
}

# TODO: document
sub delete_callback()
{
    my $self = shift;
    my $id   = shift;

    $self->fatalerror(
      "delete_callback(): id is not set"
    ) unless defined $id;

    delete $self->{-added_code}->{$id} if
	defined $self->{-added_code}->{$id};
}

sub draw()
{
    my $self = shift;
    my $no_doupdate = shift || 0;

    if ($Curses::UI::screen_too_small)
    {
        my $s = $self->{-canvasscr};
        $s->clear;
        $s->addstr(0, 0, $self->lang->get('screen_too_small'));
        $s->move(4,0);
        $s->noutrefresh();
	doupdate();
    } else {
	$self->SUPER::draw(1);
	doupdate() unless $no_doupdate;
    }
}

# TODO: document
sub feedkey()
{
    my $self = shift;
    my $key = shift;
    $self->{-feedkey} = $key;
    return $self;
}

# TODO: document
sub flushkeys()
{
    my $self = shift;

    my $key = '';
    my @k = ();
    until ( $key eq "-1" ) {
        $key = $self->get_key(0);
    }
}

# Returns 0 if less than -keydelay seconds have elapsed since the last
# user action. Returns the number of elapsed seconds otherwise.
sub keydelay()
{
    my $self = shift;

    my $time = time();
    my $elapsed = $time - $self->{-lastkey};

    return 0 if ($elapsed < $self->{-keydelay});
    return $elapsed;
}

# ----------------------------------------------------------------------
# Timed event handling
# ----------------------------------------------------------------------

sub set_read_timeout()
{
    my $self = shift;

    my $new_timeout = -1;
    TIMER: while (my ($id, $config) = each %{$self->{-timers}})
    {
        # Skip timer if it is disabled.
        next TIMER unless $config->{-enabled};

	$new_timeout = $config->{-time} 
	    unless $new_timeout != -1 and
	           $new_timeout < $config->{-time};
    }
    $new_timeout = 1 if $new_timeout < 0 and $new_timeout != -1;

    $self->{-read_timeout} = $new_timeout;
    return $self;
}

sub set_timer($$;)
{
    my $self     = shift;
    my $id       = shift;
    my $callback = shift;
    my $time     = shift || 1;

    $self->fatalerror(
        "add_timer(): callback is no CODE reference"
    ) unless defined $callback and ref $callback eq 'CODE';

lib/Curses/UI.pm  view on Meta::CPAN

        -enabled  => 1,
        -lastrun  => time(),
    };
    $self->{-timers}->{$id} = $config;

    $self->set_read_timeout;

    return $self;
}

sub disable_timer($;)
{
    my ($self,$id) = @_;
    if (defined $self->{-timers}->{$id}) {
        $self->{-timers}->{$id}->{-enabled} = 0;
    }
    $self->set_read_timeout;
    return $self;
}

sub enable_timer($;)
{
    my ($self,$id) = @_;
    if (defined $self->{-timers}->{$id}) {
        $self->{-timers}->{$id}->{-enabled} = 1;
    }
    $self->set_read_timeout;
    return $self;
}

sub delete_timer($;)
{
    my ($self,$id) = @_;
    if (defined $self->{-timers}->{$id}) {
        delete $self->{-timers}->{$id};
    }
    $self->set_read_timeout;
    return $self;
}

sub do_timer()
{
    my $self = shift;

    my $now = time();
    my $timers_done = 0;

    # Short-circuit timers if the keydelay hasn't elapsed
    if ($self->{-keydelay}) {
        return $self unless $self->keydelay;
    }

lib/Curses/UI.pm  view on Meta::CPAN

    #
    $self->focus_path(-1)->draw if $timers_done;

    return $self;
}

# ----------------------------------------------------------------------
# Mouse events
# ----------------------------------------------------------------------

sub handle_mouse_event()
{
    my $self = shift;
    my $object = shift;
    $object = $self unless defined $object;

    my $MEVENT = 0;
    getmouse($MEVENT);

    # $MEVENT is a struct. From curses.h (note: this might change!):
    #

lib/Curses/UI.pm  view on Meta::CPAN

    {
	# Send the mouse-event to the object. 
	# Leave the loop if the object handled the event.
	print STDERR "Asking $object to handle $MEVENT{-bstate} ...\n" if
	    $Curses::UI::debug;
	my $return = $object->event_mouse(\%MEVENT);
	last if defined $return and $return ne 'DELEGATE';
    }
}

sub handle_gpm_mouse_event()
{
    my $self = shift;
    my $object = shift;
    $object = $self unless defined $object;

    return unless $Curses::UI::gpm_mouse;

    my $MEVENT = gpm_get_mouse_event();
    # $MEVENT from C:UI:MH:GPM is identical.

lib/Curses/UI.pm  view on Meta::CPAN

    {
	# Send the mouse-event to the object. 
	# Leave the loop if the object handled the event.

	my $return = $object->event_mouse(\%MEVENT);
	last if defined $return and $return ne 'DELEGATE';
    }
}


sub object_at_xy($$;$)
{
    my $self = shift;
    my $object = shift;
    my $x = shift;
    my $y = shift;
    my $tree = shift;
    $tree = [] unless defined $tree;

    push @$tree, $object;

lib/Curses/UI.pm  view on Meta::CPAN


    return $tree;
}


# ----------------------------------------------------------------------
# Other subroutines
# ----------------------------------------------------------------------

# TODO: document
sub fatalerror($$;$)
{
    my $self  = shift;
    my $error = shift;
    my $exit  = shift;

    $exit = 1 unless defined $exit;
    chomp $error;
    $error .= "\n";

    my $s = $self->{-canvasscr};

lib/Curses/UI.pm  view on Meta::CPAN

    $self->flushkeys();
    for (;;)
    {
	my $key = $self->get_key();
	last if $key ne "-1";
    }

    exit($exit);
}

sub usemodule($;)
{
    my $self = shift;
    my $class = shift;

    # Create class filename.
    my $file = $class;
    $file =~ s|::|/|g;
    $file .= '.pm';

    # Automatically load the required class.

lib/Curses/UI.pm  view on Meta::CPAN

        };

        # Fatal error if the class could not be loaded.
	$self->fatalerror("Could not load $class from $file:\n$@")
	    if $@;
    }

    return $self;
}

sub focus_path()
{
    my $self = shift;
    my $index = shift;

    my $p_obj = $self;
    my @path = ($p_obj);
    for(;;)
    {
        my $p_el = $p_obj->{-draworder}->[-1];
        last unless defined $p_el;

lib/Curses/UI.pm  view on Meta::CPAN

        last if $p_obj->isa('Curses::UI::ContainerWidget');
    }

    return (defined $index ? $path[$index] : @path);
}

# add() is overridden, because we only want to be able
# to add Curses::UI:Window objects to the Curses::UI
# rootlevel.
#
sub add()
{
    my $self = shift;
    my $id = shift;
    my $class = shift;
    my %args = @_;

    # Make it possible to specify WidgetType instead of
    # Curses::UI::WidgetType.
    $class = "Curses::UI::$class"
        if $class !~ /\:\:/ or

lib/Curses/UI.pm  view on Meta::CPAN

    {
        $self->{-userdata} = $_[0];
    }
    return $self->{-userdata};
}

# ----------------------------------------------------------------------
# Focusable dialog windows
# ----------------------------------------------------------------------

sub tempdialog()
{
    my $self = shift;
    my $class = shift;
    my %args = @_;

    my $id = "__window_$class";

    my $dialog = $self->add($id, $class, %args);
    $dialog->modalfocus;
    my $return = $dialog->get;

lib/Curses/UI.pm  view on Meta::CPAN

# The argument list will be returned unchanged, unless it
# contains only one item. In that case ($ifone, $_[0]) will
# be returned. This enables constructions like:
#
#    $cui->dialog("Some dialog message");
#
# instead of:
#
#    $cui->dialog(-message => "Some dialog message");
#
sub process_args()
{
    my $self = shift;
    my $ifone = shift;
    if (@_ == 1) { @_ = ($ifone => $_[0]) }
    return @_;
}

sub error()
{
    my $self = shift;
    my %args = $self->process_args('-message', @_);
    $self->tempdialog('Dialog::Error', %args);
}

sub dialog()
{
    my $self = shift;
    my %args = $self->process_args('-message', @_);
    $self->tempdialog('Dialog::Basic', %args);
}

sub question()
{
    my $self = shift;
    my %args = $self->process_args('-question', @_);
    $self->tempdialog('Dialog::Question', %args);
}

sub calendardialog()
{
    my $self = shift;
    my %args = $self->process_args('-title', @_);
    $self->tempdialog('Dialog::Calendar', %args);
}

sub filebrowser()
{
    my $self = shift;
    my %args = $self->process_args('-title', @_);

    # Create title
    unless (defined $args{-title}) {
	my $l = $self->root->lang;
	$args{-title} = $l->get('file_title');
    }

    # Select a file to load from.
    $self->tempdialog('Dialog::Filebrowser', %args);
}

sub dirbrowser()
{
    my $self = shift;
    my %args = $self->process_args('-title', @_);

    # Create title
    unless (defined $args{-title}) {
	my $l = $self->root->lang;
	$args{-title} = $l->get('dir_title');
    }

    # Select a file to load from.
    $self->tempdialog('Dialog::Dirbrowser', %args);
}

sub savefilebrowser()
{
    my $self = shift;
    my %args = $self->process_args('-title', @_);

    my $l = $self->root->lang;

    # Create title.
    $args{-title} = $l->get('file_savetitle')
	unless defined $args{-title};

lib/Curses/UI.pm  view on Meta::CPAN

            -title     => $title,
            -buttons   => [ 'yes', 'no' ],
            -message   => $pre . $file . $post,
        );
        return unless $overwrite;
    }

    return $file;
}

sub loadfilebrowser()
{
    my $self = shift;
    my %args = $self->process_args('-title', @_);

    # Create title
    unless (defined $args{-title}) {
	my $l = $self->root->lang;
	$args{-title} = $l->get('file_loadtitle');
    }

    $self->filebrowser(-editfilename  => 0, %args);
}

# ----------------------------------------------------------------------
# Non-focusable dialogs
# ----------------------------------------------------------------------

my $status_id = "__status_dialog";
sub status($;)
{
    my $self = shift;
    my %args = $self->process_args('-message', @_);

    $self->delete($status_id);
    $self->add($status_id, 'Dialog::Status', %args)->draw;

    return $self;
}

sub nostatus()
{
    my $self = shift;
    $self->delete($status_id);
    $self->flushkeys();
    $self->draw;
    return $self;
}

sub progress()
{
    my $self = shift;
    my %args = @_;

    $self->add(
        "__progress_$self",
        'Dialog::Progress',
        %args
    );
    $self->draw;

    return $self;
}

sub setprogress($;$)
{
    my $self = shift;
    my $pos  = shift;
    my $message = shift;

    # If I do not do this, the progress bar seems frozen
    # if a key is pressed on my Solaris machine. Flushing
    # the input keys solves this. And this is not a bad
    # thing to do during a progress dialog (input is ignored
    # this way).

lib/Curses/UI.pm  view on Meta::CPAN


    my $p = $self->getobj("__progress_$self");
    return unless defined $p;
    $p->pos($pos) if defined $pos;
    $p->message($message) if defined $message;
    $p->draw;

    return $self;
}

sub noprogress()
{
    my $self = shift;
    $self->delete("__progress_$self");
    $self->flushkeys;
    $self->draw;
    return $self;
}

sub leave_curses()
{
    my $self = shift;
    def_prog_mode();
    endwin();
}

sub reset_curses()
{
    my $self = shift;
    reset_prog_mode();
    $self->layout(); # In case the terminal has been resized
}

### Color support

sub color() {
    my $self = shift;
    return $Curses::UI::color_object;
}

sub set_color {
    my $self = shift;
    my $co   = shift;

    $Curses::UI::color_object = $co;
}



# ----------------------------------------------------------------------
# Accessor functions
# ----------------------------------------------------------------------

sub compat(;$)        { shift()->accessor('-compat',          shift()) }
sub clear_on_exit(;$) { shift()->accessor('-clear_on_exit',   shift()) }
sub cursor_mode(;$)   { shift()->accessor('-cursor_mode',     shift()) }
sub lang(;$)          { shift()->accessor('-language_object', shift()) }
sub overlapping(;$)   { shift()->accessor('-overlapping',     shift()) }

# TODO: document
sub debug(;$)
{
    my $self  = shift;
    my $value = shift;
    $Curses::UI::debug = $self->accessor('-debug', $value);
}





lib/Curses/UI/Buttonbox.pm  view on Meta::CPAN

    $this->layout();

    if ($Curses::UI::ncurses_mouse) {
        $this->set_mouse_binding('mouse-button1', BUTTON1_CLICKED());
    }

    return $this;
}


sub process_buttondefs()
{
    my $this    = shift;

    my $buttons = $this->{-buttons};

    # Process button types.
    my @buttons = ();
    foreach my $button (@$buttons)
    {
        if (ref $button eq 'HASH') {

lib/Curses/UI/Buttonbox.pm  view on Meta::CPAN

        }

        keys_to_lowercase($button);
        push @buttons, $button;
    }

    $this->{-buttons} =  \@buttons;
    return $this;
}

sub layout()
{
    my $this = shift;

    $this->SUPER::layout() or return;

    # Compute the space that is needed for the buttons.
    my $xneed = $this->compute_buttonwidth;
    my $yneed = $this->compute_buttonheight;
    
    if ( ($xneed > $this->canvaswidth) || ($yneed > $this->canvasheight) ) 

lib/Curses/UI/Buttonbox.pm  view on Meta::CPAN

    # Make shortcuts all upper-case.    
    foreach my $button (@{$this->{-buttons}}) {
        if (defined $button->{-shortcut}) {
            $button->{-shortcut} = uc $button->{-shortcut};
        }
    }

    return $this;
}

sub get_selected_button()
{
    my $this = shift;
    my $selected = $this->{-selected}; 
    my $button = $this->{-buttons}->[$selected];
    return $button;
}

sub get()
{
    my $this = shift;
    my $button = $this->get_selected_button;
    if (defined $button->{-value}) {
        return $button->{-value};
    } else {
        return $this->{-selected};
    }
}

sub next_button()
{
    my $this = shift;
    $this->{-selected}++;
    $this->schedule_draw(1);
    return $this;
}

sub previous_button()
{
    my $this = shift;
    $this->{-selected}--;
    $this->schedule_draw(1);
    return $this;
}

# Focus the next button. If the last button was 
# selected, let the buttonbox loose focus.
sub focus_shift()
{
    my $this = shift;
    my $key  = shift;

    if ( $key eq KEY_BTAB() )
    {
	$this->previous_button();
	if ($this->{-selected} < 0)
	{
#	    $this->schedule_draw(0);

lib/Curses/UI/Buttonbox.pm  view on Meta::CPAN

	{
#	    $this->schedule_draw(0);
	    $this->{-selected} = 0;
	    $this->do_routine('loose-focus', $key);
	}
    }

    return $this;
}

sub press_button()
{
    my $this = shift;
    my $button = $this->get_selected_button;
    my $command = $button->{-onpress};
    $this->schedule_draw(1);
    if (defined $command and ref $command eq 'CODE') {
        $command->($this);
    }    
    return $this;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw the widget.
    $this->SUPER::draw(1) or return $this;
    
    # Check if active element isn't out of bounds.
    $this->{-selected} = 0 unless defined $this->{-selected};
    $this->{-selected} = 0 if $this->{-selected} < 0; 

lib/Curses/UI/Buttonbox.pm  view on Meta::CPAN

        
        $id++;
    }
    $this->{-canvasscr}->move(0,0);
    $this->{-canvasscr}->noutrefresh;
    doupdate() unless $no_doupdate;

    return $this;
}

sub mouse_button1($$$$;)
{
    my $this  = shift;
    my $event = shift;
    my $x     = shift;
    my $y     = shift;

    my $idx = 0;
    my $bx  = $this->{-xpos};

    # Clicked left of the buttons?

lib/Curses/UI/Buttonbox.pm  view on Meta::CPAN

    undef $idx if defined $idx and 
		  $idx > (@{$this->{-buttons}} - 1);

    if (defined $idx) {
	$this->{-selected} = $idx;
	$this->focus();
	$this->do_routine('press-button', $event);
    }
}

sub compute_buttonheight($;) 
{
    my $this   = shift;
    my $height = 1;

    if ( (defined $this->{-vertical}) && ($this->{-vertical}) ) {
        $height = scalar @{$this->{-buttons}};
    } 
    return $height;
}

sub compute_buttonwidth($;)
{
    my $this    = shift;

    $this->process_buttondefs;

    my $width=0;

    if ( (defined $this->{-vertical}) && ($this->{-vertical}) ) {
        foreach my $button (@{$this->{-buttons}}) {
            if ($width < length($button->{-label})) {

lib/Curses/UI/Buttonbox.pm  view on Meta::CPAN

        $width = @{$this->{-buttons}} - 1;
        
        # Buttons
        foreach my $button (@{$this->{-buttons}}) {
            $width += length($button->{-label});
        }
    }
    return $width;
}

sub shortcut()
{
    my $this = shift;
    my $key = uc shift;
    
    # Walk through shortcuts to see if the pressed key
    # is in the list of -shortcuts.
    my $idx = 0;
    my $found_idx;
    SHORTCUT: foreach my $button (@{$this->{-buttons}})
    {

lib/Curses/UI/Calendar.pm  view on Meta::CPAN

	    'mouse-button', BUTTON1_CLICKED(), BUTTON3_CLICKED());
    }

    return $this;
}

# ----------------------------------------------------------------------
# Methods
# ----------------------------------------------------------------------

sub onChange(;$) { shift()->set_event('-onchange', shift()) }
sub day($;)      { shift()->accessor('-day',       shift()) }
sub month($;)    { shift()->accessor('-month',     shift()) }
sub year($;)     { shift()->accessor('-year',      shift()) }


sub layout()
{
    my $this = shift;
    $this->SUPER::layout() or return;    
    return $this;
}

sub setdate($;$)
{
    my $this = shift;
    my $date = shift;
    my $nodraw = shift || 0;

    if (not defined $date)
    {
        $this->{-year}  = undef;
        $this->{-month} = undef;
        $this->{-day}   = undef;

lib/Curses/UI/Calendar.pm  view on Meta::CPAN

        $this->{-month} = $2;
        $this->{-day}   = $3;
    }

    $this->make_sane_date;
    $this->intellidraw unless $nodraw;

    return $this;
}

sub make_sane_date()
{
    my $this = shift;
    my $cursor = shift;
    my $c = $cursor ? 'c' : '';
    
    # Determine 'today'.
    my @now = localtime(); $now[4]++; $now[5]+=1900;

    # Use today's values if undefined.
    $this->{"-${c}day"}   = $now[3] 

lib/Curses/UI/Calendar.pm  view on Meta::CPAN

    # undef value?
    if ($this->{"-${c}year"} == 1752 and $this->{"-${c}month"} == 9) {
        if ($this->{"-${c}day"} > 2 and $this->{"-${c}day"} < 14) {
            $this->{"-${c}day"} = ($this->{"-${c}day"} > 8 ? 14 : 2);
        }
    }

    return $this;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;
    
    # Draw the widget
    $this->SUPER::draw(1) or return $this;
    
    $this->make_sane_date;
    $this->make_sane_date(1);
 

lib/Curses/UI/Calendar.pm  view on Meta::CPAN

    # Move the cursor to the bottomright corner of the widget
    # (in case the terminal does not support widget hiding).
    $this->{-canvasscr}->move($this->canvasheight-1, $this->canvaswidth-1);

    $this->{-canvasscr}->noutrefresh();
    doupdate() unless $no_doupdate;

    return $this;
}

sub date_selected()
{
    my $this = shift;
    $this->{-cyear} = $this->{-year};
    $this->{-cmonth} = $this->{-month};
    $this->{-cday} = $this->{-day};
    $this->schedule_draw(1);
    return $this;
}

sub date_today()
{
    my $this = shift;
    $this->{-cmonth} = undef;
    $this->{-cday}   = undef;
    $this->{-cyear}  = undef;
    $this->schedule_draw(1);
    return $this;
}

sub date_prevyear()
{
    my $this = shift;
    $this->{-cyear}--;
    $this->{-cyear} = 0 if $this->{-cyear} < 0;
    $this->schedule_draw(1);
    return $this;
}

sub date_nextyear()
{
    my $this = shift;
    $this->{-cyear}++;
    $this->{-cyear} = 9999 if $this->{-cyear} > 9999;
    $this->schedule_draw(1);
    return $this;
}

sub date_prevmonth()
{
    my $this = shift;
    $this->{-cmonth}--;
    if ($this->{-cmonth} < 1 and $this->{-cyear} > 0) {
        $this->{-cmonth} = 12;
        $this->{-cyear}--;
    }
    $this->schedule_draw(1);
    return $this;
}

sub date_nextmonth()
{
    my $this = shift;
    $this->{-cmonth}++;
    if ($this->{-cmonth} > 12 and $this->{-cyear} < 9999) {
        $this->{-cmonth} = 1;
        $this->{-cyear}++;
    }
    $this->schedule_draw(1);
    return $this;
}

sub date_delta_days($;)
{
    my $this = shift;
    my $delta = shift;

    if ($delta < 0) 
    {
        my $startday = $this->{-cday};
        $this->{-cday} += $delta;
        if ($this->{-cday} < 1) 
        {

lib/Curses/UI/Calendar.pm  view on Meta::CPAN

    }
    
    if ($this->{-cyear} == 1752 and $this->{-cmonth} == 9) {
        if ($this->{-cday} > 2 and $this->{-cday} < 14) {
            $this->{-cday} = ($delta > 0 ? 14 : 2);
        }
    }
    $this->schedule_draw(1);
}

sub date_prevweek()
{
    my $this = shift;
    $this->date_delta_days(-7);
    $this->schedule_draw(1);
    return $this;
}

sub date_nextweek()
{
    my $this = shift;
    $this->date_delta_days(+7);
    $this->schedule_draw(1);
    return $this;
}

sub date_prevday()
{
    my $this = shift;
    $this->date_delta_days(-1);
    $this->schedule_draw(1);
    return $this;
}

sub date_nextday()
{
    my $this = shift;
    $this->date_delta_days(+1);
    $this->schedule_draw(1);
    return $this;
}

sub date_select()
{
    my $this = shift;    
    $this->{-day}   = $this->{-cday};
    $this->{-month} = $this->{-cmonth};
    $this->{-year}  = $this->{-cyear};
    $this->schedule_draw(1);
    $this->run_event('-onchange');
    return $this;
}

sub mouse_button($$$$;)
{
    my $this  = shift;
    my $event = shift;
    my $x     = shift;
    my $y     = shift;

    # Click in the day area?
    if ($y > 3 and $y < 10) 
    {
	my @month = build_month($this->{-cyear}, $this->{-cmonth});

lib/Curses/UI/Calendar.pm  view on Meta::CPAN

	    $this->date_prevmonth;
	}
	$this->focus();
    }


    
    return $this;
}

sub get()
{
    my $this = shift;
    $this->make_sane_date();
    return sprintf("%04d-%02d-%02d", 
               $this->{-year}, $this->{-month}, $this->{-day});
}

# ----------------------------------------------------------------------
# Date calculation 
# ----------------------------------------------------------------------

my @days_in_month = (undef,31,28,31,30,31,30,31,31,30,31,30,31);

sub is_julian ($$;)
{
    my ($year, $month) = @_;
    return $year < 1752 or ($year == 1752 and $month <= 9);
}

sub day_of_week($$$;)
{
    my $year  = shift;
    my $month = shift;
    my $day   = shift;

    my $a = int( (14 - $month)/12 );
    my $y = $year - $a;
    my $m = $month + (12 * $a) - 2;
    my $day_of_week;
    if (is_julian($year, $month)) 

lib/Curses/UI/Calendar.pm  view on Meta::CPAN

                + $y + int($y/4) 
                - int($y/100) 
                + int($y/400) 
                + int(31*$m/12)
                   ) % 7;
    }

    return $day_of_week;
}

sub days_in_month($$;) 
{
    my $year  = shift;
    my $month = shift;

    if($month == 2 and is_leap_year($year)) {
        return 29;
    } else {
        return $days_in_month[$month];
    }
}

sub is_leap_year($;)
{
    my $year = shift;

    if (is_julian($year,1)) {
        return 1 if $year % 4 == 0;
    } else {
        return 1 if ($year % 4 == 0 and $year % 100 != 0) 
                          or $year % 400 == 0;
    }
    return 0;

lib/Curses/UI/Checkbox.pm  view on Meta::CPAN

=head1 STANDARD METHODS

    layout draw    intellidraw
    focus  onFocus onBlur

See L<Curses::UI::Widget|Curses::UI::Widget> for an explanation of
these.

=cut

sub event_onblur() {
    my $this = shift;
    $this->SUPER::event_onblur;

    $this->{-focus} = 0;
    $this->draw();

    return $this;
}

sub layout() {
    my $this = shift;

    my $label = $this->getobj('label');
    if (defined $label) {
        my $lh = $label->{-height};
        $lh = 1 if $lh <= 0;
        $this->{-height} = $lh;
    }

    $this->SUPER::layout or return;
    return $this;
}

sub draw(;$) {
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw the widget.
    $this->SUPER::draw(1) or return $this;

    # Draw the checkbox.
     if ($Curses::UI::color_support) {
	my $co = $Curses::UI::color_object;
	my $pair = $co->get_color_pair(

lib/Curses/UI/Checkbox.pm  view on Meta::CPAN


=head1 WIDGET-SPECIFIC METHODS

=head2 get

Returns the current state of the checkbox (0 == unchecked, 1 ==
checked).

=cut

sub get() {
    my $this = shift;
    return $this->{-checked};
}

=head2 check

Sets the checkbox to "checked".

=cut

sub check() {
    my $this = shift;
    my $changed = ($this->{-checked} ? 0 : 1);
    $this->{-checked} = 1;
    if ($changed) {
        $this->run_event('-onchange');
        $this->schedule_draw(1);
    }
    return $this;
}

=head2 uncheck

Sets the checkbox to "unchecked".

=cut

sub uncheck() {
    my $this = shift;
    my $changed = ($this->{-checked} ? 1 : 0);
    $this->{-checked} = 0;
    if ($changed) {
        $this->run_event('-onchange');
        $this->schedule_draw(1);
    }
    return $this;
}

=head2 toggle

Flip-flops the checkbox to its "other" state. If the checkbox is
unchecked then it will become checked, and vice versa.

=cut

sub toggle() {
    my $this = shift;
    $this->{-checked} = ($this->{-checked} ? 0 : 1);
    $this->run_event('-onchange');
    $this->schedule_draw(1);
}

=head2 onChange

This method can be used to set the C<-onchange> event handler (see
above) after initialization of the checkbox. It expects a coderef as
its argument.

=cut

sub onChange(;$)  { shift()->set_event('-onchange',  shift()) }

sub mouse_button1($$$$;) {
    my $this  = shift;
    my $event = shift;
    my $x     = shift;
    my $y     = shift;

    $this->focus();
    $this->toggle();

    return $this;
}

lib/Curses/UI/Common.pm  view on Meta::CPAN

    split_to_lines
    text_dimension
    CUI_ESCAPE       CUI_SPACE      CUI_TAB
    WORDWRAP         NO_WORDWRAP
);

# ----------------------------------------------------------------------
# Misc. routines
# ----------------------------------------------------------------------

sub parent()
{
    my $this = shift;
    $this->{-parent};
}

sub root()
{
    my $this = shift;
    my $root = $this;
    while (defined $root->{-parent}) {
        $root = $root->{-parent};
    }
    return $root;
}

sub accessor($;$)
{
    my $this  = shift;
    my $key   = shift;
    my $value = shift;

    $this->{$key} = $value if defined $value;
    return $this->{$key};
}

sub keys_to_lowercase($;)
{
    my $hash = shift;

    my $copy = {%$hash};
    while (my ($k,$v) = each %$copy) {
        $hash->{lc $k} = $v;
    }

    return $hash;
}

# ----------------------------------------------------------------------
# Text processing
# ----------------------------------------------------------------------

sub split_to_lines($;)
{
    # Make $this->split_to_lines() possible.
    shift if ref $_[0];
    my $text = shift;

    # Break up the text in lines. IHATEBUGS is
    # because a split with /\n/ on "\n\n\n" would
    # return zero result :-(
    my @lines = split /\n/, $text . "IHATEBUGS";
    $lines[-1] =~ s/IHATEBUGS$//g;
    
    return \@lines;
}

sub scrlength($;)
{
    # Make $this->scrlength() possible.
    shift if ref $_[0];
    my $line = shift;

    return 0 unless defined $line; 

    my $scrlength = 0;
    for (my $i=0; $i < length($line); $i++)    
    {

lib/Curses/UI/Common.pm  view on Meta::CPAN

        if ($chr eq "\t") {
            while ($scrlength%8) {
                $scrlength++;
            }
        }
    }
    return $scrlength;    
}

# Contstants for text_wrap()
sub NO_WORDWRAP() { 1 }
sub WORDWRAP()    { 0 }

sub text_wrap($$;)
{
    # Make $this->text_wrap() possible.
    shift if ref $_[0];
    my ($line, $maxlen, $wordwrap) = @_;
    $wordwrap = WORDWRAP unless defined $wordwrap;
    $maxlen = int $maxlen;
    
    return [""] if $line eq '';

    my @wrapped = ();

lib/Curses/UI/Common.pm  view on Meta::CPAN

            $text = $';
        }
        else {
            push(@tokens, $text);
            last;
        }
    }
    return @tokens;
}

sub text_draw($$;)
{
    my $this = shift;
    my ($y, $x, $text) = @_;

    if ($this->{-htmltext}) {
        my @tokens = &text_tokenize($text);
        foreach my $token (@tokens) {
            if ($token =~ m/^<(standout|reverse|bold|underline|blink|dim)>$/s) {
                my $type = $1;
                if    ($type eq 'standout')  { $this->{-canvasscr}->attron(A_STANDOUT);  }

lib/Curses/UI/Common.pm  view on Meta::CPAN

    return ($width, $height);
}

# ----------------------------------------------------------------------
# Keyboard input
# ----------------------------------------------------------------------

# Constants:

# Keys that are not defined in curses.h, but which might come in handy.
sub CUI_ESCAPE()       { "\x1b" }
sub CUI_TAB()          { "\t"   }
sub CUI_SPACE()        { " "    }

# Make ascii representation of a key.
sub key_to_ascii($;)
{
    my $this = shift;
    my $key  = shift;

    if ($key eq CUI_ESCAPE()) {
	$key = '<Esc>';
    }
    # Control characters. Change them into something printable
    # via Curses' unctrl function.
    elsif ($key lt ' ' and $key ne "\n" and $key ne "\t") {

lib/Curses/UI/Common.pm  view on Meta::CPAN


    return $key;
}

# For the select() syscall in char_read().
my $rin = '';
my $fno = fileno(STDIN);
$fno = 0 unless $fno >= 0;
vec($rin, $fno ,  1) = 1;

sub char_read(;$)
{
    my $this = shift;
    my $blocktime = shift;

    # Initialize the toplevel window for 
    # reading a key.
    my $s = $this->root->{-canvasscr};
    noecho();
    raw();
    $s->keypad(1);

lib/Curses/UI/Common.pm  view on Meta::CPAN

    if ($found < 0 ) {
	print STDERR "DEBUG: get_key() -> select() -> $!\n"
	    if $Curses::UI::debug; 
    } elsif ($found) {
	$key = $s->getch();
    }

    return $key;
}

sub get_key(;$)
{
    my $this            = shift;
    my $blocktime       = shift || 0;

    my $key = $this->char_read($blocktime);

    # ------------------------------------ #
    #  Hacks for broken termcaps / curses  #
    # ------------------------------------ #

lib/Curses/UI/Container.pm  view on Meta::CPAN

@ISA = qw(
    Curses::UI::Widget 
    Curses::UI::Common
);

# ----------------------------------------------------------------------
# Public interface
# ----------------------------------------------------------------------

# Create a new Container object.
sub new()
{
    my $class = shift;

    my %userargs = @_;
    keys_to_lowercase(\%userargs);

    my %args = (
        -releasefocus => 0,     # Allows the focus to be released to parent on end

        %userargs,

lib/Curses/UI/Container.pm  view on Meta::CPAN

    my $this = $class->SUPER::new(%args);
}

DESTROY()
{
    my $this = shift;
    $this->SUPER::delete_subwindows();
}

# Add an object to the container
sub add($@)
{
    my $this = shift;
    my $id = shift;
    my $class = shift;
    my %args = @_;
    
    $this->root->fatalerror(
	"The object id \"$id\" is already in use!"
    ) if defined $id and  
         defined $this->{-id2object}->{$id};

lib/Curses/UI/Container.pm  view on Meta::CPAN

    # last focus/draw). This can be overriden by the 
    # set_focusorder() and set_draworder() functions.
    push @{$this->{-focusorder}}, $id;
    unshift @{$this->{-draworder}}, $id;

    # Return the created object.
    return $object;
}

# Delete the contained object with id=$id from the Container.
sub delete(;$)
{
    my $this = shift;
    my $id = shift;

    return $this unless defined $this->{-id2object}->{$id};

    # Delete curses subwindows.
    $this->{-id2object}->{$id}->delete_subwindows(); 
   
    # Destroy object.

lib/Curses/UI/Container.pm  view on Meta::CPAN

            $new_focused_obj = $this->{-id2object}->{$new_focused_id}
                if $new_focused_id;
            $new_focused_obj->event_onfocus
                if $new_focused_obj;
        }
    }

    return $this;
}

sub delete_subwindows()
{
    my $this = shift;
    while (my ($id, $object) = each %{$this->{-id2object}}) {
        $object->delete_subwindows();
    }
    $this->SUPER::delete_subwindows();
    return $this;
}


# Draw the container and it's contained objects.
sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;
    
    # Draw the Widget.
    $this->SUPER::draw(1) or return $this;
    
    # Draw all contained object.
    foreach my $id (@{$this->{-draworder}}) {
        $this->{-id2object}->{$id}->draw(1);
      }

    # Update the screen unless suppressed.
    doupdate() unless $no_doupdate;

    return $this;
}

sub layout()
{
    my $this = shift;
    $this->SUPER::layout() or return;
    $this->layout_contained_objects();
    return $this;    
}

sub layout_contained_objects()
{
    my $this = shift;

    # Layout all contained objects.
    foreach my $id (@{$this->{-draworder}})
    {
        my $obj = $this->{-id2object}->{$id};
        $obj->{-parent} = $this;
        $obj->layout();
	$obj->draw();
    }

    return $this;
}

# Look if there are objects of a certain kind in the container.
sub hasa($;)
{
    my $this = shift;
    my $class = shift;

    my $count = 0;
    while (my ($id,$obj) = each %{$this->{-id2object}}) {
        $count++ if ref $obj eq $class;
    }
    return $count;
}

sub window_is_ontop($;)
{
    my $this = shift;
    my $win = shift;

    # If we have a stack of no windows, return immediately.
    return undef if @{$this->{-draworder}} == 0;

    my $topwin = $this->{-draworder}->[-1];
    if (ref $win) { $topwin = $this->getobj($topwin) }

    return $topwin eq $win;
}

sub event_keypress($;)
{
    my $this = shift;
    my $key = shift;

    # Try to run the event on this widget. Return
    # unless the binding returns 'DELEGATE' which
    # means that this widget should try to delegate
    # the event to its contained object which has
    # the focus.
    # 

lib/Curses/UI/Container.pm  view on Meta::CPAN

    # Get the current focused object and send the 
    # keypress to it.
    $obj = $this->getfocusobj;
    if (defined $obj) {
	return $obj->event_keypress($key);
    } else {    
	return 'DELEGATE';
    }
}

sub focus_prev()
{
    my $this = shift;

    # Return without doing anything if we do not
    # have a focuslist.
    return $this unless @{$this->{-focusorder}};
                
    # Find the current focused object id.
    my $id = $this->{-draworder}->[-1];

lib/Curses/UI/Container.pm  view on Meta::CPAN

	last if (defined $new_obj && $new_obj->focusable);
    }

    # Focus the previous object.    
    $this->focus($this->{-focusorder}->[$idx], undef, -1);
    if ( $circle_flag && $this->{-releasefocus} ) {
        $this->{-parent}->focus_prev;
    }
}

sub focus_next()
{
    my $this = shift;

    # Return without doing anything if we do not
    # have a focuslist.
    return $this unless @{$this->{-focusorder}};
                
    # Find the current focused object id.
    my $id = $this->{-draworder}->[-1];

lib/Curses/UI/Container.pm  view on Meta::CPAN

    }
    
    # Focus the next object.    
    $this->focus($this->{-focusorder}->[$idx], undef, +1);
    #check if we have to release the focus
    if ( $circle_flag && $this->{-releasefocus} ) {
        $this->{-parent}->focus_next;
    }
}

sub focus(;$$$)
{
    my $this      = shift;
    my $focus_to  = shift;
    my $forced    = shift || 0;
    my $direction = shift || 1;

    # The direction in which to look for other objects
    # if this object is not focusable.
    $direction = ($direction < 0 ? -1 : 1);

lib/Curses/UI/Container.pm  view on Meta::CPAN

            unless ($new_obj->{-has_modal_focus}) {
		$cur_obj->event_onblur;
            }
	    $new_obj->event_onfocus;
        }
    }
   
    $this->SUPER::focus();
}

sub event_onfocus()
{
    my $this = shift;

    # Do an onfocus event for this object.
    $this->SUPER::event_onfocus;

    # If there is a focused object within this
    # container and this container is not a 
    # container widget, then send an onfocus event to it.
    unless ($this->isa('Curses::UI::ContainerWidget')) {
        my $focused_object = $this->getfocusobj;
        if (defined $focused_object) {
            $focused_object->event_onfocus;
        }
    }

    return $this;
}

sub event_onblur()
{
    my $this = shift;

    #If the Container loose it focus
    #the current focused child must be unfocused

    #get the id
    my $id = $this->{-draworder}->[-1];
    return unless $id;

lib/Curses/UI/Container.pm  view on Meta::CPAN

    #draw the widget without the focus
    $obj->{-focus} = 0;
    $obj->draw;

    $this->SUPER::event_onblur();

    return $this;
}


sub set_focusorder(@)
{
    my $this = shift;
    my @order = @_;
    $this->{-focusorder} = \@order;
    return $this;
}

sub set_draworder(@)
{
    my $this = shift;
    my @order = @_;
    $this->{-draworder} = \@order;
    return $this;
}

sub getobj($;)
{
    my $this = shift;
    my $id = shift;
    return $this->{-id2object}->{$id};
}

sub getfocusobj()
{
    my $this = shift;
    my $id = $this->{-draworder}->[-1];
    return (defined $id ? $this->getobj($id) : undef); 
}

# ----------------------------------------------------------------------
# Private functions
# ----------------------------------------------------------------------

sub draworder_id2idx($;)   {shift()->base_id2idx('-draworder' , shift())}
sub focusorder_id2idx($;)  {shift()->base_id2idx('-focusorder', shift())}

sub base_id2idx($;)
{
    my $this = shift;
    my $param = shift;
    my $id = shift;
    
    my $idx;
    my $i = 0;
    foreach my $win_id (@{$this->{$param}}) 
    {
        if ($win_id eq $id) { 

lib/Curses/UI/Dialog/Basic.pm  view on Meta::CPAN

    $Curses::UI::screen_too_small = $remember;
    $this->layout;

    # Set the initial focus to the buttons.
    $b->focus;
    
    return bless $this, $class;
}

# TODO delete_curses_windows
sub layout()
{
    my $this = shift;
    return $this if $Curses::UI::screen_too_small;

    # The maximum available space on the screen.
    my $avail_width = $ENV{COLS};
    my $avail_height = $ENV{LINES};

    # Compute the maximum available space for the message.

lib/Curses/UI/Dialog/Basic.pm  view on Meta::CPAN

    $h += $this->{-ipadtop} + $this->{-ipadbottom}; 

    $this->{-width} = $w;
    $this->{-height} = $h;

    $this->SUPER::layout;
    
    return $this;
}

sub get()
{
    my $this = shift;
    $this->getobj('buttons')->get;
}

1;


=pod

lib/Curses/UI/Dialog/Calendar.pm  view on Meta::CPAN

        my $this = shift;
	$this->{-selected_date} = undef;
	$this->loose_focus;
    }, CUI_ESCAPE());

    $this->layout();

    return bless $this, $class;
}

sub layout()
{
    my $this = shift;

        my $cal = $this->getobj('calendar');
        if ($cal) {
        $this->{-width} = width_by_windowscrwidth(
                    $this->getobj('calendar')->{-width}, %$this);
        $this->{-height} = height_by_windowscrheight(
                    $this->getobj('calendar')->{-height}, %$this);
    }

    $this->SUPER::layout() or return;

    return $this;
}

sub get()
{
    my $this = shift;
    return $this->{-selected_date};
}

sub press_button_callback()
{
    my $buttons = shift;
    my $this = $buttons->parent;

    my $ok_pressed = $buttons->get;
    if ($ok_pressed)
    {
        $this->{-selected_date} = $this->getobj('calendar')->get;
    } else {
        $this->{-selected_date} = undef;

lib/Curses/UI/Dialog/Dirbrowser.pm  view on Meta::CPAN

        $this->getobj('buttons')->{-selected} = 1;
        $this->loose_focus;
    }, CUI_ESCAPE);

    $this->layout();
    $this->get_dir;

    return bless $this, $class;
}

sub layout()
{
    my $this = shift;

    my $w = 50;
    my $h = 18;
    $this->{-width} = $w,
    $this->{-height} = $h,

    $this->SUPER::layout() or return;

    return $this;
}

sub get_dir()
{
    my $this = shift;

    # Get pathvalue, filevalue, dirbrowser and filebrowser objects.
    my $pv = $this->getobj('pathvalue');
    my $db = $this->getobj('dirbrowser');

    my $path = $pv->text;

    # Resolve path.

lib/Curses/UI/Dialog/Dirbrowser.pm  view on Meta::CPAN

    $db->values(\@dirs);
    $db->{-ypos} = $this->{-selected_cache}->{$path};
    $db->{-ypos} = 0 unless defined $db->{-ypos};
    $db->{-selected} = undef;
    $db->layout_content->draw(1);

    return $this;
}

# Set $this->{-path} to the homedirectory of the current user.
sub goto_homedirectory()
{
    my $this = shift;

    my @pw = getpwuid($>);
    if (@pw) {
        if (-d $pw[7]) {
	    $this->{-path} = $pw[7];
        } else {
	    $this->{-path} = '/';
	    $this->root->error("Homedirectory $pw[7] not found");

lib/Curses/UI/Dialog/Dirbrowser.pm  view on Meta::CPAN

        }
    } else {
        $this->{-path} = '/';
        $this->root->error("Can't find a passwd entry for uid $>");
        return;
    }

    return $this;
}

sub select_homedirectory()
{
    my $b = shift; # dir-/filebrowser
    my $this = $b->parent;
    my $pv = $this->getobj('pathvalue');

    $this->goto_homedirectory or return $b;
    $pv->text($this->{-path});
    $this->get_dir;

    return $b;
}

sub dirselect()
{
    my $db = shift; # dirbrowser
    my $this = $db->parent;
    my $pv = $this->getobj('pathvalue');

    # Find the new path.
    my $add = $db->values->[$db->{-ypos}];
    my $savepath = $pv->text;
    $this->{-selected_cache}->{$savepath} = $db->{-ypos};
    $pv->text("/$savepath/$add");

    # Get the selected directory.
    unless ($this->get_dir) {
        $pv->text($savepath);
    }

    return $db;
}

sub maskbox_onchange()
{
    my $maskbox = shift; 
    my $this = $maskbox->parent;
    $this->{-activemask} = $maskbox->get;
    $this->get_dir;
    return $maskbox;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw Window
    $this->SUPER::draw(1) or return $this;

    $this->{-canvasscr}->noutrefresh();
    doupdate() unless $no_doupdate;

    return $this;
}

sub get()
{
    my $this = shift;
    if ($this->getobj('buttons')->get) {
        my $file = $this->getobj('pathvalue')->get;
        $file =~ s|/+|/|g;
        return $file;
    } else {
        return;
    }
}

sub press_button_callback()
{
    my $buttons = shift;
    my $this = $buttons->parent;
    my $file = $this->get;

    my $ok_pressed = $buttons->get;
    if ($ok_pressed and $file =~ m|/$|) {
        my $l = $this->root->lang;
        $this->root->error($l->get('file_err_nofileselected'));
        return;

lib/Curses/UI/Dialog/Error.pm  view on Meta::CPAN

    my $this = $class->SUPER::new(%args);

    unless (defined $this->{-title}) {
	my $l = $this->root->lang;
	$this->title($l->get('error_title'));
    }

    bless $this, $class;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;
    
    # Draw widget
    $this->SUPER::draw(1) or return $this;

    # Draw sign
    $this->{-borderscr}->addstr(2, 1, "    _"); 
    $this->{-borderscr}->addstr(3, 1, "   / \\"); 

lib/Curses/UI/Dialog/Filebrowser.pm  view on Meta::CPAN


    if ($this->{-editfilename}) {
        $this->getobj('filevalue')->focus;
    } else {
        $this->getobj('filebrowser')->focus;
    }

    return bless $this, $class;
}

sub layout()
{
    my $this = shift;

    my $w = 60;
    my $h = 18;
    $h += 2 if defined $this->{-mask};
    $this->{-width} = $w,
    $this->{-height} = $h,

    $this->SUPER::layout() or return;

    return $this;
}

sub get_dir()
{
    my $this = shift;

    # Get pathvalue, filevalue, dirbrowser and filebrowser objects.
    my $pv = $this->getobj('pathvalue');
    my $db = $this->getobj('dirbrowser');
    my $fb = $this->getobj('filebrowser');

    my $path = $pv->text;

lib/Curses/UI/Dialog/Filebrowser.pm  view on Meta::CPAN

    $db->layout_content->draw(1);

    $fb->values(\@files);
    $fb->{-ypos} = $fb->{-yscrpos} = 0;
    $fb->layout_content->draw(1);
    
    return $this;
}

# Set $this->{-path} to the homedirectory of the current user.
sub goto_homedirectory()
{
    my $this = shift;

    my @pw = getpwuid($>);    
    if (@pw) {
        if (-d $pw[7]) {
	    $this->{-path} = $pw[7];
        } else {
	    $this->{-path} = '/';
	    $this->root->error("Homedirectory $pw[7] not found");

lib/Curses/UI/Dialog/Filebrowser.pm  view on Meta::CPAN

        }
    } else {
        $this->{-path} = '/';
        $this->root->error("Can't find a passwd entry for uid $>");
        return;
    }

    return $this;
}

sub select_homedirectory()
{
    my $b = shift; # dir-/filebrowser
    my $this = $b->parent;
    my $pv = $this->getobj('pathvalue');

    $this->goto_homedirectory or return $b;
    $pv->text($this->{-path});
    $this->get_dir;

    return $b;
}

sub dirselect()
{
    my $db = shift; # dirbrowser
    my $this = $db->parent;
    my $fv = $this->getobj('filevalue');
    my $pv = $this->getobj('pathvalue');

    # Find the new path.
    my $add = $db->values->[$db->{-ypos}];
    my $savepath = $pv->text;
    $this->{-selected_cache}->{$savepath} = $db->{-ypos};

lib/Curses/UI/Dialog/Filebrowser.pm  view on Meta::CPAN

    $fv->text('') unless $this->{-editfilename};

    # Get the selected directory.
    unless ($this->get_dir) {
        $pv->text($savepath);
    }

    return $db;
}

sub fileselect()
{
    my $filebrowser = shift;
    my $this = $filebrowser->parent;

    my $selected = $filebrowser->{-ypos};
    
    my $file = $filebrowser->values->[$selected];

    if (defined $file) {
	$this->{-file} = $file;
	$this->getobj('filevalue')->text($file);
    } 
# TODO: find out if it is done by mouseclick. If yes, then do 
# not change focus.
# Doubleclick may also select the file.
#    $this->getobj('buttons')->focus;
}

sub maskbox_onchange()
{
    my $maskbox = shift; 
    my $this = $maskbox->parent;
    $this->{-activemask} = $maskbox->get;
    $this->get_dir;
    return $maskbox;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw Window
    $this->SUPER::draw(1) or return $this;

    $this->{-canvasscr}->noutrefresh();
    doupdate() unless $no_doupdate;

    return $this;
}

sub get()
{
    my $this = shift;
    if ($this->getobj('buttons')->get) {
        my $file = $this->getobj('pathvalue')->get
                 . "/" 
                 . $this->getobj('filevalue')->get;
        $file =~ s|/+|/|g;
        return $file;
    } else {
        return;
    }
}

sub press_button_callback()
{
    my $buttons = shift;
    my $this = $buttons->parent;
    my $file = $this->get;

    my $ok_pressed = $buttons->get;
    if ($ok_pressed and $file =~ m|/$|) {
        my $l = $this->root->lang;
        $this->root->error($l->get('file_err_nofileselected'));
        return;

lib/Curses/UI/Dialog/Progress.pm  view on Meta::CPAN

        %pb_args,
        -intellidraw => 0,
    );

    $this->layout();

    bless $this, $class;
}

# There is no need to focus a progress dialog
sub focus() {} ; 

sub layout()
{
    my $this = shift;

    if (not defined $this->{-height} 
        and defined $this->getobj('progressbar'))
    {
        # Space between progressbar and message.
        my $need = ($this->{-nomessage} ? 0 : 1);

        # The height for the message.

lib/Curses/UI/Dialog/Progress.pm  view on Meta::CPAN


        my $height = $this->height_by_windowscrheight($need, %$this);
        $this->{-height} = $height;
    }

    $this->SUPER::layout or return;

    return $this;
}

sub pos($;)
{
    my $this = shift;
    my $pos = shift;
    $this->getobj('progressbar')->pos($pos);
    return $this;
}

sub message()
{
    my $this = shift;
    return $this if $this->{-nomessage};
    my $msg = shift;
    $this->getobj('label')->text($msg);
    return $this;
}

1;

lib/Curses/UI/Dialog/Question.pm  view on Meta::CPAN

    $Curses::UI::screen_too_small = $remember;
    $this->layout;

    # Set the initial focus to the answer box.
    $a->focus;

    return bless $this, $class;
}

# TODO delete_curses_windows
sub layout()
{
    my $this = shift;
    return $this if $Curses::UI::screen_too_small;

    # The maximum available space on the screen.
    my $avail_width = $ENV{COLS};
    my $avail_height = $ENV{LINES};

    # Compute the maximum available space for the message.

lib/Curses/UI/Dialog/Question.pm  view on Meta::CPAN

    $h += $this->{-ipadtop} + $this->{-ipadbottom};

    $this->{-width} = $w;
    $this->{-height} = $h;

    $this->SUPER::layout;

    return $this;
}

sub get()
{
    my $this = shift;
    return undef if $this->{-cancelled};
    $this->getobj('answer')->get;
}

1;



lib/Curses/UI/Dialog/Status.pm  view on Meta::CPAN

        -fg    => $this->{-fg},
        -bg    => $this->{-bg},
    );

    $this->layout();

    bless $this, $class;
}

# There is no need to focus a status dialog
sub focus() {} ;

sub layout()
{
    my $this = shift;

    my $label = $this->getobj('label');

    # The label might not be added at this point.
    if (defined $label)
    {
        # Compute the width the dialog window needs.
        if (not defined $this->{-width})

lib/Curses/UI/Dialog/Status.pm  view on Meta::CPAN

            );
        }

    }

    $this->SUPER::layout or return;

    return $this;
}
    
sub message($;)
{
    my $this = shift;
    my $message = shift;
    $message = 'no message' unless defined $message;
    $this->getobj('label')->text($message);
    return $this;
}

1;

lib/Curses/UI/Label.pm  view on Meta::CPAN

    $args{-text} = '' unless defined $args{-text};

    # Create the widget.
    my $this = $class->SUPER::new( %args );

    $this->layout();

    return $this;
}

sub layout()
{
    my $this = shift;
    $this->SUPER::layout or return;
    return $this;
}


sub bold ($;$)      { shift()->set_attribute('-bold', shift())      }
sub reverse ($;$)   { shift()->set_attribute('-reverse', shift())   }
sub underline ($;$) { shift()->set_attribute('-underline', shift()) }
sub dim ($;$)       { shift()->set_attribute('-dim', shift())       }
sub blink ($;$)     { shift()->set_attribute('-blink', shift())     }

sub set_attribute($$;)
{
    my $this = shift;
    my $attribute = shift;
    my $value = shift || 0;

    $this->{$attribute} = $value;
    $this->intellidraw;

    return $this;
}



sub text($;$)
{
    my $this = shift;
    my $text = shift;

    if (defined $text) 
    {
        $this->{-text} = $text;
        $this->intellidraw;
        return $this;
    } else {
        return $this->{-text};
    }
}

sub get() { shift()->text }

sub textalignment($;)
{
    my $this = shift;
    my $value = shift;
    $this->{-textalignment} = $value;
    $this->intellidraw;
    return $this;
}

sub compute_xpos()
{
    my $this = shift;
    my $line = shift;

    # Compute the x location of the text.
    my $xpos = 0;
    if (defined $this->{-textalignment})
    {
        if ($this->{-textalignment} eq 'right') {
	    $xpos = $this->canvaswidth - length($line);
        } elsif ($this->{-textalignment} eq 'middle') {
	    $xpos = int (($this->canvaswidth-length($line))/2);
        }
    }
    $xpos = 0 if $xpos < 0;
    return $xpos;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw the widget.
    $this->SUPER::draw(1) or return $this;

    # Clear all attributes.
    $this->{-canvasscr}->attroff(A_REVERSE);
    $this->{-canvasscr}->attroff(A_BOLD);

lib/Curses/UI/Language.pm  view on Meta::CPAN

    'no'        => 'norwegian',

    'es'        => 'spanish',

    'tr'        => 'tukish',

    'cn'        => 'chinese',

);

sub new()
{
    my $class = shift;
    my $lang  = shift; 

    my $this = {
	-tags => {},
	-lang => undef,
    };
    bless $this, $class;

    # Load english tags so these can be used
    # as a fallback for other languages.
    $this->loadlanguage('english');

    # Load the wanted language.
    $this->loadlanguage($lang);

    return $this;
}

sub loadlanguage($;)
{
    my $this = shift;
    my $lang = shift;

    # Construct the language module to use.
    $lang = $default_lang unless defined $lang;
    $lang =~ s/[^\w\_]//g;
    $lang = lc $lang;
    $lang = $lang_alias{$lang} if defined $lang_alias{$lang};

lib/Curses/UI/Language.pm  view on Meta::CPAN

	}
	elsif (!m/^\s*$/) {
	    warn "$l_file, line $.: found data outside tag block\n";
	}
    }
    $this->store($tag, $block);

    close(LANG_DATA);
}

sub store($$;)
{
    my $this  = shift;
    my $tag   = shift;
    my $block = shift;

    return $this unless defined $tag;

    # Remove empty start- and endlines.
    my @block = split /\n/, $block;
    while (@block and $block[0]  =~ /^\s*$/) { shift @block }
    while (@block and $block[-1] =~ /^\s*$/) { pop @block   }

    $this->{-tags}->{lc $tag} = join "\n", @block;

    return $this;
}


sub get($;)
{
    my $this  = shift;
    my $tag   = shift;

    my $block = $this->{-tags}->{$tag};
    unless (defined $block) {
        warn "get(): no language block for tag '$tag'";
	$block = '';
    }

    return $block;
}

sub getarray($;)
{
    my $this = shift;
    my $tag  = shift;

    my $block = $this->get($tag); 
    return () unless defined $block;

    $block =~ s/\n/ /g;
    return split " ", $block;
}

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

    $this->layout_content();

    if ($Curses::UI::ncurses_mouse) {
        $this->set_mouse_binding('mouse-button1', BUTTON1_CLICKED());
        $this->set_mouse_binding('mouse-button1', BUTTON1_DOUBLE_CLICKED());
    }

    return $this;
}

sub onChange(;$) { shift()->set_event('-onchange', shift()) }

sub onSelectionChange(;$) { shift()->set_event('-onselchange', shift()) };

sub values(;$)
{
    my $this = shift;
    my $values = shift;

    if (defined $values && ! ref $values) {
	$values = [ $values, @_ ];
    }
 
    if (defined $values and ref $values eq 'ARRAY') {
	# Clear and go to first item if we get new data

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

	$this->option_first() if defined $values;

        # Make this widget non-focusable if there are
        # no values in it.
        $this->focusable(scalar(@{$values}));
    }

    return $this->{-values}
}

sub insert_at()
{
    
    my $this = shift;
    my $pos = shift;
    my $values = shift;

    # Clear and go to first item if we get new data
    $this->clear_selection();

    if (defined $values ) {

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

			   @{$this->{-values}});

	    $this->{-values} = \@newdata;
	}
    }

    return $this->{-values};

}

sub labels(;$)
{
    my $this = shift;
    my $labels = shift;

    if (defined $labels and ref $labels eq 'HASH') {
        $this->{-labels} = $labels;
    }
    return $this->{-labels}
}


sub add_labels(;$)
{
    my $this = shift;
    my $labels = shift;

    if (defined $labels and ref $labels eq 'HASH') {
        map $this->{-labels}->{$_} = $labels->{$_}, keys %{$labels};
    }
    return $this->{-labels}
}


sub maxlabelwidth(@)
{
    my %args = @_;
    
    my $maxwidth = 0;
    foreach my $value (@{$args{-values}})
    {
        my $label = $value;
        $label = $args{-labels}->{$value}
            if defined $args{-labels}->{$value};
        $maxwidth = length($label) 
            if length($label) > $maxwidth;
    }
    return $maxwidth;
}

sub layout()
{
    my $this = shift;
    $this->SUPER::layout() or return;
    
    $this->layout_content;

    # Scroll up if we can and the number of visible lines
    # is smaller than the number of available lines in the screen.
    my $inscreen = ($this->canvasheight
		 - ($this->number_of_lines - $this->{-yscrpos}));
    while ($this->{-yscrpos} > 0 and $inscreen < $this->canvasheight)
    {
	    $this->{-yscrpos}--;
	    $inscreen = ($this->canvasheight
		      - ($this->number_of_lines - $this->{-yscrpos}));
    }

    return $this;
}

sub layout_content()
{
    my $this = shift;
    return $this if $Curses::UI::screen_too_small;

    # Check bounds for -ypos index.
    $this->{-max_selected} = @{$this->{-values}} - 1;
    $this->{-ypos} = $this->{-max_selected}
        if $this->{-ypos} > $this->{-max_selected};
    $this->{-ypos} = 0 if $this->{-ypos} < 0;

lib/Curses/UI/Listbox.pm  view on Meta::CPAN


    $this->{-vscrolllen} = @{$this->{-values}};
    $this->{-vscrollpos} = $this->{-yscrpos};
    if ( @{$this->{-values}} <= $this->canvasheight) {
        undef $this->{-vscrolllen};
    }

    return $this;
}

sub getlabel($;)
{
    my $this = shift;
    my $idx = shift || 0;

    my $value = $this->{-values}->[$idx];
    my $label = $value;
    $label = $this->{-labels}->{$label} 
        if defined $this->{-labels}->{$label};
    $label =~ s/\t/ /g; # do not show TABs
    
    return $label;
}


sub get_active_value($;)
{
    my $this = shift;
    my $id = $this->{-ypos};
    my $value = $this->{'-values'}->[$id];    
    return $value;
}

sub get_active_id($;)
{
    my $this = shift;
    return $this->{-ypos};;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw the widget
    $this->SUPER::draw(1) or return $this;

    $this->layout_content;

     # Let there be color

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

        $cursor_x = 1 if $this->{-multi} or $this->{-radio};
        $this->{-canvasscr}->move($cursor_y, $cursor_x);
    }

    $this->{-canvasscr}->noutrefresh();
    doupdate() unless $no_doupdate;

    return $this;
}

sub option_last()
{
    my $this = shift;
    $this->{-ypos} = $this->{-max_selected};
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub option_nextpage()
{
    my $this = shift;
    if ($this->{-ypos} >= $this->{-max_selected}) { 
        $this->dobeep;
        return $this;
    }
    if ($this->{-ypos} + $this->canvasheight - 1 >= $this->{-max_selected}) { 
    	$this->{-ypos} = $this->{-max_selected};
		} else {
    	$this->{-ypos} += $this->canvasheight - 1;
		}
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub option_prevpage()
{
    my $this = shift;
    if ($this->{-ypos} <= 0) {
        $this->dobeep;
        return $this;
    }
    if ($this->{-ypos} - $this->canvasheight - 1 < 0) {
    	$this->{-ypos} = 0;
		} else {
    	$this->{-ypos} -= $this->canvasheight - 1;
		}
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub clear_selection()
{
    my $this = shift;
    if ($this->{-multi}) {
	my $selection = $this->{-selected};
	return unless defined $selection;
	foreach my $id (keys %$selection) {
	    $selection->{$id} = 0;
	}
    } else {
	$this->{-selected} = undef;
    }
    $this->schedule_draw(1);
}

sub set_selection() 
{
    my $this = shift;
    my $id;

    foreach $id (@_) {
	next if $id > @{$this->{-values}};
	if ($this->{-multi})
	{
	    my $changed = ($this->{-selected}->{$id} ? 0 : 1);
	    $this->{-selected}->{$id} = 1;

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

	    my $changed = (not defined $this->{-selected} or
			   ($this->{-selected} != $id));
	    $this->{-selected} = $id;
	    $this->run_event('-onchange') if $changed;
	    $this->schedule_draw(1);
	}
    }
    return $this;
}

sub option_next()
{
    my $this = shift;
    if ($this->{-ypos} >= $this->{-max_selected}) { 
        if ($this->{-wraparound}) {
            $this->{-ypos} = 0;
        } else {
            $this->dobeep;
        }
    } else {
        $this->{-ypos}++;
    }
    $this->layout_content;
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub option_prev()
{
    my $this = shift;
    if ($this->{-ypos} <= 0) {
        if ($this->{-wraparound}) {
            $this->{-ypos} = $this->{-max_selected};
        } else {
            $this->dobeep;
        }
    } else {
        $this->{-ypos}--;
    }
    $this->layout_content;
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub option_select()
{
    my $this = shift;

    if ($this->{-multi})
    {
        $this->{-selected}->{$this->{-ypos}} = 
           !$this->{-selected}->{$this->{-ypos}};
        $this->run_event('-onselchange');
        $this->run_event('-onchange');
        $this->schedule_draw(1);

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

        my $changed = (not defined $this->{-selected} or
                       ($this->{-selected} != $this->{-ypos}));
        $this->{-selected} = $this->{-ypos};
        $this->run_event('-onselchange')if $changed; 
        $this->run_event('-onchange') if $changed;
        $this->schedule_draw(1);
        return ($this->{-radio} ? $this : 'LOOSE_FOCUS');
    }
}

sub option_first()
{
    my $this = shift;
    $this->{-ypos} = 0;
    $this->run_event('-onselchange');
    $this->schedule_draw(1);
    return $this;
}

sub option_check()
{
    my $this = shift;

    if ($this->{-multi})
    {
        my $changed = ($this->{-selected}->{$this->{-ypos}} ? 0 : 1);
        $this->{-selected}->{$this->{-ypos}} = 1;
        $this->{-ypos}++;
        $this->run_event('-onchange') if $changed;
        $this->schedule_draw(1);

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

    } else {
        my $changed = (not defined $this->{-selected} or
                       ($this->{-selected} != $this->{-ypos}));
        $this->{-selected} = $this->{-ypos};
        $this->run_event('-onchange') if $changed;
        $this->schedule_draw(1);
        return ($this->{-radio} ? $this : undef);
    }
}

sub option_uncheck()
{
    my $this = shift;
    if ($this->{-multi})
    {
        my $changed = ($this->{-selected}->{$this->{-ypos}} ? 1 : 0);
        $this->{-selected}->{$this->{-ypos}} = 0;
        $this->run_event('-onchange') if $changed;
        $this->{-ypos}++;
    } else {
        $this->dobeep;
    }
    $this->schedule_draw(1);
    return $this;
}

sub mouse_button1($$$;)
{
    my $this  = shift;
    my $event = shift;
    my $x     = shift;
    my $y     = shift;

    return unless $this->{-focusable};

    $this->layout_content;

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

    my $newypos = $this->{-yscrpos} + $y;
    if (@{$this->{-values}} and
	$newypos >= 0 and $newypos < @{$this->{-values}}) {
	$this->{-ypos} = $newypos;
	$this->do_routine('option-select');
    }

    $this->schedule_draw(1);
}

sub get()
{
    my $this = shift;
    return unless defined $this->{-selected};
    if ($this->{-multi}) {
        my @values = ();
        while (my ($id, $val) = each %{$this->{-selected}}) {
            next unless $val;
            push @values, $this->{-values}->[$id];
        }
        return @values;
    } else {
        return $this->{-values}->[$this->{-selected}];
    }
}

sub id()
{
    my $this = shift;
    return unless defined $this->{-selected};
    if ($this->{-multi}) {
        my @values = ();
        while (my ($id, $val) = each %{$this->{-selected}}) {
            next unless $val;
            push @values, $id;
        }
        return @values;
    } else {
        return $this->{-selected};
    }
}

sub get_selectedlabel()
{
    my $this = shift;
    my $value = $this->get;
    return unless defined $value;
    my $label = $this->{-labels}->{$value};
    return (defined $label ? $label : $value); 
}

sub set_color_fg {
    my $this = shift;

lib/Curses/UI/Listbox.pm  view on Meta::CPAN

    my $this = shift;
    $this->{-bg} = shift;
    $this->intellidraw;
}


# ----------------------------------------------------------------------
# Routines for search support
# ----------------------------------------------------------------------

sub number_of_lines()   { @{shift()->{-values}} }
sub getline_at_ypos($;) { shift()->getlabel(shift()) }

1;


=pod

=head1 NAME

Curses::UI::Listbox - Create and manipulate listbox widgets

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

);

$VERSION = '1.10';

@ISA = qw(
    Curses::UI::Listbox 
    Curses::UI::Common 
    Curses::UI::Window
);

sub new()
{
    my $class = shift;

    my %userargs = @_;
    keys_to_lowercase(\%userargs);

    my %args = (
	-menu          => {},     # The menu contents
        -is_topmenu    => 0,      # First pulldown or not?
        -menubar       => undef,  # Ref to menubar object

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

    $this->set_binding('cursor-right', KEY_RIGHT(), 'l'); 
    
    if ($Curses::UI::ncurses_mouse) {
	$this->set_mouse_binding(\&mouse_button1, BUTTON1_CLICKED());
    }
    

    return $this;
}

sub escape_key()
{
    my $this = shift;
    $this->{-prevobject}->{-returnaction} = 'COLLAPSE';
    $this->loose_focus;
}

sub active_item()
{
    my $this = shift;
    $this->{-menu}->[$this->{-ypos}];
}

sub cursor_left()
{
    my $this = shift;
    $this->{-prevobject}->{-returnaction} = 'CURSOR_LEFT';
    $this->loose_focus;
}

sub cursor_right()
{
    my $this = shift;

    # Get the current menu-item.
    my $item = $this->active_item;

    # This item has a submenu. Open it.
    if (defined $item->{-submenu}) 
    {
                

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

    # This item has no submenu. Return CURSOR_RIGHT
    # if this is a topmenu.
    } elsif ($this->{-is_topmenu}) {
        $this->{-prevobject}->{-returnaction} = 'CURSOR_RIGHT';
        $this->loose_focus;
    }

    return $this;
}

sub option_select()
{
    my $this = shift;
    
    # Get the current menu-item.
    my $item = $this->active_item;

    # Submenu selected? Then expand it.
    if (defined $item->{-submenu}) { 
        return $this->cursor_right;
    } 

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

    my $value = $item->{-value};
    $this->{-menubar}->menuoption_selected($value);

    # Let the complete menulistbox-hierarchy collapse.
    $this->{-prevobject}->{-returnaction} = 'COLLAPSE';
    $this->loose_focus;
    
    return $this;
}

sub mouse_button1()
{
    my $this = shift;
    my $event = shift;
    my $x = shift;
    my $y = shift;

    # First check if the click is inside the widget (since
    # this widget has modal focus, all events go to it).
    my $ev_x = $event->{-x};
    my $ev_y = $event->{-y};

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

    my $this = $class->SUPER::new( %args );
    $this->layout;

    if ($Curses::UI::ncurses_mouse) {
	$this->set_mouse_binding('mouse-button1', BUTTON1_CLICKED());
    }

    return $this;
}

sub escape()
{
    my $this = shift;
    $this->loose_focus;
}

sub layout()
{
    my $this = shift;
    $this->SUPER::layout or return;
    return $this;
} 

sub draw()
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    $this->SUPER::draw(1) or return $this;

    # Create full reverse menubar.
    $this->{-canvasscr}->attron(A_REVERSE);

    # Let there be color

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

    doupdate() unless $no_doupdate;
    return $this;
}

# This calls the default event_onfocus() routine of
# the Widget class and it resets the -menuoption
# data member if the menu is not expanded (this will 
# contain the chosen menuoption at the time the 
# menubar loses focus).
#
sub event_onfocus()
{
    my $this = shift;
    unless ($this->{-is_expanded})
    {
	$this->{-menuoption} = undef;
	$this->{-selected}   = 0;
    }
    $this->SUPER::event_onfocus;
}

sub loose_focus()
{
    my $this = shift;

    # Draw the menubar like it does not have the focus anymore.
    $this->{-focus} = 0;
    $this->draw;

    # Execute callback routine if a menuitem was selected.
    my $value = $this->{-menuoption};
    if (defined $value)

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

    }

}

# This calls the default event_onblur() routine of the
# Widget class, but if -is_expanded is set, the widget
# will still render as a focused widget (this is to
# let the selected menuoption show focused, even if
# the focus is set to a menulistbox).
#
sub event_onblur()
{
    my $this = shift;
    $this->SUPER::event_onblur;

    if ($this->{-is_expanded}) {
        $this->{-focus} = 1;
    }

    return $this;
}

sub menuoption_selected()
{
    my $this = shift;
    my $value = shift;

    $this->{-menuoption} = $value;
}


sub pulldown() 
{
    my $this = shift;

    # Find the x position of the selected menu.
    my $x = 1;
    my $y = 1;
    
    # am I in a window
    if ($this->{-parent}->{-x}) {
	$x += $this->{-parent}->{-x};

lib/Curses/UI/Menubar.pm  view on Meta::CPAN

            $this->menu_right;
            $this->focus;
            $this->draw;
            $this->root->feedkey(KEY_DOWN());
        }
    }

    return $return;
}

sub menu_left()
{
    my $this = shift;
    $this->{-selected}--;
    $this->{-selected} = @{$this->{-menu}}-1 
        if $this->{-selected} < 0;
    $this->schedule_draw(1);    
    return $this;
}

sub menu_right()
{
    my $this = shift;
    $this->{-selected}++;
    $this->{-selected} = 0
        if $this->{-selected} > (@{$this->{-menu}}-1);
    $this->schedule_draw(1);    
    return $this;
}

sub mouse_button1

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

    "\cA"               => 'goto_first_page',
    KEY_END()           => 'goto_last_page',
    "\cE"               => 'goto_last_page',
    KEY_NPAGE()         => 'goto_next_page',
    "\cN"               => 'goto_next_page',
    KEY_PPAGE()         => 'goto_prev_page',
    "\cP"               => 'goto_prev_page',
);


sub debug_msg(;$) {
    return unless ($Curses::UI::debug);

    my $caller = (caller(1))[3];
    my $msg = shift || '';
    my $indent = ($msg =~ /^(\s+)/ ? $1 : '');
    $msg =~ s/\n/\nDEBUG: $indent/mg;

    warn 'DEBUG: ' . 
        ($msg ?
            "$msg in $caller" : 
            "$caller() called by " . ((caller(2))[3] || 'main')
        ) .
        "().\n";
}


sub new($;) {
    debug_msg;
    my $class = shift;

    my %userargs = @_;
    keys_to_lowercase(\%userargs);
    # nb: support only arguments listed in @valid_args;
    my @valid_args = (
        'x', 'y', 'width', 'height',
        'pad', 'padleft', 'padright', 'padtop', 'padbottom',
        'ipad', 'ipadleft', 'ipadright', 'ipadtop', 'ipadbottom',

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

    my $this = $class->SUPER::new(%args);
    if ($Curses::UI::ncurses_mouse) {
        $this->set_mouse_binding(\&mouse_button1, BUTTON1_CLICKED());
    }
    @{$this->{-pages}} = ();            # names of pages stored as an array.

    return $this;
}


sub layout($) {
    debug_msg;
    my $this = shift;

    # Don't wast time if we know the screen is too small.
    return if ($Curses::UI::screen_too_small);

    # Origin defaults to (0,0) relative to parent.
    #
    # nb: if origin is negative, treat it as an end-point and
    #     as relative to parent's end-point.

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

    unless (defined $this->{-borderscr}) {
        $this->{-bh} = $this->{-sh};
        $this->{-bw} = $this->{-sw};
        $this->{-by} = $this->{-sy};
        $this->{-bx} = $this->{-sx};
    }
    return $this;
}


sub draw($;$) {
    debug_msg;
    my $this = shift;
    my $no_doupdate = shift || 0;
    debug_msg "  \$no_doupdate = $no_doupdate";

    # Return immediately if this object is hidden or if
    # the screen is currently too small.
    return if $this->hidden;
    return if $Curses::UI::screen_too_small;

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

    # Draw active window.
    $this->getobj($active_page)->draw($no_doupdate);

    doupdate unless ($no_doupdate);
    return $this;
}


# NB: we can't simply inherit intellidraw from Curses::UI::Widget 
#     since notebooks themselves contain window objects.
sub intellidraw(;$) {
    debug_msg;
    my $this = shift;

    if ($this->{-intellidraw} and !$this->hidden) {
        # Check if parent window has modal focus or is on top of focus path.
        my $parent = $this->parentwindow;
        debug_msg "  parent window = " . $parent;

        my @path = $this->root->focus_path;
        debug_msg "  focus_path " . join(" & ", @path);

lib/Curses/UI/Notebook.pm  view on Meta::CPAN


        $this->draw if (
            $parent->{-has_modal_focus} or 
            (@path and $parent eq $path[-1])
        );
    }
    return $this;
}


sub add_page($$;) {
    debug_msg;
    my $this = shift;
    my $page = shift or return;
    debug_msg "  adding '$page' page";

    # Make sure page is not yet part of the notebook.
    $this->root->fatalerror("The notebook already has a page named '$page'!")
        if (defined $this->{-id2object}->{$page});

    # Make sure the page does not cause the 'tabs' window to overflow.

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

        # we need to adjust them manually.
        my $active_page = $this->active_page;
        $this->set_draworder($active_page);
        $this->set_focusorder($active_page);
    }

    return $this->getobj($page);
}


sub delete_page($$) {
    debug_msg;
    my $this = shift;
    my $page = shift or return;

    # Make sure page is part of the notebook.
    $this->root->fatalerror("The notebook widget does not have a page named '$page'!")
        unless (defined $this->{-id2object}->{$page});

    debug_msg "  deleting '$page' page";

lib/Curses/UI/Notebook.pm  view on Meta::CPAN


    my $active_page = $this->active_page;
    @{$this->{-pages}} = grep($page ne $_, @{$this->{-pages}});
    $this->activate_page($this->first_page) if ($page eq $active_page);
    $this->SUPER::DESTROY($page);

    return;
}


sub active_page($) {
    debug_msg;
    my $this = shift;
    return unless (@{$this->{-pages}});

    my $page = defined $this->{-active_page} ?
        $this->{-active_page} :
        ($this->{-active_page} = '');
    debug_msg "  active page = '$page'";
    return $page;
}


sub first_page($) {
    debug_msg;
    my $this = shift;
    return unless (@{$this->{-pages}});

    my $page = ${$this->{-pages}}[0];
    debug_msg "  first page = '$page'";
    return $page;
}


sub last_page($) {
    debug_msg;
    my $this = shift;
    return unless (@{$this->{-pages}});

    my $page = ${$this->{-pages}}[$#{$this->{-pages}}];
    debug_msg "  last page = '$page'";
    return $page;
}


sub prev_page($) {
    debug_msg;
    my $this = shift;
    return unless (@{$this->{-pages}});

    my $active_page = $this->active_page;
    my $i = scalar(@{$this->{-pages}});
    while (--$i >= 0) {
        last if ($active_page eq ${$this->{-pages}}[$i]);
    }
    return if ($i < 0);

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

        $i-1 :
        $this->{-wraparound} ?
            $#{$this->{-pages}} :
            0;
    my $page = ${$this->{-pages}}[$i];
    debug_msg "  prev page = '$page'";
    return $page;
}


sub next_page($) {
    debug_msg;
    my $this = shift;
    return unless (@{$this->{-pages}});

    my $active_page = $this->active_page;
    my $i = scalar(@{$this->{-pages}});
    while (--$i >= 0) {
        last if ($active_page eq ${$this->{-pages}}[$i]);
    }
    return if ($i < 0);

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

        $i+1 :
        $this->{-wraparound} ?
            0 :
            $#{$this->{-pages}};
    my $page = ${$this->{-pages}}[$i];
    debug_msg "  next page = '$page'";
    return $page;
}


sub activate_page($$) {
    debug_msg;
    my $this = shift;
    my $page = shift or return;

    # Make sure page is part of the notebook.
    $this->root->fatalerror("The notebook widget does not have a page named '$page'!")
        unless (defined $this->{-id2object}->{$page});

    my $active_page = $this->active_page;
    debug_msg "  old active page = '$active_page'";

lib/Curses/UI/Notebook.pm  view on Meta::CPAN

        $this->set_draworder($active_page);
        $this->set_focusorder($active_page);

        # Redraw the notebook widget only if in curses mode.
        $this->intellidraw unless isendwin;
    }
    return $active_page;
}


sub mouse_button1($$$$) {
    debug_msg;
    my $this = shift;
    my $event = shift;
    my $x = shift;
    my $y = shift;

    my $ev_x = $event->{-x};
    my $ev_y = $event->{-y};
    debug_msg "  mouse click at ($ev_x,$ev_y)";

lib/Curses/UI/Popupmenu.pm  view on Meta::CPAN

    @ISA
);

$VERSION = '1.0011';

@ISA = qw(
    Curses::UI::Listbox
    Curses::UI::Window
);

sub new()
{
    my $class = shift;
    my $this = $class->SUPER::new(@_);

    # Do own option_select() method.
    $this->set_routine('option-select', \&option_select);

    return $this;
}

sub option_select()
{
    my $this = shift;
    $this->SUPER::option_select();
    $this->loose_focus;
    return $this;
}

# Let Curses::UI->usemodule() believe that this module
# was already loaded (usemodule() would else try to
# require the non-existing file).

lib/Curses/UI/Popupmenu.pm  view on Meta::CPAN

    $this->layout;

    if ($Curses::UI::ncurses_mouse) {
	$this->set_mouse_binding('mouse-button1', BUTTON1_CLICKED());
    }


    return $this;
}

sub onChange(;$)  { shift()->set_event('-onchange',  shift()) }

sub layout()
{
    my $this = shift;

    $this->SUPER::layout() or return;

    # Compute the location and length of the listbox.
    my $ll = height_by_windowscrheight(@{$this->{-values}}, -border=>1);
    my $lx = $this->{-x} + $this->{-parent}->{-sx};
    my $ly = $this->{-y} + $this->{-parent}->{-sy} + 1;

lib/Curses/UI/Popupmenu.pm  view on Meta::CPAN

        
    # Store the listbox layout setup for later use.
    $this->{-listbox}->{-x}      = $lx;
    $this->{-listbox}->{-y}      = $ly;
    $this->{-listbox}->{-width}  = $this->width;
    $this->{-listbox}->{-height} = $ll;

    return $this;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Draw the widget.
    $this->SUPER::draw(1) or return $this;
        
    # Get the selected label.
    my $sellabel;
    if (defined $this->{-selected})

lib/Curses/UI/Popupmenu.pm  view on Meta::CPAN

    $this->{-canvasscr}->move(0,$this->canvaswidth-1);
    $this->{-canvasscr}->attroff(A_DIM);
    $this->{-canvasscr}->attroff(A_REVERSE);

    $this->{-canvasscr}->noutrefresh;
    doupdate() unless $no_doupdate;;

    return $this;
}

sub open_popup()
{
    my $this = shift;
    my $pre_value = $this->get;

    my %listbox_options = %{$this->{-listbox}};
    foreach my $option (qw(
	-values -labels 
	-selected -wraparound
    )) {    
        $listbox_options{$option} = $this->{$option}

lib/Curses/UI/Popupmenu.pm  view on Meta::CPAN

            $pre_value ne $post_value)) {
        $this->run_event('-onchange');
    }

    $this->root->delete($id);
    $this->root->draw;

    return $this;
}

sub get()
{
    my $this = shift;

    my $value;
    if (defined $this->{-selected}) {
	$value = $this->{-values}->[$this->{-selected}];
    }

    return $value;
}

sub select_next()
{
    my $this = shift;
    
    my $pre_value = $this->get;

    if (defined $this->{-selected}) {
	$this->{-selected}++;
	if ( $this->{-selected} > (@{$this->{-values}}-1) ) {
	    $this->{-selected} = @{$this->{-values}} - 1;
	}

lib/Curses/UI/Popupmenu.pm  view on Meta::CPAN

    if ((not defined $pre_value and defined $post_value) or 
        (defined $pre_value and $pre_value ne $post_value)) {
        $this->run_event('-onchange');
    }

    $this->schedule_draw(1);

    return $this;
}

sub select_prev()
{
    my $this = shift;

    my $pre_value = $this->get;

    if (defined $this->{-selected}) {
        $this->{-selected}--;
	$this->{-selected} = 0 if $this->{-selected} <= 0;
    } else {
        $this->{-selected} = @{$this->{-values}} - 1;

lib/Curses/UI/Popupmenu.pm  view on Meta::CPAN

    if ((not defined $pre_value and defined $post_value) or 
        (defined $pre_value and $pre_value ne $post_value)) {
        $this->run_event('-onchange');
    }

    $this->schedule_draw(1);

    return $this;
}

sub mouse_button1($$$;)
{
    my $this  = shift;
    my $event = shift;
    my $x     = shift;
    my $y     = shift;

    unless ($this->{-focus}) {
        $this->focus;
    }
    $this->open_popup;

lib/Curses/UI/Progressbar.pm  view on Meta::CPAN

        $args{-max} = $tmp;
    }

    my $height = height_by_windowscrheight(1, %args);
    $args{-height} = $height;

    my $this = $class->SUPER::new( %args );    
    return $this;
}

sub get()
{
    my $this = shift;
    return $this->{-pos};
}

sub pos(;$)
{
    my $this = shift;
    my $pos = shift || 0;
    $this->{-pos} = $pos;    
    $this->intellidraw;
    return $this;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;
    
    # Draw the widget
    $this->SUPER::draw(1) or return $this;

    # Check bounds for the position.
    $this->{-pos} = $this->{-max} if $this->{-pos} > $this->{-max};
    $this->{-pos} = $this->{-min} if $this->{-pos} < $this->{-min};

lib/Curses/UI/Searchable.pm  view on Meta::CPAN

    $VERSION 
    @ISA
);

$VERSION = "1.10";

@ISA = qw(
    Curses::UI::ContainerWidget
);

sub new()
{
    my $class = shift;

    my %userargs = @_;
    keys_to_lowercase(\%userargs);

    my %args = (
        -prompt     => '/',    # The initial search prompt

        %userargs,

lib/Curses/UI/Searchable.pm  view on Meta::CPAN

        -intellidraw => 0,
    );

    $entry->set_routine('loose-focus', \&entry_loose_focus);

    $this->layout;

    return $this;
}

sub entry_loose_focus()
{
    my $this = shift;
    $this->parent->loose_focus;
}

sub event_keypress($;)
{
    my $this = shift;
    my $key  = shift;

    my $entry = $this->getobj('entry');
    if ($entry->{-focus}) {
	$this->getobj('entry')->event_keypress($key);
    } else {
	$this->{-key} = $key;
    }

    return $this;
}

sub get()
{
    my $this = shift;
    $this->getobj('entry')->get;
}

sub pos(;$)
{
    my $this = shift;
    my $pos = shift;
    $this->getobj('entry')->pos($pos);
}

sub text(;$)
{
    my $this = shift;
    my $text = shift;
    $this->getobj('entry')->text($text);
}

sub prompt(;$) 
{ 
    my $this = shift;
    my $prompt = shift;
    if (defined $prompt) 
    {
        $prompt = substr($prompt, 0, 1);
        $this->{-prompt} = $prompt;
        $this->getobj('prompt')->text($prompt);
        $this->intellidraw;
        return $this;

lib/Curses/UI/Searchable.pm  view on Meta::CPAN

    Exporter
);

@EXPORT = qw(
    search_forward
    search_backward
    search
    search_next
);

sub search_forward()
{
    my $this = shift;
    $this->search("/", +1);
}

sub search_backward()
{
    my $this = shift;
    $this->search("?", -1);
}

sub search()
{
    my $this   = shift;
    my $prompt = shift || ':';
    my $direction   = shift || +1; 

    $this->change_canvasheight(-1);
    $this->draw;

    my $querybox = new Curses::UI::SearchEntry(
        -parent   => $this,

lib/Curses/UI/Searchable.pm  view on Meta::CPAN


    # Restore the screen.
    $this->root->cursor_mode($old_cursor_mode);
    $this->change_canvasheight(+1);
    $this->draw;

    $this->root->feedkey($querybox->{-key});
    return $this;
}

sub search_next($$;)
{
    my $this = shift;
    my $query = shift;
    my $direction = shift;
    $direction = ($direction > 0 ? +1 : -1);
    $this->search_get($query, $direction);
}

sub change_canvasheight($;)
{
    my $this = shift;
    my $change = shift;

    if ($change < 0)
    {
	# Change the canvasheight, so we can fit in the searchline.
	$this->{-sh}--;
	$this->{-yscrpos}++
	    if ($this->{-ypos}-$this->{-yscrpos} == $this->canvasheight);

lib/Curses/UI/Searchable.pm  view on Meta::CPAN

	    $inscreen = ($this->canvasheight 
                      - ($this->number_of_lines 
                      - $this->{-yscrpos}));
	}
    }

    $this->{-search_highlight} = undef;
    $this->layout_content();
}

sub search_get($$;)
{
    my $this      = shift;
    my $query     = shift;
    my $direction = shift || +1;

    my $startpos = $this->{-ypos};
    my $offset = 0;
    my $wrapped = 0;
    for (;;)
    {

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

    $this->readonly($this->{-readonly});
    $this->layout_content;

    if ($Curses::UI::ncurses_mouse) {
	$this->set_mouse_binding('mouse-button1', BUTTON1_CLICKED());
    }

    return $this;
}

sub getrealxpos()
{
    my $this = shift;

    my $offset = $this->{-xscrpos};
    my $length = $this->{-xpos} - $this->{-xscrpos};
    return 0 if $length <= 0;

    my $current_line = $this->{-scr_lines}->[$this->{-ypos}];
    my $before_cursor = substr(
        $current_line,
        $this->{-xscrpos},                    # Screen's x position
        $this->{-xpos} - $this->{-xscrpos}    # Space up to the cursor
    );

    my $realxpos = scrlength($before_cursor);

    return $realxpos;
}

sub layout()
{
    my $this = shift;
    $this->SUPER::layout() or return;

    # Scroll up if we can and the number of visible lines
    # is smaller than the number of available lines in the screen.
    my $inscreen = ($this->canvasheight
		 - ($this->number_of_lines 
		    - $this->{-yscrpos}));
    while ($this->{-yscrpos} > 0 and 

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

	$this->{-xscrpos}--;
	$inscreen = ($this->canvaswidth
		  - ($this->number_of_columns 
		     - $this->{-xscrpos}));
    }

    $this->layout_content();
    return $this;
}

sub layout_content()
{
    my $this = shift;
    return $this if $Curses::UI::screen_too_small;
                
    # ----------------------------------------------------------------------
    # Build an array of lines to display and determine the cursor position
    # ----------------------------------------------------------------------

    my $lines_src = $this->split_to_lines($this->{-text});
    foreach (@$lines_src) {$_ .= "\n"}

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

        $this->{-vscrolllen} = @{$this->{-scr_lines}};
        $this->{-vscrollpos} = $this->{-yscrpos};
    } else {
        $this->{-vscrolllen} = 0;
        $this->{-vscrollpos} = 0;
    }

    return $this;
}

sub draw_text(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;
    return $this if $Curses::UI::screen_too_small;

    # Return immediately if this object is hidden.
    return $this if $this->hidden;

    # Turn on underlines and fill the screen with lines
    # if neccessary.

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

        );
    }
    
    $this->{-canvasscr}->attroff(A_UNDERLINE) if $this->{-showlines};
    $this->{-canvasscr}->attroff(A_REVERSE) if $this->{-reverse};
    $this->{-canvasscr}->noutrefresh();
    doupdate() unless $no_doupdate;
    return $this;
}

sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    $this->SUPER::draw(1) or return $this;

    $this->layout_content;
    $this->draw_text(1);
    doupdate() unless $no_doupdate;

    return $this;
}

sub event_onblur()
{
    my $this = shift;
    
    $this->SUPER::event_onblur;

    # Set the cursor position to the startposition
    # if -homeonblur is set.
    if ($this->{-homeonblur}) {
        $this->cursor_to_home;
        $this->layout_content;

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

        $this->run_event('-onchange');
        $this->draw(1);
    }

    # Save the current key.
    $this->{-prevkey} = $key;

    return $ret;
}

sub add_string($;)
{
    my $this = shift;
    my $ch = shift;

    my @ch = split //, $ch;
    $ch = '';
    foreach (@ch) {
	$ch .= $this->key_to_ascii($_);
    }

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

        # pasted string. Get it and process it. Don't do
        # special bindings, but only add-string and newline.
        $ch = $this->get_key(0);
    }

    $this->layout_content;
    $this->set_curxpos;
    return $this;
}

sub toggle_showoverflow()
{
    my $this = shift;
    $this->{-showoverflow} = ! $this->{-showoverflow};
    return $this;
}

sub toggle_wrapping()
{
    my $this = shift;
    return $this->dobeep if $this->{-singleline};
    $this->{-wrapping} = ! $this->{-wrapping};
    $this->layout;
    return $this;
}

sub toggle_showhardreturns()
{
    my $this = shift;
    return $this->dobeep if $this->{-singleline};
    $this->{-showhardreturns} = ! $this->{-showhardreturns};
    return $this;
}

sub cursor_right()
{
    my $this = shift;
    
    # Handle cursor_right for read only mode. 
    if ($this->{-readonly})
    {
        return $this->dobeep
            unless defined $this->{-hscrolllen};

        return $this->dobeep 

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

    if ($this->{-pos} == length($this->{-text})) {
        $this->dobeep;
    } else {
        $this->{-pos}++;
    }
    $this->layout_content;
    $this->set_curxpos;
    return $this;
}

sub cursor_left()
{
    my $this = shift;
    
    # Handle cursor_left for read only mode. 
    if ($this->{-readonly})
    {
        return $this->dobeep if $this->{-xscrpos} <= 0;
        $this->{-xscrpos} -= 1;
        $this->{-xpos} = $this->{-xscrpos};
        return $this;

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

    if ($this->{-pos} <= 0) {
        $this->dobeep;
    } else {
        $this->{-pos}--;
    }
    $this->layout_content;
    $this->set_curxpos;
    return $this;
}
            
sub set_curxpos()
{
    my $this = shift;
    $this->{-curxpos} = $this->{-xpos};
    return $this;
}
            
sub cursor_up(;$)
{
    my $this = shift;
    shift; # stub for bindings handling.
    my $amount = shift || 1;
    
    return $this->dobeep if $this->{-singleline};
    
    # Handle cursor_up for read only mode. 
    if ($this->{-readonly})
    {

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

        my $line = $l->[$idx];
        my $line_length = length($line);
        $this->{-pos} -= $line_length;
        $amount--;
    }
    $this->cursor_to_curxpos;

    return $this;
}

sub cursor_pageup()
{
    my $this = shift;

    return $this->dobeep if $this->{-singleline};
    $this->cursor_up(undef, $this->canvasheight - 1);

    return $this;
}
            
sub cursor_down($;)
{
    my $this = shift;
    shift; # stub for bindings handling.
    my $amount = shift || 1;
    
    return $this->dobeep if $this->{-singleline};
    
    # Handle cursor_down for read only mode. 
    if ($this->{-readonly})
    {

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

        my $line = $l->[$idx];
        my $line_length = length($line);
        $this->{-pos} += $line_length;
        $amount--;
    }
    $this->cursor_to_curxpos;

    return $this;
}

sub cursor_pagedown()
{
    my $this = shift;
    return $this->dobeep if $this->{-singleline};
    
    $this->cursor_down(undef, $this->canvasheight - 1); 

    return $this;
}

sub cursor_to_home()
{
    my $this = shift;
        
    if ($this->{-readonly})
    {
        $this->{-xscrpos} = $this->{-xpos} = 0;
        $this->{-yscrpos} = $this->{-ypos} = 0;
        return $this;
    }
    
    $this->{-pos} = 0;
    $this->set_curxpos;
    return $this;
}

sub cursor_to_end()
{
    my $this = shift;

    if ($this->{-readonly})
    {
        $this->{-xscrpos} = $this->{-xpos} = 0;
        $this->{-yscrpos} = $this->{-ypos} =
            $this->{-vscrolllen}-$this->canvasheight;
        return $this;
    }
    
    $this->{-pos} = length($this->{-text});
    $this->set_curxpos;
    return $this;
}

sub cursor_to_scrlinestart()
{
    my $this = shift;
    # Key argument is set if called from binding.
    my $from_binding = shift; 
    
    if ($this->{-readonly})
    {
        $this->{-xscrpos} = $this->{-xpos} = 0;
        return $this;
    }

    $this->{-pos} -= $this->{-xpos};
    $this->{-xpos} = 0;
    $this->set_curxpos if defined $from_binding;
    return $this;
}
            
sub cursor_to_scrlineend()
{
    my $this = shift;
    my $from_binding = shift;
    
    if ($this->{-readonly})
    {
        $this->{-xscrpos} = $this->{-xpos} = 
            $this->{-hscrolllen} - $this->canvaswidth ;
        return $this;
    }

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

    my $newpos = $this->{-pos};
    my $l = $this->{-scr_lines};
    my $len = length($l->[$this->{-ypos}]) - 1;
    $newpos += $len - $this->{-xpos};
    $this->{-pos} = $newpos;
    $this->layout_content;
    $this->set_curxpos if defined $from_binding;
    return $this;
}

sub cursor_to_linestart()
{
    my $this = shift;

    # Move cursor back, until \n is found. That is
    # the previous line. Then go one position to the
    # right to find the start of the line.
    my $newpos = $this->{-pos};
    for(;;) 
    {
        last if $newpos <= 0;
        $newpos--;
        last if substr($this->{-text}, $newpos, 1) eq "\n";
    }    
    $newpos++ unless $newpos == 0;    
    $newpos = length($this->{-text}) if $newpos > length($this->{-text});
    $this->{-pos} = $newpos;
    $this->layout_content;
    return $this;
}

sub cursor_to_curxpos()
{
    my $this = shift;
    my $right = $this->{-curxpos};
    $right = 0 unless defined $right;
    my $len = length($this->{-scr_lines}->[$this->{-ypos}]) - 1;
    if ($right > $len) { $right = $len }
    $this->{-pos} += $right;
    $this->layout_content;
    return $this;
}

sub clear_line()
{
    my $this = shift;
    $this->cursor_to_linestart;
        $this->delete_till_eol;
    return $this;
}

sub delete_line()
{
    my $this = shift;
    return $this->dobeep if $this->{-singleline};

    my $len = length($this->{-text});
    if ($len == 0)
    {
        $this->dobeep;
        return $this;
    }

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

         ->delete_till_eol
         ->cursor_left
         ->delete_character
         ->cursor_right
         ->cursor_to_linestart
         ->set_curxpos
         ->beep_on;
    return $this;
}

sub delete_till_eol()
{
    my $this = shift;
            
    $this->set_undoinfo;
    
    # Cursor is at newline. No action needed.
    return $this if substr($this->{-text}, $this->{-pos}, 1) eq "\n";

    # Find the next newline. Delete the content up to that newline.
    my $pos = $this->{-pos};

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

        last if substr($this->{-text}, $pos, 1) eq "\n";
    }

    $this->add_to_pastebuffer(
        substr($this->{-text}, $this->{-pos}, $pos - $this->{-pos})
    );
    substr($this->{-text}, $this->{-pos}, $pos - $this->{-pos}, '');
    return $this;
}
            
sub delete_character()
{
    my $this = shift;
    shift(); # stub for bindings handling.
    my $is_backward = shift;
    
    if ($this->{-pos} >= length($this->{-text})) {
        $this->dobeep;    
    } else {
        $this->set_undoinfo;
        $this->add_to_pastebuffer(
            substr($this->{-text}, $this->{-pos}, 1),
            $is_backward    
        );
        substr($this->{-text}, $this->{-pos}, 1, ''),
    }
    return $this;
}

sub backspace()
{
    my $this = shift;
        
    if ($this->{-pos} <= 0) {
        $this->dobeep;
    } else {
        $this->set_undoinfo;
        $this->{-pos}--;
        $this->delete_character(undef,1);
        $this->layout_content;
        $this->set_curxpos;
    }
    return $this;
}

sub newline()
{
    my $this = shift;
    return $this->dobeep if $this->{-singleline};
    $this->add_string("\n");
}

sub mouse_button1($$$$;)
{
    my $this  = shift;
    my $event = shift;
    my $x     = shift;
    my $y     = shift;

    return unless $this->{-focusable};

    # TODO: make this possible for multi line widgets.
    if ($this->{-singleline})
    {
	$this->{-pos} = $this->{-xscrpos} + $x;
        $this->layout_content;
	$this->set_curxpos;
    }
    $this->focus();

    return $this;
}

sub resetsetundo() { shift()->{-didsetundo} = 0}
sub didsetundo()   { shift()->{-didsetundo} }

sub set_undoinfo()
{
    my $this = shift;

    return $this if $this->didsetundo;

    push @{$this->{-undotext}}, $this->{-text};
    push @{$this->{-undopos}}, $this->{-pos};

    my $l = $this->{-undolevels};
    if ($l and @{$this->{-undotext}} > $l) {
        splice(@{$this->{-undotext}}, 0, @{$this->{-undotext}}-$l, ());
        splice(@{$this->{-undopos}}, 0, @{$this->{-undopos}}-$l, ());
    }

    $this->{-didsetundo} = 1;
    return $this;
}

sub undo()
{
    my $this = shift;

    if (@{$this->{-undotext}})
    {
        my $text = pop @{$this->{-undotext}};
        my $pos = pop @{$this->{-undopos}};
        $this->{-text} = $text;
        $this->{-pos} = $pos;
    }
    return $this;
}

sub do_new_pastebuffer(;$)
{
    my $this = shift;
    my $value = shift;
    $this->{-do_new_pastebuffer} = $value     
        if defined $value;
    $this->{-pastebuffer} = '' unless defined $this->{-pastebuffer};
    return $this->{-do_new_pastebuffer};
}

sub clear_pastebuffer()
{
    my $this = shift;
    $this->{-pastebuffer} = '';
    return $this;
}

sub add_to_pastebuffer($;)
{
    my $this = shift;
    my $add = shift;
    my $is_backward = shift || 0;

    $this->clear_pastebuffer if $this->do_new_pastebuffer;
    if ($is_backward) {
        $this->{-pastebuffer} = $add . $this->{-pastebuffer};
    } else {        
        $this->{-pastebuffer} .= $add;
    }
    $this->do_new_pastebuffer(0);
    return $this;
}

sub paste()
{
    my $this = shift;
    
    if ($this->{-pastebuffer} ne '') {
        $this->add_string($this->{-pastebuffer});
    }    
    return $this;
}

sub readonly($;)
{
    my $this = shift;
    my $readonly = shift;

    $this->{-readonly} = $readonly;
    
    if ($readonly)
    {
        my %mybindings = (
            %basebindings,

lib/Curses/UI/TextEditor.pm  view on Meta::CPAN

            %basebindings,
            %editbindings
        );
        $this->{-bindings} = \%mybindings;
	$this->{-nocursor} = 0;
    } 

    return $this;
}

sub get() {shift()->text}

sub pos(;$)
{
    my $this = shift;
    my $pos = shift;
    if (defined $pos) 
    {
        $this->{-pos} = $pos;
        $this->layout_content;
        $this->intellidraw;
        return $this;
    }
    return $this->{-pos};
}

sub text(;$)
{
    my $this = shift;
    my $text = shift;
    if (defined $text) 
    {
        $this->{-text} = $text;
        $this->layout_content;
        $this->intellidraw;
        return $this;
    }
    return $this->{-text};
}

sub onChange(;$) { shift()->set_event('-onchange', shift()) }

sub set_password_char {
    my ($this, $char) = @_;
    $char = substr($char, 0, 1)  if defined $char;
    $this->{-password} = $char;
}

# ----------------------------------------------------------------------
# Routines for search support
# ----------------------------------------------------------------------

sub number_of_lines()   { @{shift()->{-scr_lines}} }
sub number_of_columns()   
{ 
    my $this = shift;
    my $columns = 0;
    foreach (@{$this->{-scr_lines}}) {
        $columns = length($_) 
            if length($_) > $columns;
    }
    return $columns;
}
sub getline_at_ypos($;) { shift()->{-scr_lines}->[shift()] }

#
# Color
#

sub set_color_fg {
    my $this = shift;
    $this->{-fg} = shift;
    $this->intellidraw;
}

lib/Curses/UI/Widget.pm  view on Meta::CPAN

    $this->layout;

    if ($Curses::UI::ncurses_mouse) {
        $this->set_mouse_binding(\&mouse_button1, BUTTON1_CLICKED())
            unless $this->{-mousebindings}->{BUTTON1_CLICKED()};
    }

    return $this;
}

sub DESTROY()
{
    my $this = shift;
    $this->delete_subwindows();
}

sub userdata
{
    my $this = shift;
    if (defined $_[0])
    {
        $this->{-userdata} = $_[0];
    }
    return $this->{-userdata};
}

sub focusable(;$) { 
    my $this = shift;
    my $focusable = shift;

    if (defined $focusable) 
    {
        $this->accessor('-focusable', $focusable);

        # Let the parent find another widget to focus
        # if this widget is not focusable anymore.
        if ($this->{-focus} and not $focusable) {
            $this->parent->focus($this);
        }
    }

    return $this->{-focusable};
}

sub layout()
{
    cbreak();
    
    my $this = shift;

    return if $Curses::UI::screen_too_small;

    $this->process_padding;
    
    # -------------------------------------------------------

lib/Curses/UI/Widget.pm  view on Meta::CPAN

        $this->{-bw}  = $this->{-sw};
        $this->{-bh}  = $this->{-sh};
        $this->{-bx}  = $this->{-sx};
        $this->{-by}  = $this->{-sy};
    }

    return $this;
}


sub process_padding($;)
{
    my $this = shift;

    # Process the padding arguments.
    foreach my $type ('-pad','-ipad') {
        if (defined $this->{$type}) {
            foreach my $side ('right','left','top','bottom') {
                $this->{$type . $side} = $this->{$type}
                    unless defined $this->{$type . $side};
            }
        }
    }
    foreach my $type ('-pad','-ipad') {
        foreach my $side ('right','left','top','bottom') {
            $this->{$type . $side} = 0
                unless defined $this->{$type . $side};
        }
    }
}

sub width_by_windowscrwidth($@)
{
    my $width = shift || 0;
    $width = shift if ref $width; # make $this->width... possible.
    my %args = @_;
    
    $width += 2 if $args{-border};              # border
    $width += 2 if $args{-sbborder};            # sbborder
    $width += 1 if (not $args{-border}   and    # scrollbar and no border
                    not $args{-sbborder} and 
                    $args{-vscrollbar});

lib/Curses/UI/Widget.pm  view on Meta::CPAN

        if ($args{$t}) {
            $width += 2*$args{$t};
        } else {
            $width += $args{$t . "left"}  if defined $args{$t . "left"};
            $width += $args{$t . "right"} if defined $args{$t . "right"};
        }
    }
    return $width;    
}

sub height_by_windowscrheight($@)
{
    my $height = shift || 0;
    $height = shift if ref $height; # make $this->height... possible.
    my %args = @_;
    
    $height += 2 if $args{-border};  # border
    $height += 1 if (not $args{-border} and $args{-hscrollbar});
    foreach my $t ("-ipad", "-pad") # internal + external padding
    {
        if ($args{$t})

lib/Curses/UI/Widget.pm  view on Meta::CPAN


    if (defined $title)
    {
        $this->{-title} = $title; 
        $this->intellidraw;
    }

    return $this->{-title}
}

sub windowparameters()
{ 
    my $this = shift;
    my $scr = shift;

    $scr = "-canvasscr" unless defined $scr;
    my $s = $this->{$scr};
    my ($x,$y,$w,$h);

    $s->getbegyx($y, $x);
    $s->getmaxyx($h, $w); 

lib/Curses/UI/Widget.pm  view on Meta::CPAN

        -h => $h,
        -x => $x,
        -y => $y,
    };
}

#
# Actually, the focus is not loose but the widget should
# lose the focus:

sub lose_focus() 
{
    my $this = shift;
    $this->loose_focus(@_);
}


sub loose_focus()
{
    my $this = shift;
    my $key  = shift;
        
    # The focus change will draw $this anyhow and this
    # will reset the schedule if somewhere in the middle of
    # a binding routine loose_focus() is called (else
    # first the focus would shift and after that $this
    # would be redrawn).
    #

lib/Curses/UI/Widget.pm  view on Meta::CPAN

        if (defined $key and $key eq KEY_BTAB()) {
            $this->parent->focus_prev();
        } else {
            $this->parent->focus_next();
        }
    }

    return $this;
}

sub focus()
{ 
    my $this = shift;

    # Let the parent focus this object.
    my $parent = $this->parent;
    $parent->focus($this) if defined $parent;

    $this->draw(1) if ($this->root->overlapping);
    return $this;
}

lib/Curses/UI/Widget.pm  view on Meta::CPAN

        $this->root->do_one_event($this);
    }

    $this->{-focus} = 0;
    $this->{-has_modal_focus} = 0;

    return $this;
}


sub draw(;$)
{
    my $this = shift;
    my $no_doupdate = shift || 0;

    # Return immediately if this object is hidden of if
    # the screen is currently too small.
    return if $Curses::UI::screen_too_small;
    return if $this->hidden;

    eval { curs_set(0) }; # not available on every system.

lib/Curses/UI/Widget.pm  view on Meta::CPAN

        }
        
        $this->draw_scrollbars();
        $this->{-borderscr}->noutrefresh();
    }

    doupdate() unless $no_doupdate;
    return $this;
}

sub draw_scrollbars()
{    
    my $this = shift;

    return $this unless defined $this->{-borderscr};

    if ($this->{-vscrollbar} and defined $this->{-vscrolllen}) 
    {

        # Compute the drawing range for the scrollbar.
        my $xpos = $this->{-vscrollbar} eq 'left' 

lib/Curses/UI/Widget.pm  view on Meta::CPAN

            for my $i (0 .. $actlen-1) {
                $this->{-borderscr}->addch($ypos, $i+$actpos," ");
            }
            $this->{-borderscr}->attroff(A_REVERSE);
        }
    }
    
    return $this;
}

sub beep_on()  { my $this = shift; $this->{-nobeep} = 0; return $this }
sub beep_off() { my $this = shift; $this->{-nobeep} = 1; return $this }
sub dobeep()
{
    my $this = shift;
    beep() unless $this->{-nobeep};
    return $this;
}


# TODO: work out hiding of objects.
sub hidden() { shift()->{-hidden}     }
sub hide()   { shift()->{-hidden} = 1 }
sub show()   { shift()->{-hidden} = 0 }

sub intellidraw(;$)
{
    my $this = shift;

    if ( $this->{-intellidraw} and
         not $this->hidden     and 
         $this->in_topwindow ) {
        $this->draw(1);
    }

    return $this;
}

sub delete_subwindows()
{
    my $this = shift;
    delete $this->{-scr};
    foreach my $win (qw(-borderscr -canvasscr)) 
    {
        if (defined $this->{$win}) 
        {
            $this->{$win}->delwin;
            delete $this->{$win};
        }
    }
}

sub parentwindow()
{
    my $object = shift;

    until (not defined $object or 
           $object->isa('Curses::UI::Window')) { 
       $object = $object->parent 
    }

    return $object;
}

sub in_topwindow()
{
    my $this = shift;

    # Get the parent window of this widget.
    my $win = $this->parentwindow();
    return unless defined $win;

    # A modal window should always be the topwindow.
    return 1 if $win->{-has_modal_focus};

lib/Curses/UI/Widget.pm  view on Meta::CPAN

    } 

    # Check if the parent window is on top.
    return (@path and ($win eq $path[-1]));
}

# ----------------------------------------------------------------------
# Binding 
# ----------------------------------------------------------------------

sub clear_binding($;)
{
    my $this = shift;
    my $binding = shift;
    my @delete = ();
    while (my ($k,$v) = each %{$this->{-bindings}}) {
            push @delete, $k if $v eq $binding;
    }
    foreach (@delete) {
            delete $this->{-bindings}->{$_};
    }
    return $this;
}

sub set_routine($$;)
{
    my $this = shift;
    my $binding = shift;
    my $routine = shift;
    $this->{-routines}->{$binding} = $routine;
    return $this;
}

sub set_binding($@)
{
    my $this = shift;
    my $routine = shift;
    my @keys = @_;

    # Create a routine entry if the routine that was
    # passed is a code reference instead of a 
    # routine name.
    if (ref $routine eq 'CODE')
    {

lib/Curses/UI/Widget.pm  view on Meta::CPAN

    $this->root->fatalerror("set_binding(): $routine: no such routine")
        unless defined $this->{-routines}->{$routine};

    foreach my $key (@keys) {
            $this->{-bindings}->{$key} = $routine;
    }

    return $this;
}

sub set_mouse_binding($@)
{
    my $this = shift;
    my $routine = shift;
    my @mouse_events = @_;

    # Create a routine entry if the routine that was
    # passed is a code reference instead of a 
    # routine name.
    if (ref $routine eq 'CODE')
    {

lib/Curses/UI/Widget.pm  view on Meta::CPAN

    $this->root->fatalerror("set_binding(): $routine: no such routine")
        unless defined $this->{-routines}->{$routine};

    foreach my $mouse_event (@mouse_events) {
            $this->{-mousebindings}->{$mouse_event} = $routine;
    }

    return $this;
}

sub schedule_draw(;$) { shift()->accessor('-schedule_draw', shift()) }

sub process_bindings($;$@)
{
    my $this = shift;
    my $key = shift;
    my $is_mouse_event = shift || 0; 
    my @extra = @_;
    
    # Reset draw schedule.
    $this->schedule_draw(0);

    # Find the binding to use.

lib/Curses/UI/Widget.pm  view on Meta::CPAN

    if (defined $binding) {
        my $return = $this->do_routine($binding, $key, @extra);
        # Redraw if draw schedule is set.
        $this->intellidraw if $this->schedule_draw; 
        return $return;
    } else {
        return 'DELEGATE';
    }
}

sub do_routine($;$)
{
    my $this = shift;
    my $binding = shift;
    my @arguments = @_;

    # Find the routine to call.
    my $routine = $this->{-routines}->{$binding};
        
    if (defined $routine) 
    {

lib/Curses/UI/Widget.pm  view on Meta::CPAN

        } else {
            return $routine;
        }
    } else {
        $this->root->fatalerror(
            "No routine defined for keybinding \"$binding\"!"
        );
    }
}

sub onFocus($;$) { shift()->set_event('-onfocus', shift()) }
sub onBlur($;$)  { shift()->set_event('-onblur',  shift()) }

sub event_onfocus()
{
    my $this = shift;

    # Let the parent find another widget to focus
    # if this widget is not focusable.
    unless ($this->focusable) {
        return $this->parent->focus($this);
    }

    $this->{-focus} = 1;

lib/Curses/UI/Widget.pm  view on Meta::CPAN


    # Set cursor mode
    my $show_cursor = $this->{-nocursor} ? 0 : 1;
    $this->root->cursor_mode($show_cursor);

    $this->draw(1) if (not $this->root->overlapping);

    return $this;
}

sub event_onblur()
{
    my $this = shift;
    $this->{-focus} = 0;
    $this->run_event('-onblur');
    $this->draw(1) if (not $this->root->overlapping);
    return $this;
}

sub event_keypress($;)
{
    my $this = shift;
    my $key = shift;
    $this->process_bindings($key);
}

sub event_mouse($;)
{
    my $this   = shift;
    my $MEVENT = shift;

    my $winp = $this->windowparameters;
    my $abs_x = $MEVENT->{-x} - $winp->{-x};
    my $abs_y = $MEVENT->{-y} - $winp->{-y};

    $this->process_bindings($MEVENT, 1, $abs_x, $abs_y);
}

sub mouse_button1($$$$;)
{
    my $this  = shift;
    my $event = shift;
    my $x     = shift;
    my $y     = shift;

    $this->focus() if not $this->{-focus} and $this->focusable;
}

# ----------------------------------------------------------------------
# Event handling
# ----------------------------------------------------------------------

sub clear_event($;)
{
    my $this = shift;
    my $event = shift;
    $this->set_event($event, undef);
    return $this;
}

sub set_event($;$)
{
    my $this      = shift;
    my $event     = shift;
    my $callback  = shift;

    if (defined $callback) 
    {
        if (ref $callback eq 'CODE') {
            $this->{$event} = $callback;
        } else {

lib/Curses/UI/Widget.pm  view on Meta::CPAN

                "$event callback for $this "
              . "($callback) is no CODE reference"
            );
        }
    } else {
        $this->{$event} = undef;
    }
    return $this;
}

sub run_event($;)
{
    my $this = shift;
    my $event = shift;
    
    my $callback = $this->{$event};
    if (defined $callback) {
        if (ref $callback eq 'CODE') {
            return $callback->($this);
        } else {
            $this->root->fatalerror(



( run in 1.580 second using v1.01-cache-2.11-cpan-65fba6d93b7 )