NAME
Prima::TextView - rich text browser widget
SYNOPSIS
use strict;
use warnings;
use Prima qw(TextView Application);
my $w = Prima::MainWindow-> create(
name => 'TextView example',
);
my $t = $w->insert(TextView =>
text => 'Hello from TextView!',
pack => { expand => 1, fill => 'both' },
);
# Create a single block that renders all the text using the default font
my $tb = tb::block_create();
my $text_width_px = $t->get_text_width($t->text);
my $font_height_px = $t->font->height;
$tb->[tb::BLK_WIDTH] = $text_width_px;
$tb->[tb::BLK_HEIGHT] = $font_height_px;
$tb->[tb::BLK_BACKCOLOR] = cl::Back;
$tb->[tb::BLK_FONT_SIZE] = int($font_height_px) + tb::F_HEIGHT;
# Add an operation that draws the text:
push @$tb, tb::text(0, length($t->text), $text_width_px);
# Set the markup block(s) and recalculate the ymap
$t->{blocks} = [$tb];
$t->recalc_ymap;
# Additional step needed for horizontal scroll as well as per-character
# selection:
$t->paneSize($text_width_px, $font_height_px);
run Prima;
DESCRIPTION
Prima::TextView accepts blocks of formatted text, and provides basic functionality - scrolling and user selection. The text strings are stored as one large text chunk, available by the ::text
and ::textRef
properties. A block of a formatted text is an array with fixed-length header and the following instructions.
A special package tb::
provides the block constants and simple functions for text block access.
Capabilities
Prima::TextView is mainly the text block functions and helpers. It provides function for wrapping text block, calculating block dimensions, drawing and converting coordinates from (X,Y) to a block position. Prima::TextView is centered around the text functionality, and although any custom graphic of arbitrary complexity can be embedded in a text block, the internal coordinate system is used ( TEXT_OFFSET, BLOCK ), where TEXT_OFFSET is a text offset from the beginning of a block and BLOCK is an index of a block.
The functionality does not imply any text layout - this is up to the class descendants, they must provide they own layout policy. The only policy Prima::TextView requires is that blocks' BLK_TEXT_OFFSET field must be strictly increasing, and the block text chunks must not overlap. The text gaps are allowed though.
A text block basic drawing function includes change of color, backColor and font, and the painting of text strings. Other types of graphics can be achieved by supplying custom code.
- block_draw CANVAS, BLOCK, X, Y
-
The
block_draw
draws BLOCK onto CANVAS in screen coordinates (X,Y). It can be used not only inside begin_paint/end_paint brackets; CANVAS can be an arbitraryPrima::Drawable
descendant. - block_walk BLOCK, %OPTIONS
-
Cycles through block opcodes, calls supplied callbacks on each.
Coordinate system methods
Prima::TextView employs two its own coordinate systems: (X,Y)-document and (TEXT_OFFSET,BLOCK)-block.
The document coordinate system is isometric and measured in pixels. Its origin is located into the imaginary point of the beginning of the document ( not of the first block! ), in the upper-left pixel. X increases to the right, Y increases down. The block header values BLK_X and BLK_Y are in document coordinates, and the widget's pane extents ( regulated by ::paneSize
, ::paneWidth
and ::paneHeight
properties ) are also in document coordinates.
The block coordinate system in an-isometric - its second axis, BLOCK, is an index of a text block in the widget's blocks storage, $self->{blocks}
, and its first axis, TEXT_OFFSET is a text offset from the beginning of the block.
Below different coordinate system converters are described
- screen2point, point2screen X, Y
-
screen2point
accepts (X,Y) in the screen coordinates ( O is a lower left widget corner ), returns (X,Y) in document coordinates ( O is upper left corner of a document ).point2screen
does the reverse. - xy2info X, Y
-
Accepts (X,Y) is document coordinates, returns (TEXT_OFFSET,BLOCK) coordinates, where TEXT_OFFSET is text offset from the beginning of a block ( not related to the big text chunk ) , and BLOCK is an index of a block.
- info2xy TEXT_OFFSET, BLOCK
-
Accepts (TEXT_OFFSET,BLOCK) coordinates, and returns (X,Y) in document coordinates of a block.
- text2xoffset TEXT_OFFSET, BLOCK
-
Returns X coordinate where TEXT_OFFSET begins in a BLOCK index.
- info2text_offset
-
Accepts (TEXT_OFFSET,BLOCK) coordinates and returns the text offset with regard to the big text chunk.
- text_offset2info TEXT_OFFSET
-
Accepts big text offset and returns (TEXT_OFFSET,BLOCK) coordinates
- text_offset2block TEXT_OFFSET
-
Accepts big text offset and returns BLOCK coordinate.
Text selection
The text selection is performed automatically when the user selects a text region with a mouse. The selection is stored in (TEXT_OFFSET,BLOCK) coordinate pair, and is accessible via the ::selection
property. If its value is assigned to (-1,-1,-1,-1) this indicates that there is no selection. For convenience the has_selection
method is introduced.
Also, get_selected_text
returns the text within the selection (or undef with no selection ), and copy
copies automatically the selected text into the clipboard. The latter action is bound to Ctrl+Insert
key combination.
A block with TEXT_OFFSET set to -1 will be treated as not containing any text, and therefore will not be able to get selected.
Event rectangles
Partly as an option for future development, partly as a hack a concept of 'event rectangles' was introduced. Currently, {contents}
private variable points to an array of objects, equipped with on_mousedown
, on_mousemove
, and on_mouseup
methods. These are called within the widget's mouse events, so the overloaded classes can define the interactive content without overloading the actual mouse events ( which is although easy but is dependent on Prima::TextView own mouse reactions ).
As an example Prima::PodView uses the event rectangles to catch the mouse events over the document links. Theoretically, every 'content' is to be bound with a separate logical layer; when the concept was designed, a html-browser was in mind, so such layers can be thought as ( in the html world ) links, image maps, layers, external widgets.
Currently, Prima::TextView::EventRectangles
class is provided for such usage. Its property ::rectangles
contains an array of rectangles, and the contains
method returns an integer value, whether the passed coordinates are inside one of its rectangles or not; in the first case it is the rectangle index.
AUTHOR
Dmitry Karasik, <dmitry@karasik.eu.org>.
SEE ALSO
Prima::Drawable::TextBlock, Prima::PodView, examples/mouse_tale.pl.