Fenestra User's Guide (Chapter 5) -- contents | previous | next
This cluster describes the graphical output facilities of the library. Graphics output goes to graphics devices such as the screen or a printer page, or other more abstract devices. After the device system, device setting classes and drawable objects corresponding to graphics primitives will be introduced.
The `graphics' cluster makes use of the basic persistence mechanism provided by the foundation library. In a nutshell, objects which inherit from the class P_TEXT_OBJECT can be serialised to a text string, to_string. This string can be stored into a file, or in the case of a GUI application in a system registry entry -- see chapter (see section 6) for complete coverage of the registry facility. This string can be retrieved later and used to initialise an instance of the object using from_string, which may also be a creation procedure of the object.
This simple scheme is compiler and platform independent, so applications written using this library can exchange such serialised representation of objects even if compiled with different Eiffel compilers on various implementations of the Win32 API.
The schema is specified by the object implementation, which in the case of this library generally includes a version number ensuring whenever possible a smooth transition to later versions of the library. Each serialisable object has its own version history, and a new version is added only when necessary, not with every global version of the library, which would be excessive At the time of writing, the first release of the library of course include one single version for each P_TEXT_OBJECT descendant. Evolutions will be documented on a case by case basis in future releases..
A more detailed explanation of the foundation library's class P_TEXT_OBJECT can be found in [pylon96] and appendix (see section B.2) of this manual. Most uses of the facility in the GUI library are in this cluster, for graphical objects such as font and the geometric primitives, points and rectangles.
This section introduces two basic geometry primitives, point and rectangle which are used throughout the library. The aim of these classes is not to provide a complete coverage of geometric concepts, but simply to provide the basic amenities that are required by the library's other components. A complete geometry cluster is out of the scope of a user interface library.
These classes are only implementing geometric concepts, and are not used directly for more concrete classes. For example, a rectangle that can be drawn on a graphic device uses a geometric RECTANGLE as a client, not as an ancestor -- or an heir -- in harmony with the usual design guidelines of this library.
All coordinates used in the geometry classes are integers, as both the graphics and windowing subsystem use integers in their coordinate systems.
Both points and rectangles are implemented as heirs to the foundation class P_TEXT_OBJECT for simple persistence. This can be used to save the position of a window in the registry for example. The standard out string function is also redefined to show meaningful output, that can be convenient for debugging among other things.
The class POINT implements the basic concept of point, that is a set of two coordinates, x and y. These coordinates can be changed either separately (set_x and set_y) or at the same time using set_xy. The later is also a creation procedure under the name make_coord. The other creation procedure creates a default point at the origin (0,0). A boolean value, is_origin can check this, along with a small set of other functions for simple comparisons with other points.
The class RECTANGLE does not really implement geometric rectangles, but the most common type of user interface rectangles, whose sides are parallel to the coordinate axes. Such a rectangle is defined by two points, the lower and upper points -- as the names indicate, lower's coordinates are inferior to upper's. It is nevertheless possible to create or change a rectangle with arbitrary points, using respectively make_points and its synonym set_points.
The lower and upper points can also be changed individually (set_lower and set_upper) as long as the contract is maintained (the new coordinates of a lower point are still inferior to the existing upper point for instance). The size of the rectangle, width and height, is available and can be changed with set_width and set_height. Changing the size is equivalent to moving the upper point, the lower point remains unchanged.
The width and height are defined so that a rectangle reduced to a point has a width and height equal to one, that is the width for instance is equal to upper.y - lower.y + 1.
As discussed in appendix (see section D), this is meaningful for pixel-based devices or coordinate system. On devices based on logical coordinates, where a pixel can be assumed to have no width (or zero), it makes less sense. As these dimensions are most useful in relation to the GUI construction classes, absolute coordinates are better used with graphics functions operating in a logical space.
A set of informative attributes are available, such as the rectangle centre, along with some procedures for basic operations such as translation of the rectangle. Translation may be useful for instance to centre a dialog box into its parent window.
Graphic devices are abstract constructs used to represent the various devices, physical or logical, that can receive graphic output. Physical devices are typically the screen or printers while logical devices may be a metafile (a set of graphic commands stored in memory or a file) or a bitmap stored in memory and not actually displayed or the client area of a window -- a part of the physical screen.
The class GRAPHIC_DEVICE is a deferred class which introduces most operations that can be done on a graphic device. The main categories of operations are: device setup, modal methods used to maintain the state of the device and to set some common drawing parameters, utility functions for retrieving information about the device, and finally the drawing methods performing the actual graphic output.
A device can be able or not to receive graphic output. A device that can accept output is ready. This status can be checked with the boolean value is_ready. A device can be made ready by a call to the method prepare or by its creation procedures for some devices -- it depends on the type of device and will be clarified later on a case by case basis. Conversely, an active device can be freed with the procedure release.
In order to help the programmer, assertions ensure that an open device will be closed -- it is not possible to prepare a device twice, so the error should be promptly caught when a device has not been properly released, if this is necessary.
Some commands, like changing the device state, can be processed whatever the readiness status, while others, like drawing operations, are valid only on an active device, as documented by appropriate preconditions.
A graphic device maintains a state of several permanent attributes which are used by most graphic operations. For instance, a pen describes how lines and curves will be drawn -- be they straight lines or part of a rectangle or circle. The device state can be changed at any time and the device will not lose its state across readiness boundaries, when the device is freed and prepared again Developers familiar with the low-level API should note that this library's graphic device state is at a higher level than the API's. There is no direct mapping between a library's pen, or device for that matter, and their Windows' counterpart, although there is of course a semantic mapping.. Attributes range from those used to set the way graphic output is done, like changing line thickness, to others used to set the coordinate system -- to change units from pixel to millimetres for instance.
A device has a default state at creation time, which can be reinitialised using reset. The graphic attributes, pen, font, etc will be reviewed in later sections and are changed using the corresponding procedures set_pen, set_font, etc.
It is important to remember that the state of the device correspond to the attribute at the time of the call of the procedures that changes them. As the contracts show, these procedure do not keep references on their parameters, which can later be modified and reused without consequences for the device or devices with which they were previously used.
Before drawing, the device client may need some information. Capabilities such as the device size, colour depth, may be retrieved from attribute capabilities, an instance of DEVICE_CAPABILITIES. Similarly, capabilities associated with text output are accessible through text_capabilities, an instance of TEXT_METRICS which gives information such as the current font selected for the device.
Drawing operations needs coordinates, and the device may change the coordinate system (see section (see section 5.4.2) below) to use logical coordinates, as opposed to physical coordinates where the unit is the device pixel. The functions device_to_logical and logical_to_device allow conversions of points between physical and logical coordinates. This may be especially useful when drawing in the client area of a window and interacting with the window system which uses device coordinates.
The function get_point_color may be used to retrieve the current colour of any point on raster devices which permit this operation (see preconditions). It is not possible on vector devices such as a plotter or a metafile.
Extra metrics functions are used in association with text operations and will be described below (section (see section 5.5.5)).
The graphic device may be clipped, that is graphical output is constrained into a specific area of the device -- output outside this area is allowed but will not be displayed. A window device is clipped during a partial redraw event for instance. In order to speed up processing a client may test if an area is at least partially inside the current clipping area, and send graphic commands only when necessary. The boolean functions is_point_visible and is_rectangle_visible are used to that effect.
Actual graphic output is done on active devices by a simple call to the procedure draw which takes a DRAWABLE object. Every graphics primitive inherits from the class DRAWABLE, whose descendants are detailed in section (see section 5.5).
The most common type of concrete graphic output is done on the computer screen. Applications do not write directly to the whole screen, but to the part of the window they are in charge of, the client area. Each window has a device attribute, an instance of class WINDOW_DEVICE which is the graphic device used to draw in the client area of the window.
This type of device is not always ready for graphic output. Most, if not all, graphic output will only take place during the processing of a drawing event as seen in chapter (see section 3). For this reason, a window's device is not usually ready, and has to be prepared, and then released, for graphic output. The library prepares the device before a drawing event and releases afterwards so that the client need not bother about the issue most of the time. Nevertheless, it may be necessary to access the device outside the drawing to get access to device metrics for instance, like converting the physical coordinates of a mouse click during a mouse event to device coordinates for later use.
Another basic type of device is the printer device, used as an interface to traditional printers or sometimes services with a pseudo printer interface such as fax software. A printer device can accept the same graphical output than another device for WYSIWYG output -- except for text in some circumstances (see section (see section 5.5.5)).
In addition to normal device operations, a printer introduces the concept of document, and the concept of page. Before graphic output, the document must be opened with the method start_document and closed after use with end_document. Inside a document, each page must be bracketed with calls to start_page and end_page -- pages are sent to the actual printer device once completed. Optionally a document name can be specified for information purposes before the call to start_document using the procedure set_document_name.
An instance of class PRINTER_DEVICE is ready at creation, if this has been succesful, and therefore calls to prepare will trigger an assertion violation. A printer device can be released. It is possible to create a printer device corresponding to the default printer using the creation procedure make_default; or an instance of a printer device can be obtained from a successful invocation of the print setup common dialog box (see section (see section 3.9.5)).
The metafile device, class METAFILE_DEVICE is associated with a file which contains a series of graphics commands that can be replayed at a later stage on another device. It is Windows' native version of vector file formats like CGM or DXF, although file processing is managed by the operating system. While generally viewed as a vector format, it can include bitmaps, as drawing a bitmap into a device is a normal drawing operation. It is not a raster device in the sense that it is not possible to retrieve the colour of an arbitrary point for instance, and the commands are just stored, not actually rasterised, like for bitmap device introduced in the next section.
The files managed by this device usually have the extension .EMF, for Enhanced MetaFile, which is Win32's native metafile format. The `enhanced' part refers to the old metafile format -- .WMF extension -- used by earlier 16-bit versions of Windows.
Metafile devices are created in reference to an existing device, for the default state, colour depth and palette, etc. A metafile is bounded by a rectangle whose size in millimetres must be specified at creation time. A metafile can be associated with a file when created using the creation procedure make_file. It is also possible to create a metafile in memory, for use inside the application, most commonly for pasting into the clipboard. A memory metafile is created using the creation procedure make_memory.
The creation of a metafile can fail (for instance when the file name is invalid, or the current user does not have the permission to write to this file), and the is_ready boolean value should be checked before graphics command are executed.
Bitmap devices are graphic devices whose graphic output is rasterised into a logical bitmap in memory. A new bitmap device can be created using the procedure make, which takes a model device -- which can be any type of raster device -- as a parameter. This model is used to initialise the device, especially the colour depth and palette which is essential for bitmaps.
Alternatively, the bitmap can also be to initialised from a bitmap resource -- using the make_resource creation procedure inherited from RESOURCE_OBJECT.
Like a metafile or printer device, a bitmap device is ready at creation and can only be released using the procedure release when it is not needed any more. The size of the bitmap can be changed -- the existing bitmap will be erased if there is one -- using the procedure set_size. The attributes width and height are used to retrieve the bitmap size.
In addition, the class BITMAP_DEVICE makes extensive use of multiple inheritance: BITMAP_DEVICE device also inherits from DRAWABLE. It means a bitmap stored in a bitmap device object can itself be drawn on another device -- even another bitmap device.
The symmetric operation is also possible, a portion of any raster device can be copied to the bitmap device using copy_from_device. The procedure set_position is used to set the position on the `other' device for both drawing into and copying from the client device.
The drawing and copy operation can also be made to map the bitmap's device content to a remote rectangle in the client device, by changing the default mode using set_mode_stretch. In this case, the client has to set a target rectangle using set_target instead of a simple position. If this rectangle's size is not equal to the bitmap's size, the bitmap will be stretched by the system from the source to the destination to fit in its destination rectangle -- that is the bitmap device size for copy_from_device, and the target rectangle when drawing on another device.
The class also provides access to Windows' bitmap (.BMP) files, that can be saved from the device using the procedure save and load to retrieve a bitmap from disk. Unlike metafiles, the processing of bitmap file on disk is implemented by the library, not by the operating system. However, the library implements canonical bitmap files as documented in the Win32 API documentation while common .bmp file may also come from OS/2 or from earlier version of Windows. The differences are not managed by the library and such files may not be loaded correctly.
The first family of classes associated with a graphic device allows control of the state of the device, and access to device information. This section will introduce information classes, coordinate control, and then the more graphic concepts of drawing modes, pens, brushes, colours, palette and fonts.
The classes DEVICE_CAPABILITIES and TEXT_METRICS are permanent attributes of graphic devices, and are used to group device information functions.
Device capabilities cover information like the type of device, colour structure of the device and the device size. The type of device can be checked using the is_plotter, is_raster_display, is_metafile family of boolean values. Nonetheless, client code should not usually rely on the type of device and the output should be as generic as possible.
On the other hand, the more general has_raster boolean can be relied upon, when the fact that the device is a raster -- bitmap -- device is important.
The size of the device is provided in pixels by width_pixel and height_pixel integers, along with the rectangle screen_pixel for convenience. Other measures are the size in millimetres -- width_mm and height_mm -- and the resolution in dots per inches -- width_dpi and height_dpi for respectively horizontal and vertical resolution.
The boolean value can_rotate_text is true when the device can rotate text to any angle, and can_rotate_text_90 for right angles.
The remainder relates to colour and palette information. If the device has a palette, that is a restricted set of colours that can be displayed at the same time, the boolean value has_palette will be true. Otherwise, the device is either true colour or has enough colours so that a palette is not used. Palettised screen modes typically have 256 simultaneous colours. The actual number is the integer palette_size.
A palette has a number of standard colours -- palette_reserved -- used by Windows to display the user interface constantly, even when individual windows change the palette. These colours cannot normally be changed.
The class TEXT_METRICS give information relating to the current font (see section (see section 5.4.8) below). Like device capabilities, information is only available when the parent device is active (is_ready).
The font family functions permit access to a list all fonts available for the device. This could be used to implement a font selection dialog box for instance. The list font_families lists all font families, eg `Times New Roman', `Arial', etc. This is done by giving a list of font descriptions, including one typical font of each family. Iterating on this list to get the font names, gets the list of font families.
The list of all actual fonts, that is including the variants of a single font, such as `Bold', `Bold Italic', etc, can be obtained from font_family, taking the main family name as a parameter. Various variants may be available, and the system may produce automatically some pseudo-italic or bold version of a single font, but they will never match the quality of a specially design italic or bold font. This function lists the real variants that correspond to separate font data files.
The method font gives a copy of the current font description, an instance of LOGICAL_FONT. Other attributes give extra information on the current font. is_true_type indicates a scalable TrueType font (as opposed to a bitmap or plotter font). is_vector is true for plotter fonts and is_device is for device specific fonts such as a printer's built-in fonts which have no screen equivalent.
The functions ascent, internal_leadings, maximum_character_width and others give extra metrics information relating to the current font, in device logical coordinates.
When a device is initialised, the coordinate system works in normal device coordinates as common with computer graphic output systems -- the unit is the pixel, the origin is the top left of the screen, the x-axis coordinates grows from left to right and the y-axis goes down.
It is nevertheless possible to change this with the classes inheriting from GRAPHIC_MAPPING, used with the set_mapping procedure from GRAPHIC_DEVICE.
Basic coordinate systems can be selected through the class PAGE_MAPPING. The procedure text selects the default system described above.
All other systems offered by this class are cartesian -- this can be checked with is_cartesian -- that is the x-axis goes rightwards as usual, the y-axis goes up and the system is isotropic -- logical squares are (or should be) shown as squares. These cartesian coordinates are also using real coordinates that are independent of the device, such as millimetres. This is especially useful for WYSIWYG output that can use the same coordinates for printing and screen display for instance.
The cartesian coordinates systems available use the corresponding units:
It is also possible to change the origin using the procedure set_origin, which takes a point relative to the default origin.
The class CUSTOM_MAPPING is more flexible and allows both changing the origin and the scale and direction of the axes. The routine set_origin is like in PAGE_MAPPING.
The coordinate system is normally is normally isotropic (squares are square) unless anisotropicis called, influencing the boolean value is_isotropic. The default status is restored with isotropic. For an isotropic mapping, the procedure set_scale is then called to set the axes scaling factor. The parameter is a real number between 0 and 1. In the case of anistropic device, both axes' scaling factors have to be set separately using set_x_scale and set_y_scale.
The graphic mode is used to change the way new graphic operations will be combined with the existing picture. This setting can be changed with the class GRAPHIC_MODE and the graphic device's procedure set_mode.
The default is pen for the new pixel to be the colour of the current pen. inverse_pen does the same with the pen colour inverted -- at the colour bits level. More interestingly, inverse allows to revert the target pixel colour -- the original image can be restored by doing the same operation twice.
The procedures black and white allow to draw in basic colours while ignoring the current pen, and merge is used to combine the current pen and the original colour.
Descendants of the class COLOR describe the logical colours used when drawing on a device.
The colour can be specified as a 24-bit RGB value. Each component (red, green, blue) can take a value between 0 and 255. The procedure to change the colour is rgb. It may not always be possible to display the exact colour on devices which are not able to use enough colours at the same time. Two classes are used depending on how the mapping to the available colours will be done on palettised devices: with RGB_COLOR, the colour is selected from the set of system colours, dithering non-system colours to produce a similar colour, with RGB_PALETTE_COLOR the closest colour in the current palette is selected without dithering. On devices with enough colours to dispense with a palette, the closest or true colour is always chosen.
These two classes also have a set of feature to select the predefined system colours, which should be available most of the time even when the palette is changed, using a set of procedures -- which actually set the default RGB values -- like black or light_grey or normal_red. These methods can also be used as creation procedures.
The classes RGB_COLOR and RGB_PALETTE_COLOR also inherit from P_TEXT_OBJECT and so can be saved to and restored from the registry. The serialised version only includes the bare RGB values so the client code is in charge of restoring the appropriate type.
For direct access to palette colours, on appropriate devices, the class PALETTE_COLOR is used. The index of the required colour is set with set_index -- make_index at creation time. More information on palettes is in section (see section 5.4.7).
Finally, the class STANDARD_COLOR is for colours retrieved from the operating system.
The class PEN is the ancestor for all types of pen that can be selected into a graphic device using set_pen. Some generic features are available in all pens. First, the line colour which is set with set_color and an instance of the COLOR family (see section (see section 5.4.4) for colour classes).
The line style is another common feature. A solid line (set_line_solid), the default, is a plain continuous line. A variant is code set_line_solid_inside_frame for drawing plain lines inside frames for figures such as rectangles -- even a wide line will be drawn inside the figure. The procedure set_line_invisible draws no lines at all, which can be useful to draw filled figures without a border.
A line can also be made of dashes (set_line_dash). Other self explanatory styles are set using set_line_dot, set_line_dash_dot, set_line_dash_dot_dot. These `dots' are not necessarily reduced to a simple pixel or circle.
A geometric pen, class GEOMETRIC_PEN, is a pen whose width can be specified -- with set_width -- in device logical units. It will be scaled appropriately during transformations. It has extra style function to set the way end of lines are drawn (set_end_round and set_end_square and set_end_flat). Other routines apply to the joins of continuous lines (set_join_round and set_join_bevel and set_join_miter). In addition to plain colour, it is also possible to use a brush (section (see section 5.4.6)) to draw lines. A plain solid brush is equivalent to the direct use of a colour, but more sophisticated brushes can also be used to draw lines.
Conversely, a cosmetic pen, class COSMETIC_PEN, is simpler and consequently quicker: the width is always one pixel on all devices. Besides, it has one extra line style: set_line_alternate for lines with only alternate pixels drawn.
A legacy of earlier versions of Windows, the simple pen, class SIMPLE_PEN, is a combination of the above. It supports colour, basic line styles, and its width can be changed. The width is in logical units, unless if it is zero then it is one device pixel. Line style must be invisible or solid (normal or inside frame) for wide (>1) lines.
A simple invisible pen is implemented by the class VOID_PEN, which has no features.
For solid graphic figures such as polygons or filled rectangle, it is necessary to select how the inner area is to be filled. Brushes, descendants of the class BRUSH, are used to that effect. Brushes are effected into a device with set_brush from GRAPHIC_DEVICE.
The simplest form is the class COLOR_BRUSH which takes a colour object with its procedure set_color. Figures will then be filled with this solid colour. Even simpler is the class VOID_BRUSH, the brush version of VOID_PEN, which avoids filling altogether.
The remaining brush is HATCHED_BRUSH is for pattern filling, such as those used in technical drawings. In addition to the colour of the patterns, the hatching style can be selected with the procedures set_hatch_cross and set_hatch_vertical and companions.
On devices like screens which support the display of a restricted number of colours simultaneously, it is necessary to use a colour palette. This colour palette can be changed using the class LOGICAL_PALETTE, an heir to the deferred class PALETTE The only other concrete palette is obtained from the clipboard. accepted by set_palette in the device class.
A logical palette is comparable to an array of colours. The size of the palette is decided at creation time -- it is the parameter of make, the creation procedure. The size of the palette should be smaller than the number of physically available colours, available from DEVICE_CAPABILITIES (section (see section 5.4.1)). The individual colours can be set using the procedure set_color which takes an integer index (included between 1 and size) and an RGB colour. The current colours can be retrieved from the function color.
An important setting is used by for text output (section (see section 5.5.5)), it is the font description. The abstract class is FONT.
The simplest concrete font, in addition to descriptions obtain from system services, is SYSTEM_FONT, an instance of the default font for the given device.
The class LOGICAL_FONT contains a description of a font which can be used to select a real font. If a font matching exactly the description is not available, the selected font will be the one that corresponds most the requirement, according to the system's criteria. The class may also be used to retrieve a font description from the system, in this case the description is read from functions that mirrors the settings procedure presented in this section (face_name corresponding to set_face_name for instance).
This class, LOGICAL_FONT, is an heir to P_TEXT_OBJECT and can consequently be serialised and save, for instance in the registry to save a user font choice.
The most straightforward way to get a given font, is to name it, using set_face_name. This is the family name -- ``Times New Roman'' as opposed to ``Times New Roman Bold Italic'' and it should not contain weight indication. Common Windows installations provide the basic fonts ``Times New Roman'' (serif), ``Arial'' (sans serif, a variant of the common ``Helvetica'') and ``Courier New'' (monospaced typewriter font). These fonts share the same metrics as the standard basic Postscript fonts.
In case the required font is not available, or a given general style of fonts is required, some optional family style attributes may be set, using set_family_swiss, set_family_roman, etc. The procedure reset_family gets back to a neutral choice.
Another major information for a font is its size -- actually its height, though the width of course follows proportionally. It is common to specify font sizes in points, using set_point It is not very natural to do it with the low-level API unfortunately. The implementation details are mentioned in appendix (see section D.3).. A point is a device independent unit from traditional typography, which is equivalent to 1/72 of an inch.
It is also possible to specify -- not concurrently of course -- the size, in logical units of the corresponding device, as the cell height (set_cell_height -- with some blank space above and under the character) or the bare character height (set_character_height).
Optionally, a monospaced font can be requested with set_pitch_fixed. It is also used to check status with is_pitch_fixed Note though that many monospaced TrueType fonts actually report a variable pitch. or is_pitch_variable.
The style specification is optional but still very useful. It includes the weight of the font (Bold, Roman) and the kind of font (Italics or not mainly). The system can either have a separate font from its normal variant or produce automatic variants of the base font. It is not recommended to use automatic variants, which are generally of very poor quality compared to hand-crafted fonts. In typography, a proper italic font is not a skewed version of the roman font.
The weight is specified using the procedure set_weight as an integer value. Default weight value are available as manifest constants, the most common by far are Bold and Normal. The italic status is set using set_italic and reset using reset_style. Part of style is also the underline status, set with set_underline.
An extra style characteristic is set with set_strike_out (and cancelled with reset_strike_out) to have a line drawn on the text output.
A more particular setting is orientation. It is possible to draw rotated text by specifying an angle (in tenth of degrees, from the baseline, anticlockwise) with set_line_orientation. This is for rotating whole lines of text, individual characters may be rotated separately -- of the line orientation, not individually -- using set_character_orientation.
Although it is rarely needed, it is also possible to change the width of the font, which is usually proportional to the height. The procedure set_width takes a parameter which is the required average character width in logical coordinates.
When requesting a font, it is possible to request a specific character set using set_charset_ functions. This are a rather primitive way to handle character sets and it should not be useful very often.
After a device has been prepared and set up, the actual drawing can be done. The classes in this section are heirs of DRAWABLE that can be passed to GRAPHIC_DEVICE's draw procedure for display.
Most of these classes are prefixed with DRAWABLE_ to distinguish them from more abstract geometric concept such as RECTANGLE. It is on purpose, in accordance with the style guideline, that such a class as DRAWABLE_RECTANGLE does take an instance of the geometric RECTANGLE as a client instead of inheriting from it.
These classes usually have a simple creation procedure, make, which sets the default values.
Generally, the classes in this section do not keep references on the parameters of their procedures, so both the instances of heirs to DRAWABLE and their parameters can be safely reused to avoid too many creations of new object instances.
The simplest construct is the straight line, class DRAWABLE_LINE. It is defined by two points, set with set_start and set_final, and makes use of the pen setting for the actual drawing. If the staring and final point are the same, the line is reduced to a point -- which can be drawn on any device unlike DRAWABLE_POINT (section (see section 5.5.6)) which is for raster devices only and works at the pixel level.
An oddity to account for is the fact that the operating system does not draw the first (start) point of the line.
Simple rectangles which can be described by the class RECTANGLE (section (see section 5.2)) are drawn using the class DRAWABLE_RECTANGLE, which takes the corresponding rectangle as a parameter of set_position. Unless the current brush is a void brush, rectangles will be filled. They will similarly have a border unless the current pen is invisible.
The class DRAWABLE_ROUND_RECTANGLE is a variant (and descendant) of DRAWABLE_RECTANGLE for drawing rectangles with a rounded corner. The procedure set_corner takes the width and height of the ellipse used to draw the corner.
Rectangles whose sides are not parallel to the coordinate axes, or more sophisticated polygons, are drawn with the class DRAWABLE_POLYGON, whose ancestor DRAWABLE_POLYLINE draws a set of consecutive line segments without filling. Both classes define the figure with a list of ordered points. Points are added, in order, with add_point. The list of points can be reinitialised using reset. Like a line, the first point of an open polyline is not drawn by the system.
In addition to the points, DRAWABLE_POLYGON has a filling mode: set_filling_mode_winding (the default) and set_filling_mode_alternate as illustrated above.
Although it is possible to approximate curves with a number of small straight lines, the system provides Bezier curves for drawing proper curves. The basic unit of a Bezier curve is a curve defined by four control points: a starting and an ending point, and two anchor points which are used to define how the curve will be drawn. The curve will typically not go through the anchor points.
Like polylines, it is possible to have several pieces of curves in a row with the class DRAWABLE_BEZIER. The ending point of the previous section of curve is the starting point of the new one. Hence, only three new points need be specified to add a new section. The sections of curve will not make a smooth curve unless the programmer takes care of it -- by having the anchors neighbouring the junction in a line with it for instance.
After the initial starting point is set with set_starting_point, curve sections can be added with add_curve which takes the two anchor points and the ending control point. As with DRAWABLE_POLYLINE, the procedure reset initialises the object.
A set of classes is available to draw elliptic figures. First, the class DRAWABLE_ELLIPSE is used to draw simple filled ellipses. An ellipse is defined by a bounding rectangle set with the procedure set_bounding_rectangle. The centre of the ellipse is the centre of this rectangle. There is no specific class to draw circles, a circle is simply an ellipse defined by a square -- at least on isomorphic coordinate systems or devices.
The class DRAWABLE_ARC is for a section of ellipse or circle. In addition to the bounding rectangle defining the ellipse, two radial lines defining the beginning and the end of the arc shall be set using the procedures set_starting_radial and set_ending_radial, which both take a point as argument -- the radial is the line going through this point and the centre of the ellipse. The direction used to go from the starting to the ending radial is selected with set_direction_clockwise and set_direction_anticlockwise.
For filled sections of an ellipse, bounded by the radiant lines and the arc, the class DRAWABLE_PIE is used. It has the same interface as DRAWABLE_ARC.
Finally, the class DRAWABLE_CHORD is for a filled section of ellipse limited by a line, the secant, defined by the staring and ending point of an arc. Its interface is similar to the two previous class but for the secant is defined by the procedure set_starting_secant and set_ending_secant corresponding to their radial counterparts in the arc and pie classes.
Text output is done with the class DRAWABLE_TEXT. The output depends heavily on the current font setting (section (see section 5.4.8)) which defines the font used to draw the individual characters, and related information. This class is used to output single lines of text (contained in an Eiffel STRING) -- operations like paragraph formatting belong to higher level classes. The text to be rendered is specified with the procedure set_text.
An extended version of the basic text drawing class, DRAWABLE_UNICODE_TEXT, allows the output of Unicode text on platforms where it is supported. This class is for use in an 8-bit context -- when CHARACTER is 8-bit wide. Strings of 8-bit characters are converted to Unicode for output, a character map table must be set using set_character_map before the class is used for any text output. The character map is an array of INTEGER which takes the 8-bit character code (from 0 to 255) as an index, and returns the unicode character code as an integer.
Some Eiffel compilers may support Unicode natively, and may be used with the library in full Unicode mode, that is when CHARACTER is 16-bit wide, and other kernel types follow. In this case, all text output can be done in Unicode directly and the Unicode output class is redundant.
In order to choose the position of a piece of text it is often necessary to know how much space it will take, and this depends on the font and device settings. The device object has a specific function text_extent for this purpose. It is similar to draw and takes a DRAWABLE_TEXT object. It returns the bounding rectangle that would enclose the text if the output was done with draw on the same device using the current settings.
A DTP program for instance may apply this function to every word in a paragraph and then decides the interword space necessary and either output each word individually or use the justification facility of the text class, that is adding extra space with set_justification which distributes the extra space between words. It is also possible to add extra space between individual characters using the procedure set_intercharacter_spacing.
The position where the text is to be drawn is specified with set_point which takes a point. This point is by default the top left corner of the output rectangle, but this can be changed using the align_top, align_baseline, align_bottom vertically and align_left, align_center and aligh_right horizontally. For text that uses several fonts or font settings on the same line (eg. a bold word in the middle of a line in roman type) shall use the align_baseline mode for proper results.
Finally, the output colour can be changed with set_color -- the default is black. The text output does not use the current pen, or the current brush. All text output is normally transparent: only the outline of the characters is drawn and the space between characters is left untouched. If the background needs an update, the normal graphics classes, such as rectangles, can be used before the text is drawn.
Alternatively, it is possible to specify a background area -- using set_area -- which is going to be filled with the background colour before the text is drawn. This is especially useful if the text needs to be frequently updated, like it is for instance in a text editor, to avoid an unpleasant graphical effect due to erasing the background and drawing the text separately.
The background colour used in this case is set during the function set_background_color of GRAPHIC_DEVICE and is not related with the current brush.
Some operations working at the pixel level may only be done on raster devices -- such as screens.
The class DRAWABLE_POINT is used to change the colour of individual pixels. The pixel is selected with the procedure set_position -- still in logical coordinates -- and set_color is used for the new colour of the pixel. The class does not use the current pen.
The class DRAWABLE_FLOODFILL allows to fill an area delimited by a colour boundary with the current brush. The starting point of the fill is set with set_position and the colour defining the boundary using set_color. If the mode is set_mode_border, the default, the surface until a border of the given colour is filled. With set_mode_surface every point being of the boundary colour and adjacent to the starting point will be repainted.
In addition to these, another raster operation is the handling of bitmaps which was described in section (see section 5.3.5) about bitmap devices, because BITMAP_DEVICE is also polymorphically DRAWABLE.
Section (see section 5.3.4) explained how to draw to metafiles, this one is about how to draw from metafiles. The class DRAWABLE_CLIP_METAFILE is for metafiles which are retrieved through the clipboard (see section (see section 3.8) on the clipboard). The only procedure is set_rectangle to define the rectangle into which the metafile will be displayed -- a bounding rectangle was defined when drawing into the metafile.
Metafiles which are stored in real .EMF files are retrieved using the class DRAWABLE_METAFILE which, in addition to the target rectangle, has a procedure set_file_name for the file name (the extension should be specified explicitly -- .EMF is just a convention).
An icon is generally retrieved from the resource section of the executable, by creating it with the procedure make_resource. It can then be drawn on a device after its position has been set with set_position, which takes the point where in the device coordinate space the upper-left corner of the icon will be.
The class GRAPHICS_ROUTINES, a mix-in class without a state, contains some useful functions to simplify commonly used sequences of operations.
The functions void_pen and void_brush and color_pen and color_brush return basic pens or brushes, corresponding to solid lines and brushes associated with a colour for the latter.
The result of these functions can be used directly with for instance the procedure set_pen of a graphic device. Alternatively, the routines set_pen and set_brush from GRAPHICS_ROUTINES take a device and a colour to set these parameters directly without having to handle a pen or brush object.
The functions device_to_logical_size and its opposite number logical_to_device_size are used to convert dimensions (width and height stored in a point object) independently of the origin of the logical and device coordinate system -- it would be a problem when the origin is not the same point in both spaces.