Prima::Drawable - 2-D graphic interface |
Prima::Drawable - 2-D graphic interface
Prima::Drawable is a descendant of Prima::Component. It provides access to the object-bound graphic context and canvas through its methods and properties. The Prima::Drawable descendants Prima::Widget, Prima::Image, Prima::DeviceBitmap and Prima::Printer are backed by system-dependent routines that allow drawing and painting on the system objects.
Prima::Drawable, as well as its ancestors Prima::Component and
Prima::Object, is never used directly, because Prima::Drawable class
by itself provides only the interface. It provides a
three-state object access - when drawing and painting is enabled,
when these are disabled, and the information acquisition state.
By default, the object is created in paint-disabled state. To
switch to the enabled state, begin_paint()
method is used. Once in the enabled state,
the object drawing and painting methods apply to the object-bound canvas.
To return to the disabled state, end_paint()
method is called.
The information state can be managed by using
begin_paint_info()
and end_paint_info()
methods pair. An object
cannot be triggered from the information state
to the enabled state ( and vice versa ) directly.
These states differ on how do they apply to a graphic context and
a canvas.
The graphic context is the set of variables, that control how exactly graphic primitives are rendered. The variable examples are color, font, line width, etc. Another term used here is 'canvas' - the graphic area of a certain extent, bound to the object, where the drawing and painting methods are applied to.
In all three states a graphic context is allowed to be modified, but in different ways. In the disabled state the graphic context values form a template values; when a object enters the information or the enabled state, the values are preserved, but when the object is back to the disabled state, the graphic context is restored to the values last assigned before entering new state. The code example below illustrates the idea:
$d = Prima::Drawable-> create; $d-> lineWidth( 5); $d-> begin_paint_info; # lineWidth is 5 here $d-> lineWidth( 1); # lineWidth is 1 $d-> end_paint_info; # lineWidth is 5 again
( Note: ::region
, ::clipRect
and ::transform
properties are exceptions.
They can not be used in the disabled state; their values are neither
recorded nor used as a template).
That is, in disabled state any Drawable maintains only the graphic context. To draw on a canvas, the object must enter the enabled state by begin_paint(). This function can be unsuccessful, because the object binds with system resources during this stage, and that can fail. After the enabled state is entered, the canvas is accessible:
$d = Prima::Image-> create( width => 100, height => 100); if ( $d-> begin_paint) { $d-> color( cl::Black); $d-> bar( 0, 0, $d-> size); $d-> color( cl::White); $d-> fill_ellipse( $d-> width / 2, $d-> height / 2, 30, 30); $d-> end_paint; }
Different objects are mapped to different types of canvases - Prima::Image canvas pertains its content after end_paint(), Prima::Widget maps it to a screen area, which content is of more transitory nature, etc.
The information state is as same as the enabled state, but the changes to
a canvas are not visible. Its sole purpose is to read, not to write information.
Because begin_paint()
requires some amount of system resources, there is
a chance that resource request can fail, for any reason. The begin_paint_info()
requires some resources as well, but usually much less, and therefore
if only information is desired, it is usually faster and cheaper to
obtain it inside the information state. A notable and wide-spread example is
get_text_width()
method, that returns length of a text string in pixels.
It works in both enabled and information states, but code
$d = Prima::Image-> create( width => 10000, height => 10000); $d-> begin_paint; $x = $d-> get_text_width('A'); $d-> end_paint;
is much more 'expensive' than
$d = Prima::Image-> create( width => 10000, height => 10000); $d-> begin_paint_info; $x = $d-> get_text_width('A'); $d-> end_paint_info;
for the obvious reasons.
It must be noted that some information methods like get_text_width()
work even under the disabled state; the object is switched to
the information state implicitly if needed.
Graphic context and canvas operations are wholly relied on a system implementation. The internal canvas color representation is therefore system-specific, and usually could not be described in standard definitions. Often the only information available about color space is its color depth.
Therefore, all color manipulations, including dithering and antialiasing are subject to system implementation, and can not be controlled from perl code. When a property is set in the object disabled state, it is recorded verbatim; color properties are no exception. After the object switched to the enabled state, a color value is transformed to a system color representation, and these values may differ. For example, if a display color depth is 15 bits, 5 bits for every component, then white color value 0xffffff is mapped to
11111000 11111000 11111000 --R----- --G----- --B-----
that equals to 0xf8f8f8, not 0xffffff ( See the Prima::gp-problems manpage for inevident graphic issues discussion ).
As it might be guessed, Drawable color format is RRGGBB, with component resolution 8 bit, thus allowing 2^24 color combinations. If the color space depth is different, the color is truncated or expanded automatically. In case the device color depth is small, dithering algorithms might apply.
Note: not only color properties, but all graphic context properties allow all possible values in the disabled state, which transformed into system-allowed values in the enabled and the information states. This feature can be used to test if a graphic device is capable of performing certain operations ( for example, if it supports raster operations - the printers usually do not ). Example:
$d-> begin_paint; $d-> rop( rop::Or); if ( $d-> rop != rop::Or) { # this assertion is always false without ... # begin_paint/end_paint brackets } $d-> end_paint;
There are ( at least ) two color properties on each drawable -
::color
and ::backColor
. The values they operate are integers
in the discussed above RRGGBB format, however, the toolkit defines
some mnemonic color constants:
cl::Black cl::Blue cl::Green cl::Cyan cl::Red cl::Magenta cl::Brown cl::LightGray cl::DarkGray cl::LightBlue cl::LightGreen cl::LightCyan cl::LightRed cl::LightMagenta cl::Yellow cl::White cl::Gray
As stated before, it is not unlikely that if a device color depth is small, the primitives plotted in particular colors will be drawn with dithered or incorrect colors. This usually happens on paletted displays, with 256 or less colors.
There exists two methods that facilitate the correct color representation.
The first way is to get as much information as possible about the device.
The methods get_nearest_color()
and get_physical_palette()
provide possibility to avoid mixed colors drawing by obtaining
indirect information about solid colors, supported by a device.
Another method is to use ::palette
property. It tries to insert
the passed colors into the system palette, so if an application
knows the colors it needs beforehand, it can employ this method - however
this might result in system palette flash if a window focus toggles.
Both of these methods are applicable both with drawing routines and image output. An image desired to output with least distortion is advised to export its palette to an output device, because images usually are not subject to automatic dithering algorithms. Prima::ImageViewer module employs this scheme.
Prima maintains its own font naming convention, that usually does not conform to system's. Since its goal is interoperability, it might be so that some system fonts would not be accessible from within the toolkit.
Prima::Drawable provides property ::font
, that accepts/returns a hash,
that represents the state of a font in the object-bound graphic context.
The font hash keys that are acceptable on set-call are:
size
and height
is
height - internal_leading size = --------------------------- * 72.27 resolution
That differs from some other system representations: Win32, for example, rounds 72.27 constant to 72.
fs::
( font style ) constants. The constants hight
fs::Normal fs::Bold fs::Thin fs::Italic fs::Underlined fs::StruckOut fs::Outline
and can be OR-ed together to express the font style. fs::Normal equals to 0 and usually never used. If some styles are not supported by a system-dependent font subsystem, they get ignored.
fp::Default fp::Fixed fp::Variable
fp::Default specifies no interest about font pitch selection. fp::Fixed is set when a monospaced font is desired - e.g., when all glyphs are of same width. fp::Variable pitch specifies a font with different glyph widths. This key is of the highest priority; all other keys may be altered for the consistency of the pitch key.
Prima::Application::font_encodings
. Selects desired font
encoding; if empty, picks the first matched encoding.
The encodings provided by different systems are different; in addition, the only encodings are recognizable by the system, that are represented by at least one font in the system.
Unix systems and the toolkit PostScript interface usually provide the following encodings:
iso8859-1 iso8859-2 ... other iso8859 ... fontspecific
Win32 returns the literal strings like
Western Baltic Cyrillic Hebrew Symbol
A hash that ::font
returns, is a tied hash, whose
keys are also available as separate properties.
For example,
$x = $d-> font-> {style};
is equivalent to
$x = $d-> font-> style;
While the latter gives nothing but the arguable coding convenience, its usage in set-call is much more usable:
$d-> font-> style( fs::Bold);
instead of
my %temp = %{$d-> font}; $temp{ style} = fs::Bold; $d-> font( \%temp);
The properties of a font tied hash are also accessible through set()
call,
like in Prima::Object:
$d-> font-> style( fs::Bold); $d-> font-> width( 10);
is adequate to
$d-> font-> set( style => fs::Bold, width => 10, );
When get-called, ::font
property returns a hash where
more entries than the described above can be found. These keys
are read-only, their values are discarded if passed to ::font
in a set-call.
In order to query the full list of fonts available to
a graphic device, a ::fonts
method is used. This method is
not present in Prima::Drawable namespace; it can be found in two
built-in class instances, Prima::Application
and Prima::Printer
.
Prima::Application::fonts
returns metrics for the fonts available to
a screen device, while Prima::Printer::fonts
( or its substitute Prima::PS::Printer )
returns fonts for the printing device. The result of this method is an
array of font metrics, fully analogous to these
returned by Prima::Drawable::font
method.
------------- external leading line
$ ------------- ascent line $ $ ------------- internal leading line $ $$$ $ $ $ $ $ $$$$$$$ $$$ $ $ $ $ $ $ $ $ $ $ $$$ ---- baseline $ $ $ $$$$ ---- descent line
fw::UltraLight fw::ExtraLight fw::Light fw::SemiLight fw::Medium fw::SemiBold fw::Bold fw::ExtraBold fw::UltraBold
constants.
Besides these characteristics, every font glyph has an ABC-metric, the three integer values that describe horizontal extents of a glyph's black part relative to the glyph extent:
. . . . . . . . . . $$$. . . . . . . $$. $ . . . . . . $$. . . . $$ . . . $$$$$$$$$$. . .$$$$$ . . . . $$ . . . $ $$ . . . . $$ . . . .$$$$$ . . . . $$ . . . . $$ . . . .$$ . . . . $$$ $$$. . $$ .$$ . . . $ $$ . .$$$ . . . .$$$$$$$$. . . . . . . . . . <A>. .<C> <A>. .<C> .<-.--B--.->. . .<--B--->. .
A = -3 A = 3 B = 13 B = 10 C = -3 C = 3
A and C are negative, if a glyphs 'hangs' over it neighbors, as shown in picture on the left. A and C values are positive, if a glyph contains empty space in front or behind the neighbor glyphs, like in picture on the right. As can be seen, B is the width of a glyph's black part.
ABC metrics returned by get_font_abc()
method.
A drawable has two raster operation properties: ::rop
and ::rop2
.
These define how the graphic primitives are plotted. ::rop
deals
with the foreground color drawing, and ::rop2
with the background.
The toolkit defines the following operations:
rop::CopyPut # /* dest = src */ rop::XorPut # /* dest ^= src */ rop::AndPut # /* dest &= src */ rop::OrPut # /* dest |= src */ rop::NotPut # /* dest = !src */ rop::NotBlack # /* dest = (src != 0) ? src : dest */ rop::NotDestXor # /* dest = (!dest) ^ src */ rop::NotDestAnd # /* dest = (!dest) & src */ rop::NotDestOr # /* dest = (!dest) | src */ rop::NotSrcXor # /* dest ^= !src */ rop::NotSrcAnd # /* dest &= !src */ rop::NotSrcOr # /* dest |= !src */ rop::NotXor # /* dest = !(src ^ dest) */ rop::NotAnd # /* dest = !(src & dest) */ rop::NotOr # /* dest = !(src | dest) */ rop::NotBlackXor # /* dest ^= (src != 0) ? src : dest */ rop::NotBlackAnd # /* dest &= (src != 0) ? src : dest */ rop::NotBlackOr # /* dest |= (src != 0) ? src : dest */ rop::NoOper # /* dest = dest */ rop::Blackness # /* dest = black */ rop::Whiteness # /* dest = white */ rop::Invert # /* dest = !dest */ rop::Pattern # /* dest = pattern */ rop::XorPattern # /* dest ^= pattern */ rop::AndPattern # /* dest &= pattern */ rop::OrPattern # /* dest |= pattern */ rop::NotSrcOrPat # /* dest |= pattern | (!src) */ rop::SrcLeave # /* dest = (src != fore color) ? src : dest */ rop::DestLeave # /* dest = (src != back color) ? src : dest */
Usually, however, graphic devices support only a small part
of the above set, limiting ::rop
to the most important operations:
Copy, And, Or, Xor, NoOp. ::rop2
is usually even more restricted -
it is only OS/2 system currently that supports other rop2 modes than
Copy and NoOp.
The raster operations apply to all graphic primitives except SetPixel.
The Prima toolkit employs a geometrical XY grid, where X ascends rightwards and Y ascends upwards. There, the (0,0) location is the bottom-left pixel of a canvas.
All graphic primitives use inclusive-inclusive boundaries. For example,
$d-> bar( 0, 0, 1, 1);
plots a bar that covers 4 pixels: (0,0), (0,1), (1,0) and (1,1).
The coordinate origin can be shifted using ::transform
property,
that translates the (0,0) point to the given offset. Calls to
::transform
, ::clipRect
and ::region
always use the 'physical'
(0,0) point, whereas the plotting methods use the transformation result,
the 'logical' (0,0) point.
As noted before, these three properties can not be used in when an object is in its disabled state.
$d-> clipRect( 1, 1, 2, 2); $d-> bar( 0, 0, 1, 1);
thus affects only one pixel (1,1).
Discards the previous ::region
value.
Note: ::clipRect
can not be used while the object is in the paint-disabled state,
its context is neither recorded nor used as a template
( see Graphic context and canvas).
Accepts either a fp::
constant or a reference to an array of 8 integers,
each representing 8 bits of each line in a pattern, where the first integer
is the topmost pattern line, and the bit 0x80 is the leftmost pixel in the line.
There are some predefined patterns, that can be referred via fp::
constants:
fp::Empty fp::Solid fp::Line fp::LtSlash fp::Slash fp::BkSlash fp::LtBkSlash fp::Hatch fp::XHatch fp::Interleave fp::WideDot fp::CloseDot fp::SimpleDots fp::Borland fp::Parquet
( the actual patterns are hardcoded in primguts.c ) The default pattern is fp::Solid.
An example below shows encoding of fp::Parquet pattern:
# 76543210 84218421 Hex
0 $ $ $ 51 1 $ $ 22 2 $ $ $ 15 3 $ $ 88 4 $ $ $ 45 5 $ $ 22 6 $ $ $ 54 7 $ $ 88
$d-> fillPattern([ 0x51, 0x22, 0x15, 0x88, 0x45, 0x22, 0x54, 0x88 ]);
On a get-call always returns an array, never a fp::
constant.
name
, height
, size
, width
, style
and pitch
.
Synopsis:
$d-> font-> size( 10); $d-> font-> name( 'Courier'); $d-> font-> set( style => $x-> font-> style | fs::Bold, width => 22 );
See Fonts for the detailed descriptions.
Applies to text_out(), get_text_width(), get_text_box(), get_font_abc().
le::Flat le::Square le::Round
constants. le::Round is the default value.
lp::
constant, or
a string where each even byte is a length of a dash,
and each odd byte is a length of a gap.
The predefined constants are:
lp::Null # "" /* */ lp::Solid # "\1" /* ___________ */ lp::Dash # "\x9\3" /* __ __ __ __ */ lp::LongDash # "\x16\6" /* _____ _____ */ lp::ShortDash # "\3\3" /* _ _ _ _ _ _ */ lp::Dot # "\1\3" /* . . . . . . */ lp::DotDot # "\1\1" /* ............ */ lp::DashDot # "\x9\6\1\3" /* _._._._._._ */ lp::DashDotDot # "\x9\3\1\3\1\3" /* _.._.._.._.. */
Not all systems are capable of accepting user-defined line patterns,
and in such situations the lp::
constants are mapped to the system-defined
patterns. In Win9x, for example, lp::DashDotDot is much different from
its string definition therefore.
Default value is lp::Solid.
Default value is 0.
$d-> palette([128, 240, 240]);
selects a gray-cyan color, for example.
The return value from get-call is the content of the previous set-call, not the actual colors that were copied to the system palette.
::clipRect
value; successive get-calls
to ::clipRect
return the boundaries of the region.
Note: ::region
can not be used while the object is in the paint-disabled state,
its context is neither recorded nor used as a template
( see Graphic context and canvas).
See also: ::rop2
, Raster operations.
See also: ::rop
, Raster operations.
text_out()
fills the text background area
with ::backColor
property value before
drawing the text. Default value is 0, when text_out()
plots
text only.
See get_text_box().
text_out()
plots text on a given Y coordinate
correspondent to font baseline. If FLAG is 0, a Y coordinate is
mapped to font descent line. Default is 0.
::clipRect
and ::region
. Not cumulative,
so the call sequence
$d-> transform( 5, 5); $d-> transform( 15, 15);
is equivalent to
$d-> transform( 15, 15);
Note: ::transform
can not be used while the object is in the paint-disabled state,
its context is neither recorded nor used as a template
( see Graphic context and canvas).
Context used: color, backColor, lineEnd, linePattern, lineWidth, rop, rop2
Context used: color, backColor, fillPattern, rop, rop2
Context used: color, backColor, lineEnd, linePattern, lineWidth, rop, rop2
Context used: backColor, rop2
draw_text
is a convenience wrapper around text_wrap
for drawing the wrapped
text, and also provides the tilde ( ~ )- character underlining support.
The FLAGS is a combination of the following constants:
dt::Left - text is aligned to the left boundary dt::Right - text is aligned to the right boundary dt::Center - text is aligned horizontally in center dt::Top - text is aligned to the upper boundary dt::Bottom - text is aligned to the lower boundary dt::VCenter - text is aligned vertically in center dt::DrawMnemonic - tilde-escapement and underlining is used dt::DrawSingleChar - sets tw::BreakSingle option to Prima::Drawable::text_wrap call dt::NewLineBreak - sets tw::NewLineBreak option to Prima::Drawable::text_wrap call dt::SpaceBreak - sets tw::SpaceBreak option to Prima::Drawable::text_wrap call dt::WordBreak - sets tw::WordBreak option to Prima::Drawable::text_wrap call dt::ExpandTabs - performs tab character ( \t ) expansion dt::DrawPartial - draws the last line, if it is visible partially dt::UseExternalLeading - text lines positioned vertically with respect to the font external leading dt::UseClip - assign ::clipRect property to the boundary rectangle dt::QueryLinesDrawn - calculates and returns number of lines drawn ( contrary to dt::QueryHeight ) dt::QueryHeight - if set, calculates and returns vertical extension of lines drawn dt::NoWordWrap - performs no word wrapping by the width of the boundaries dt::WordWrap - performs word wrapping by the width of the boundaries dt::Default - dt::NewLineBreak|dt::WordBreak|dt::ExpandTabs|dt::UseExternalLeading
Context used: color, backColor, font, rop, textOpaque, textOutBaseline
Context used: color, backColor, linePattern, lineWidth, rop, rop2
Context used: color, backColor, fillPattern, rop, rop2
Context used: color, backColor, fillPattern, rop, rop2
$d-> fillpoly([ 0, 0, 15, 20, 30, 0]); # triangle
Context used: color, backColor, fillPattern, rop, rop2
See also: polyline().
Context used: color, backColor, fillPattern, rop, rop2
SINGLEBORDER = 0: The fill area is bounded by the color specified by the COLOR parameter.
SINGLEBORDER = 1: The fill area is defined by the color that is specified by COLOR. Filling continues outward in all directions as long as the color is encountered. This style is useful for filling areas with multicolored boundaries.
Context used: color, backColor, fillPattern, rop, rop2
Context used: color, backColor, linePattern, lineWidth, rop, rop2
lines()
plots a straight line per quartet.
Context used: color, backColor, linePattern, lineWidth, rop, rop2
No context is used.
Context used: rop
abs(DEST_WIDTH)
pixels wide
and abs(DEST_HEIGHT)
pixels tall.
If DEST_WIDTH or DEST_HEIGHT are
negative, a mirroring is performed.
OBJECT must be Prima::Image, Prima::Icon or Prima::DeviceBitmap.
No context is used.
Context used: rop
No context is used.
Context used: color, backColor, linePattern, lineWidth, rop, rop2
Context used: color, backColor, lineEnd, linePattern, lineWidth, rop, rop2
OBJECT must be Prima::Image, Prima::Icon or Prima::DeviceBitmap.
Context used: rop
Context used: color, backColor, font, rop, textOpaque, textOutBaseline
See also: end_paint
, begin_paint_info
, Graphic context and canvas
begin_paint
),
except painting and drawing methods do not change the object canvas.
See also: end_paint_info
, begin_paint
, Graphic context and canvas
See also: begin_paint
, Graphic context and canvas
See also: begin_paint_info
, Graphic context and canvas
Called implicitly by ::font
on set-call, allowing the following
example to work:
$d-> font-> set( size => 10); $d-> font-> set( style => fs::Bold);
In the example, the hash 'style => fs::Bold' does not overwrite the previous font context ( 'size => 10' ) but gets added to it ( by font_match()), providing the resulting font with both font properties set.
Prima::Application
and Prima::Printer
, does not
present in Prima::Drawable
.
Returns an array of font metric hashes for a given font FAMILY. Every hash has full set of elements described in Fonts.
If called without parameters, returns an array of same hashes where each hash represents a member of font family from every system font set.
Example:
print sort map {"$_->{name}\n"} @{$::application-> fonts};
The result is an integer array reference, where every character glyph is referred by three integers, each triad containing A, B and C values.
For detailed explanation of ABC meaning, see Font ABC metrics;
Context used: font
The physical palette array is non-empty only on paletted graphic devices, the true color devices return an empty array.
The physical palette reflects the solid colors currently available to all programs in the system. The information is volatile if the system palette can change colors, since any other application may change the system colors at any moment.
If ADD_OVERHANG is 1, the first character's absolute A value and the last character's absolute C value are added to the string if they are negative.
See more on ABC values at Font ABC metrics.
Context used: font
The result is an anonymous array of 5 points ( 5 integer pairs in (X,Y) format). These 5 points are offsets for the following string extents, given the string is plotted at (0,0):
1: start of string at ascent line
2: start of string at descent line
3: end of string at ascent line
4: end of string at descent line
5: concatenation point
The concatenation point coordinates (XC,YC) are coordinated passed
to consequent text_out()
call so the conjoint string would plot
as if it was a part of TEXT.
Context used: font
The break algorithm and its result are governed by OPTIONS integer value that is a combination of C<tw::> constants:
If set, returns an empty array. If unset, returns a text broken by minimum number of characters perl chunk. In the latter case, the text blocks will exceed WIDTH.
0x2028
and 0x2029
are also
in effect.
text_wrap()
function.
If set, the array consists of integer pairs, each consists of a text offset within TEXT and a its length.
If unset, the resulting array consists from text chunks.
text_wrap
proceeds until the first line is wrapped, either by
width or ( if specified ) by break characters. Returns length of the
resulting line. Used for efficiency when a reverse function to get_text_width
is needed.
If OPTIONS has tw::CalcMnemonic or tw::CollapseTilde bits set, then the last scalar in the array result is a hash reference. The hash contains extra information regarding the 'hot key' underline position - it is assumed that '~' - escapement denotes an underlined character. The hash contains the following keys:
Context used: font
Dmitry Karasik, <dmitry@karasik.eu.org>.
Prima, the Prima::Object manpage, the Prima::Image manpage
Prima::Drawable - 2-D graphic interface |