=for rcs $Id: Drawable.pod,v 1.30 2008/04/24 21:30:15 dk Exp $ =head1 NAME Prima::Drawable - 2-D graphic interface =head1 SYNOPSIS if ( $object-> isa('Prima::Drawable')) { $object-> begin_paint; $object-> color( cl::Black); $object-> line( 100, 100, 200, 200); $object-> ellipse( 100, 100, 200, 200); $object-> end_paint; } =head1 DESCRIPTION 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. =head1 USAGE 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. =head2 Graphic context and 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: C<::region>, C<::clipRect> and C<::translate> 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 calling begin_paint(). This function can be unsuccessful, because the object binds with system resources during this stage, and might fail. Only 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; } else { die "can't draw on image:$@"; } 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 a 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 example is get_text_width() method, that returns the 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 it is necessary. =head2 Color space Graphic context and canvas operations rely completely 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, which might be different from Prima's. 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 L for inevident graphic issues discussion ). The Prima::Drawable color format is RRGGBB, with each component resolution of 8 bit, thus allowing 2^24 color combinations. If the device 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 - C<::color> and C<::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 C<::palette> property. It works by inserting the 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 when 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. =head2 Monochrome bitmaps A special case of C is taken where the object to be drawn is a monochrome DeviceBitmap object. This object doesn't possess the color palette, and is by definition a bitmap, where there are only two values present, 0s and 1s. When it is drawn, 0s are drawn with the color value of the target canvas C property, and 1s with C. This means that the following code $bitmap-> color(0); $bitmap-> line(0,0,100,100); $target-> color(cl::Green); $target-> put_image(0,0,$bitmap); produces a green line on C<$target>. When using monochrome bitmaps for logical operations, note that target colors should not be explicit 0 and 0xffffff, nor C and C, but C and C instead. The reason is that on paletted displays, system palette may not necessarily contain the white color under palette index (2^ScreenDepth-1). C thus signals that the value should be "all ones", no matter what color it represents, because it will be used for logical operations. =head2 Fonts 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 C<::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: =over 4 =item name The font name string. If there is no such font, a default font name is used. To select default font, a 'Default' string can be passed with the same result ( unless the system has a font named 'Default', of course). =item height An integer value from 1 to MAX_INT. Specifies the desired extent of a font glyph between descent and ascent lines in pixels. =item size An integer value from 1 to MAX_INT. Specifies the desired extent of a font glyph between descent and internal leading lines in points. The relation between C and C is height - internal_leading size = --------------------------- * 72.27 resolution That differs from some other system representations: Win32, for example, rounds 72.27 constant to 72. =item width A integer value from 0 to MAX_INT. If greater than 0, specifies the desired extent of a font glyph width in pixels. If 0, sets the default ( designed ) width corresponding to the font size or height. =item style A combination of C ( 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 are ignored. =item pitch A one of three constants: fp::Default fp::Fixed fp::Variable fp::Default specifies no interest about font pitch selection. fp::Fixed is set when a monospaced (all glyphs are of same width) font is desired. 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. =item direction A counter-clockwise rotation angle - 0 is default, 90 is pi/2, 180 is pi, etc. If a font could not be rotated, it is usually substituted to the one that can. =item encoding A string value, one of the strings returned by C. Selects desired font encoding; if empty, picks the first matched encoding, preferably the locale set up by the user. 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 =back A hash that C<::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, C<::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 C<::font> in a set-call. In order to query the full list of fonts available to a graphic device, a C<::fonts> method is used. This method is not present in Prima::Drawable namespace; it can be found in two built-in class instances, C and C. C returns metrics for the fonts available to a screen device, while C ( 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 C method. =over 4 =item family A string with font family name. The family is a secondary string key, used for distinguishing between fonts with same name but of different vendors ( for example, Adobe Courier and Microsoft Courier). =item vector A boolean; true if the font is vector ( e.g. can be scaled with no quality loss ), false otherwise. The false value does not show if the font can be scaled at all - the behavior is system-dependent. Win32 and OS/2 can scale all non-vector fonts; X11 only the fonts specified as the scalable. =item ascent Number of pixels between a glyph baseline and descent line. =item descent Number of pixels between a glyph baseline and descent line. =item internalLeading Number of pixels between ascent and internal leading lines. Negative if the ascent line is below the internal leading line. =item externalLeading Number of pixels between ascent and external leading lines. Negative if the ascent line is above the external leading line. =for podview =for html

------------- external leading line $ ------------- ascent line $ $ ------------- internal leading line $ $$$ $ $ $ $ $ $$$$$$$ $$$ $ $ $ $ $ $ $ $ $ $ $$$ ---- baseline $ $ $ $$$$ ---- descent line =for podview =item weight A font designed weight. Can be one of fw::UltraLight fw::ExtraLight fw::Light fw::SemiLight fw::Medium fw::SemiBold fw::Bold fw::ExtraBold fw::UltraBold constants. =item maximalWidth Maximal extent of a glyph in pixels. Equals to B in monospaced fonts. =item xDeviceRes Designed horizontal font resolution in dpi. =item yDeviceRes Designed vertical font resolution in dpi. =item firstChar Index of the first glyph present in a font. =item lastChar Index of the last glyph present in a font. =item breakChar Index of the default character used to divide words. In a typical western language font it is 32, ASCII space character. =item defaultChar Index of a glyph that is drawn instead of nonexistent glyph if its index is passed to the text drawing routines. =back =head2 Font ABC metrics 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: =for podview =for html

. . . . . . . . . . $$$. . . . . . . $$. $ . . . . . . $$. . . . $$ . . . $$$$$$$$$$. . .$$$$$ . . . . $$ . . . $ $$ . . . . $$ . . . .$$$$$ . . . . $$ . . . . $$ . . . .$$ . . . . $$$ $$$. . $$ .$$ . . . $ $$ . .$$$ . . . .$$$$$$$$. . . . . . . . . . . . . . .<-.--B--.->. . .<--B--->. . A = -3 A = 3 B = 13 B = 10 C = -3 C = 3 =for podview 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. =head2 Raster operations A drawable has two raster operation properties: C<::rop> and C<::rop2>. These define how the graphic primitives are plotted. C<::rop> deals with the foreground color drawing, and C<::rop2> with the background. The toolkit defines the following operations: rop::Blackness # = 0 rop::NotOr # = !(src | dest) rop::NotSrcAnd # &= !src rop::NotPut # = !src rop::NotDestAnd # = !dest & src rop::Invert # = !dest rop::XorPut # ^= src rop::NotAnd # = !(src & dest) rop::AndPut # &= src rop::NotXor # = !(src ^ dest) rop::NotSrcXor # alias for rop::NotXor rop::NotDestXor # alias for rop::NotXor rop::NoOper # = dest rop::NotSrcOr # |= !src rop::CopyPut # = src rop::NotDestOr # = !dest | src rop::OrPut # |= src rop::Whiteness # = 1 Usually, however, graphic devices support only a small part of the above set, limiting C<::rop> to the most important operations: Copy, And, Or, Xor, NoOp. C<::rop2> is usually even more restricted - it is only OS/2 system that supports currently rop2 modes others than Copy and NoOp. The raster operations apply to all graphic primitives except SetPixel. =head2 Coordinates 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 C<::translate> property, that translates the (0,0) point to the given offset. Calls to C<::translate>, C<::clipRect> and C<::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. =head1 API =head2 Graphic context properties =over 4 =item backColor COLOR Reflects background color in the graphic context. All drawing routines that use non-solid or transparent fill or line patterns use this property value. =item color COLOR Reflects foreground color in the graphic context. All drawing routines use this property value. =item clipRect X1, Y1, X2, Y2 Selects the clipping rectangle corresponding to the physical canvas origin. On get-call, returns the extent of the clipping area, if it is not rectangular, or the clipping rectangle otherwise. The code $d-> clipRect( 1, 1, 2, 2); $d-> bar( 0, 0, 1, 1); thus affects only one pixel at (1,1). Set-call discards the previous C<::region> value. Note: C<::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 L<"Graphic context and canvas">). =item fillWinding BOOLEAN Affect filling style of complex polygonal shapes filled by C. If 1, the filled shape contains no holes; otherwise, holes are present where the shape edges cross. Default value: 0 =item fillPattern ( [ @PATTERN ] ) or ( fp::XXX ) Selects 8x8 fill pattern that affects primitives that plot filled shapes: bar(), fill_chord(), fill_ellipse(), fillpoly(), fill_sector(), floodfill(). Accepts either a C 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 C 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 C constant. =item font \%FONT Manages font context. FONT hash acceptable values are C, C, C, C, C