Prima

 view release on metacpan or  search on metacpan

Prima/InputLine.pm  view on Meta::CPAN


	my $border = $self-> {borderWidth};
	my @size = $self-> size;
	my @r = ( $self->{atDrawX} + $border + 2, $self->{atDrawX} + $border + 2 );
	my @invalid_rects;
	my $fc = $self->{firstChar};
	$self-> begin_paint_info;
	$self-> {glyphs}-> selection_walk(
		$self-> {glyphs}-> selection_diff( $old_chunks, $new_chunks ),
		$self->{firstChar}, $self->{n_clusters},
		sub {
			my ( $offset, $length, $changed ) = @_;
			my $dx = $self->{glyphs}->get_sub_width($self, $fc + $offset, $length );
			$r[1] += $dx;
			push @invalid_rects, [ $r[0] - 1, $border + 1, $r[1], $size[1]-$border-1 ]
				if $changed;
			$r[0] = $r[1];
		}
	);
	$self-> end_paint_info;

	$self->invalidate_rect(@$_) for @invalid_rects;
}

sub on_enable  { $_[0]-> repaint; }
sub on_disable { $_[0]-> repaint; }

sub on_leave
{
	my @s = $_[0]-> selection;
	$_[0]-> repaint if $s[0] != $s[1];
}

sub on_enter
{
	my $self = $_[0];

	$self-> insertMode( $::application-> insertMode);

	if ( $self-> {autoSelect}) {
		my @s = $self-> selection;
		$self-> {autoAdjustDisabled} = 1;
		$self-> select_all;
		$self-> {autoAdjustDisabled} = undef;
		my @s2 = $self-> selection;
		$self-> repaint if $s[0] == $s2[0] and $s[1] == $s2[1];
	} else {
		my @s = $self-> selection;
		$self-> repaint if $s[0] != $s[1];
	}
}

sub on_dragbegin
{
	my $self = shift;
	$self->{drop_transaction} = 1;
}

sub on_dragend
{
	my ( $self, $clipboard, $action, $modmap, $x, $y, $ref) = @_;
	$self->{drop_transaction} = 0;
	return unless $clipboard;
	my $cap = $clipboard->text;
	$self->text($cap) if defined $cap;
}

sub select_all { $_[0]-> selection(0,-1); }

sub autoHeight
{
	return $_[0]-> {autoHeight} unless $#_;
	$_[0]-> {autoHeight} = $_[1];
	$_[0]-> check_auto_size;
}

sub textLigation
{
	return $_[0]-> {textLigation} unless $#_;
	my ( $self, $textLigation ) = @_;
	$self-> {textLigation} = $textLigation;
	$self-> text( $self-> text );
}

sub textDirection
{
	return $_[0]-> {textDirection} unless $#_;
	my ( $self, $td ) = @_;
	$self-> {textDirection} = $td;
	$self-> text( $self-> text );
	$self-> alignment( $td ? ta::Right : ta::Left );
}

sub edit_text
{
	my ($self, $text) = @_;
	$self-> begin_undo_group;
	$self-> push_undo_action( 'edit_text', $self->text);
	$self-> text($text);
	$self-> end_undo_group;
}

sub autoSelect    {($#_)?($_[0]-> {autoSelect}    = $_[1])                :return $_[0]-> {autoSelect}   }
sub autoTab       {($#_)?($_[0]-> {autoTab}       = $_[1])                :return $_[0]-> {autoTab}      }
sub readOnly      {($#_)?($_[0]-> {readOnly }     = $_[1])                :return $_[0]-> {readOnly }    }
sub wordDelimiters{($#_)?($_[0]-> {wordDelimiters}= $_[1])                :return $_[0]-> {wordDelimiters}}
sub alignment     {($#_)?($_[0]-> set_alignment(    $_[1]))               :return $_[0]-> {alignment}    }
sub borderWidth   {($#_)?($_[0]-> set_border_width( $_[1]))               :return $_[0]-> {borderWidth}  }
sub charOffset    {($#_)?($_[0]-> set_char_offset(  $_[1]))               :return $_[0]-> {charOffset}   }
sub maxLen        {($#_)?($_[0]-> set_max_len  (    $_[1]))               :return $_[0]-> {maxLen   }    }
sub firstChar     {($#_)?($_[0]-> set_first_char(   $_[1]))               :return $_[0]-> {firstChar}    }
sub writeOnly     {($#_)?($_[0]-> set_write_only(   $_[1]))               :return $_[0]-> {writeOnly}    }
sub passwordChar  {($#_)?($_[0]-> set_password_char($_[1]))               :return $_[0]-> {passwordChar} }
sub insertMode    {($#_)?($_[0]-> set_insert_mode  (    $_[1]))           :return $_[0]-> {insertMode}   }
sub selection     {($#_)? $_[0]-> set_selection   ($_[1], $_[2]) : return ($_[0]-> {selStart},$_[0]-> {selEnd})}
sub selStart      {($#_)? $_[0]-> set_selection   ($_[1], $_[0]-> {selEnd}): return $_[0]-> {'selStart'}}
sub selEnd        {($#_)? $_[0]-> set_selection   ($_[0]-> {'selStart'}, $_[1]):return $_[0]-> {'selEnd'}}
sub selText    {
	my( $f, $t) = $_[0]->selection_strpos;
	($#_) ? do {
	my $x = $_[ 0]-> text;
	substr( $x, $f, $t - $f) = $_[ 1];
	$_[0]-> text( $x);
	$_[0]-> set_selection( $f, $f + length $_[ 1]);
	} : return substr( $_[ 0]-> text, $f, $t - $f);
}

#sub on_validate
#{
#	my ($self, $textref) = @_;
#}

sub blink
{
	my ($self, %opt) = @_;
	return if $self-> bring('BlinkTimer');
	my $bc = $self-> backColor;
	my $c  = $self-> color;
	$self-> color($opt{color} // cl::White);
	$self-> backColor($opt{backColor} // 0xff8080);
	$self-> insert( Timer =>
		name    => 'BlinkTimer',
		timeout => 300,
		onTick  => sub {
			$_[0]-> destroy;
			$self-> color($c);
			$self-> backColor($bc);
		},
	)-> start;
}

1;

=pod

=head1 NAME

Prima::InputLine - standard input line widget

=head2 SYNOPSIS

	use Prima qw(InputLine Application);
	Prima::InputLine-> new( text => 'Hello world!');
	run Prima;

=for podview <img src="inputline.gif">

=for html <p><img src="https://raw.githubusercontent.com/dk/Prima/master/pod/Prima/inputline.gif">

=head1 DESCRIPTION

The class provides basic functionality of an input line,
including hidden input, read-only state, selection, and
clipboard operations. The input line text data is
contained in L<text> property.

=head1 API

=head2 Events

=over

=item Change

The notification is called when the L<text> property is changed, either
interactively or as a result of direct call.

=item Validate TEXT_REF

The notification is called right before the L<text> property is changed, either
interactively or as a result of direct call. The custom code has a chance to
validate the text and/or provide some sort of interactive feedback.

See also: L</blink>

=back

=head2 Properties

=over

=item alignment INTEGER

One of the following C<ta::> constants, defining the text alignment:

	ta::Left
	ta::Right
	ta::Center

Default value: C<ta::Left>

=item autoHeight BOOLEAN

If 1, adjusts the height of the widget automatically when its font changes.

Default value: 1

=item autoSelect BOOLEAN

If 1, all the text is selected when the widget becomes focused.

Default value: 1

=item autoTab BOOLEAN

If 1, the keyboard C<kb::Left> and C<kb::Right> commands, if received
when the cursor is at the beginning or at the end of text, and cannot be
mover farther, not processed. The result of this is that the default handler
moves focus to a neighbor widget, in a way as if the Tab key
was pressed.

Default value: 0

=item borderWidth INTEGER

Prima/InputLine.pm  view on Meta::CPAN

=item readOnly BOOLEAN

If 1, the text cannot be edited by the user.

Default value: 0

=item selection START, END

Two integers, specifying the beginning and the end of the selected text, in
clusters. A case with no selection is when START equals END.

=item selStart INTEGER

Selects the start of text selection.

=item selEnd INTEGER

Selects the end of text selection.

=item textDirection BOOLEAN

If set, indicates RTL text input.

=item textLigation BOOLEAN

If set, text may be rendered at better quality with ligation and kerning,
however that comes with a price that some ligatures may be indivisible and form
clusters (f.ex. I<ff> or I<ffi> ligatures). Cursor cannot go inside of such
clusters, and thus one can only select them, delete as whole, or press
Del/Backspace on the cluster's edge.

Toggle during runtime with Ctrl+Shift+L.

=item wordDelimiters STRING

Contains string of character that are used for locating a word break.
Default STRING value consists of punctuation marks, space and tab characters,
and C<\xff> character.

=item writeOnly BOOLEAN

If 1, the input is not shown but mapped to L<passwordChar> characters.
Useful for a password entry.

Default value: 0

=back

=head2 Methods

=over

=item blink %options

Produces a short blink by setting background to red color.
Can be used to signal invalid input, f ex from C<on_validate>.
C<%options> allows C<backColor> and C<color> entries.

=item copy

Copies the selected text, if any, to the clipboard.

Default key: Ctrl+Insert

=item cut

Cuts the selected text into the clipboard.

Default key: Shift+Delete

=item delete

Removes the selected text.

Default key: Delete

=item paste

Copies text from the clipboard and inserts it in the cursor position.

Default key: Shift+Insert

=item select_all

Selects all text

=back

=head2 Bi-directional input and output

When working on bidirectional texts, or text represented by complex script
shaping, methods C<firstChar>, C<charOffset>, C<selection> etc cannot be used
to calculate text offsets f.ex. via C<substr>. Note that these values are in
clusters, not in characters (see L<Prima::Drawable::Glyphs> for the
description>. Also, selection ranges of bidi text become not straighforward.
Use the following methods whenever text manipulations are needed:

=over

=item char_at OFFSET

Returns character at OFFSET

=item selection_strpos

Returns range of characters covered by the selection.

=back

=head1 AUTHOR

Dmitry Karasik, E<lt>dmitry@karasik.eu.orgE<gt>.

=head1 SEE ALSO

L<Prima>, L<Prima::Widget>, F<examples/edit.pl>.

=cut



( run in 1.562 second using v1.01-cache-2.11-cpan-84e82930d8c )