GRAPHICS_CONTEXT DISPLAY_GRAPHICS_CONTEXT PRINTER_GRAPHICS_CONTEXT MEMORY_GRAPHICS_CONTEXT GDI_RESOURCE PEN BRUSH FONT COLOR
When your applications want to paint some images, graphic figures or print out some text information then according to the Windows Graphic Device Interface (GDI) ideology it should use Graphics Context. Graphics Context (GC) is an abstract "paper sheet" corresponding to a window area in your program. Also you have drawing tools: pens, brushes and fonts. All you need is to select a desired tool and using it draw on GC.
First of all we must introduce class COLOR.
By default Windows defines a color as a combination of three primary colors - red, green, and blue. Windows identifies a color by giving values that identify how much red, green, and blue the color has. Such values are known as RGB values (red, green, blue) and consist of three integer values specifying the intensities of the three components. Range of each value is from 0 to 255. Black has the minimum intensity for red, green, and blue, so the RGB value for black is (0,0,0). White has the maximum intensity for red, green, and blue, so its value is (255, 255, 255). The following code shows how to create a color object in GRAPE. It's simple - define a color object and use its creation procedure to specify its RGB-color, later, during the object life, you also can change this color - simply use the creation feature again.
red, dark_green, yellow, brown : color ... -- call colors creation procedure -- with red component value 255 !!red.make_rgb (255,0,0) -- now make dark green color -- with green component value 128 !!dark_green.make_rgb (0,128,0) -- Now a bit difficult - yellow color -- yellow is red plus green !!yellow.make_rgb (255,255,0) -- and brown is dark red plus dark green !!brown.make_rgb (128,128,0) ...
You can use the powerful RGB color mechanism to specify about 16 millions of colors (actually the number of available pure colors depends on the current video-mode of your videocard) but of course with GRAPE you do not need to take in mind that, e.g. purple is RGB(128,0,128). You can simple use proper creation procedure - !!c.make_purple(). All basic colors have the same names for the creation procedures.
Also you can specify the system color as a color of you objects. The system color is a color of control elements in Windows such as colors of button's background, window titles, etc. For more information see Appendix A.
Next we give a brief GDI resource tour. For detailed information please see our On-Line Help Reference. In GRAPE there are three basic resources Pen, Brush and Font.
A pen is a graphics tool used to draw lines and curves. Drawing applications use pens to draw freehand lines, straight lines, and curves. There are three pen attributes that define the type of the pen and its characteristics: width, style, color. It is specified in the pen creation procedure.
pen.make ( style : INTEGER, weight : INTEGER, pencolor : COLOR )
The first parameter determines the pen style. GRAPE provides the following pen styles (it corresponds to the styles in the Windows GDI). Here are gray rectangles framed with different style's borders.
Figure 6.1 Pen styles.
NULL_PEN - specifies the pen used with filled painting features when you want to paint figures without border.
The second parameter determines the pen weight. Weight is specified in pixels (unit corresponding to a dot on the screen). You can specify any reasonable positive integer value. GRAPE class PEN provides two integer constants NORMAL_WIDTH and THICK_WIDTH setting the pen pixel's weight 1 and 3 respectively. In Appendix C we describe how to define the pen weight in device independent units (e.g. in millimeters)
The third parameter determines the pen's color.
Here is a simple example defining and creating two pens (red and black are color objects defined somewhere else):
red_pen, black_dot_pen : PEN; ... !!red_pen.make (red_pen.SOLID_PEN, black_pen.NORMAL_WIDTH, red ); !!black_dot_pen.make (black_dot_pen.DOT_PEN, 5, black ); ...
Brush is a graphics tool to paint the interior of shapes (polygons, ellipses, etc.).
There are three types of logical brushes (solid, hatch, and pattern) as it's shown at the following illustration.
Figure 6.2 Brush styles.
The brush style specified by the creation procedure:
!!p1.make_solid ( Blue ); !!p2.make_hatched ( p2.DIAGONAL_HATCH, Red ); !!p3.make_pattern ( pattern_picture );
Class FONT provides basic tools for operating Windows fonts. Fonts are used to drawing text with different styles. In Windows, a font is a collection of characters and symbols sharing a common design. To draw something with a particular font you should select it into the graphics context.
There are two creation procedures make and make_default. The first feature make creates a font with the default parameters. Normally it is the standard platform's font. To create a specific font object a programmer should set the appropriate font attributes after calling these creation features. Fortunately you can use make_default's fonts if you too lazy to specify the particular fonts' attributes. The latter feature creates one of the standard platform's fonts (normal or small).
In Windows, the size of a font is an imprecise value. It can generally be determined by measuring the distance from the bottom of a lowercase "g" to the top of an adjacent uppercase "M," as shown in the following illustration.
A font's size is specified in units called points. A point is 0.013837 of an inch. Following the point system devised by Pierre Simon Fournier, it is common practice to approximate a point as 1/72 inch.
Class FONT contains integer attribute height that keeps the font's size and following feature is used to set the desired height of the font.
set_height ( h : INTEGER )
Note Character width is calculated automatically when you specify a new character height. You can obtain it by calling get_font_average_char_width() and get_font_max_char_width() for GRAPHICS_CONTEXT objects. Please refer to our On-Line Reference or wait a bit till you finds it later in this chapter.
The term style refers to the weight and slant of a font.
Class FONT provides a set of features that trigger available styles for the current font object.
set_bold ( val : BOOLEAN ) set_italic ( val : BOOLEAN ) set_underline ( val : BOOLEAN ) set_strike_out ( val : BOOLEAN )
When all the styles are "turned off" we have default normal font style:
Normal | |
set_bold ( true ) | Bold |
set_italic ( true ) | Italic |
set_underline ( true ) | Underline |
set_strike_out ( true ) |
For example, the following code combines Underline Bold Italic Font:
fnt : FONT; ... !!f.make (); fnt.set_bold ( true ); fnt.set_italic ( true ); fnt.set_underline ( true );
Windows organizes fonts by their family; a family is a set of fonts having the same stroke width and serif characteristics. Windows categorizes families with five family names. The second name DONTCARE allows an application to use the default font.
The following table describes the names of the font families.
Font-family name | Description |
DECORATIVE | Specifies a novelty font. An example is Old English. |
DONTCARE | Specifies a generic family name. This name is used when information about a font does not exist or does not matter. |
MODERN | Specifies a monospace font with or without serifs. Monospace fonts are usually modern; examples include Pica, Elite, and Courier New®. |
ROMAN | Specifies a proportional font with serifs e.g. Times New Roman |
SCRIPT | Specifies a font that is designed to look like handwriting; examples include Script and Cursive. |
SWISS | Specifies a proportional font without serifs. An example is Arial. |
To specify font family class FONT provides feature set_family that takes as a parameter one of the family's constants from the table above. For example:
fnt.set_family ( ROMAN )
You can also directly specify a font's typeface name. For example "Arial" or "MS Sans Serif."
Use feature set_face_name:
fnt.set_face_name ( "Arial" );
To specify the font color use set_color feature.
!!c.make_blue; fnt.set_color ( c );
Also as one of the font's attributes you can specify the angle between X-axis and the font base line. Feature set_escapement takes angles in 0.1 degree units.
fnt.set_face_name ( "Arial" ); fnt.set_escapement ( 450 );
Note Escapement is available not for all fonts. Usually it's available when the selected font is a TrueType® font.
For complete example how different font attributes affect their visual presentations see FONTVIEW samples from GRAPE's EXAMPLES directory.
Figure 6.3 The FONTDEMO example.
Now it's time to introduce the main topic of the chapter GRAPHICS_CONTEXT (GC). This class is deferred and provides the basic device-independent painting features. In this chapter we also consider all the features of the class.
Before painting or setting anything with using GC you must initialize a graphics device context by establishing a link to the target output device. There are two features begin_paint and end_paint that perform this low level service. Every request to the graphics engine is valid only if it occurs between the calls of the begin_paint and end_paint feature. Only calls affecting the state of the graphics context are allowed outside these feature calls.
dgc.begin_paint; ... painting on dgc ... dgc.end_paint;
Now return to the resource tools discussed at the beginning of this chapter. To paint using your own resource object you must select it. GC has four features to do it - one universal and three explicit ones:
select_resource ( resource : GDI_RESOURCE ) : GDI_RESOURCE select_pen ( a_pen : PEN ) select_brush ( a_brush : BRUSH ) select_font ( a_font : FONT )
Graphics context has its own resource tools selected by default (e.g. the normal width black pen, solid white brush, system fixed font ) used when you don't specify your own ones.
There are two groups of painting features draw_xxx and paint_xxx. The first group draws outline primitives using the selected pen object. The second group paints filled primitives using the selected pen and brush.
Here we consider only the small amount of primitives available in class GRAPHICS_CONTEXT.
For the complete list please refer to our On-Line Help Reference.
draw_point ( x, y : REAL, a_color : COLOR )
Draw a point using given color.
draw_line ( x1, y1, x2, y2 : REAL)
Draw a line using the current pen. It's the fast equivalent to the following pair move_to (x1, y1) and line_to (x2, y2).
draw_rectangle ( x1, y1, x2, y2 : REAL ) paint_rectangle ( x1, y1, x2, y2 : REAL )
Draw a rectangle using the current pen. In addition to drawing the second feature fills the rectangle by the current brush.
draw_circle ( xc, yc, radius : REAL ) paint_circle ( xc, yc, radius : REAL )
Draw a circle using the current pen. In addition to drawing the second feature fills the circle by the current brush.
Now we can present an example demonstrating all discussed above. This is only a piece of the code: the on_paint feature. The full code you can find in the \EXAMPLES\DRAW\DEMO1.E file.
on_paint : INTEGER is -- paint red square with black frame local dgc : DISPLAY_GRAPHICS_CONTEXT; blackpen : PEN; redbrush : BRUSH; c : color; do !! c.make_red; !!redbrush.make_solid (c); !!c.make_black; !!blackpen.make( blackpen.SOLID_PEN, 1, c ); !!dgc.make_with_assignment ( Current ); -- window object dgc.begin_paint; dgc.select_pen (blackpen); dgc.select_brush (redbrush); dgc.paint_rectangle (10,10,90,90); dgc.end_paint; Result := processed; end; -- on_paint
You perhaps note in the example above that we introduced a new class DISPLAY_GRAPHICS_CONTEXT (DGC). When you are outputting your drawing on a computer's display there are a lot of other Windows applications which may share the entire screen with you. One of the principals is that each application must use its own window (or windows) for information output. In GRAPE it means that you must assign a target tile object to a display device context.
There are two way of assigning target TILE to the DISPLAY_GRAPHICS_ CONTEXT. To use the creation procedure make_with_assignment or to call feature assign_target_tile before any operation on DGC. You can assign the same tile for several DGC objects.
Usually an application draws something during the on_paint callback feature (see the chapter dedicated to callbacks). Fortunately you may draw not only inside on_paint but always keep in mind one important restriction - the target tile must be initialized and now you should understand why painting inside the features of TILE such as make, on_create raise exception "tile wasn't initialized".
There is a list of features used for printing a text.
put_character ( c : CHARACTER, x, y : REAL )
Output a single character string at the specified position using the font currently selected.
put_string ( s : STRING, x, y : REAL )
Output a character string at the specified position using the font selected.
put_string_clipping ( s : STRING, tx, ty, x, y, w, h : REAL )
Output a character string at the specified position clipping the string to the specified rectangular area.
fill_with_string ( s : STRING, x, y, width : REAL )
Fill the specified width with the line of some text. Character spacing will be adjusted automatically to the width specified.
put_text ( s : STRING; x, y : REAL)
Put some text. The output can occupy several lines.
put_text_cliping ( s : STRING; x, y, w, h : REAL; ha, va : INTEGER )
Put lines of some text into a clipping rectangle with the specified alignment.
You can align any output text vertically and horizontally using the following alignment features.
set_horizontal_text_alignment ( hcode : INTEGER ) get_horizontal_text_alignment : INTEGER
Where hcode is one of the following:
TA_LEFT | Aligns the drawing point with the left side of the bounding rectangle. This is a default setting |
TA_CENTER | Aligns the drawing point with the horizontal center of the bounding rectangle |
TA_RIGHT | Aligns the drawing point with the right side of the bounding rectangle. |
set_vertical_text_alignment ( vcode : INTEGER ) get_vertical_text_alignment : INTEGER
Where vcode is one of the following:
TA_TOP | Aligns the drawing point with the top of the bounding rectangle. This is a default setting. |
TA_BASELINE | Aligns the drawing point with the baseline of chosen font. |
TA_BOTTOM | Aligns the drawing point with the bottom of the bounding rectangle. |
There are a lot of features provided by class DISPLAY_GRAPHICS_CONTEXT that are used to obtain different font characteristics. Here we include only a list of them. For more information on each feature please look at our On-Line Help Reference.
get_font_face_name : STRING get_font_cell_height : REAL get_font_ascent : REAL get_font_descent : REAL get_font_external_leading : REAL get_font_average_char_width : REAL get_font_max_char_width : REAL get_font_default_char : INTEGER get_font_break_char : INTEGER get_intercharacter_spacing : REAL measure_char_width ( char : CHARACTER ) : REAL measure_text_width ( s : STRING ) : REAL measure_text_height ( s : STRING ) : REAL
The drawing mode defines how foreground colors are being mixed with the existing screen colors for pen, brush, picture and text objects. There are two features dealt with the drawing mode: get_draw_mode and set_draw_mode. They are simple. In GRAPE there are sixteen different modes shown in following table.
Mode |
Effect |
ROP_CLEAR | dest := always black color |
ROP_AND | dest := src AND dest |
ROP_AND_REVERSE | dest := src AND ( NOT dest) |
ROP_COPY | dest := src (* This is default mode) |
ROP_AND_INVERTED | dest := (NOT src) AND dest |
ROP_NOOP | dest := dest (* painting "ignored") |
ROP_XOR | dest := src XOR dest |
ROP_OR | dest := src OR dest |
ROP_NOR | dest := (NOT src) AND (NOT dest) |
ROP_EQUIV | dest := (NOT src) XOR dest |
ROP_INVERT | dest := NOT dest |
ROP_OR_REVERSE | dest := src OR (NOT dest) |
ROP_COPY_INVERTED | dest := NOT src |
ROP_OR_INVERTED | dest := (NOT src) OR dest |
ROP_NAND | dest := (NOT src) OR (NOT dest) |
ROP_SET | dest := always white color |
Next we include an example how this mode affects painting. This is only a piece of the code - the on_paint feature. You can find the complete example in the \EXAMPLES\DRAW\DEMO2.E file.
on_paint : INTEGER is local i : INTEGER; do dgc.begin_paint; from i := dgc.ROP_CLEAR until i > dgc.ROP_SET loop dgc.set_draw_mode (i); dgc.select_brush (greenbrush); dgc.paint_rectangle ( 0, i*20, 35, i*20+14); dgc.select_brush (redbrush); dgc.paint_rectangle ( 5, i*25, 40, i*20+19); i := i + 1; end -- loop Result := processed; end;
The background mode defines how background colors are being mixed with the existing screen colors for picture and text operations. There are two features dealt with the background mode: get_background_mode and set_background_ mode.
Mode | Effect |
OPAQUE_BACKGROUND | Background is filled with the current background color before the text, hatched brush, or pen is drawn. |
TRANSPARENT_BACKGROUND | Background remains untouched |
For example, we set the window background to the gray color. Suppose that this code is executing for a window object:
!!c.make_gray; set_image_background ( c );
Now if you draw any text it will clip white rectangles - each character erases background around itself. By default the OPAQUE_BACKGROUND mode is selected.
dgc.draw_text ( "aBcD", 10, 10 );
To draw a text with the untouched background set the TRANSPARENT_ BACKGROUND mode.
dgc.set_background_mode ( dgc.TRANSPARENT_BACKGROUND ); dgc.draw_text ( "aBcD", 10, 30 );
GRAPE has a special class called PICTURE that
represents a bitmap picture object. There are three possibilities:
There is a special feature in class CRAPHICS_CONTEXT to display a picture object on GC.
put_picture ( p : PICTURE, x, y : REAL )
For example the following code displays bitmap file CLOUDS.BMP .
p : PICTURE ... !!p.make ("CLOUDS.BMP"); ... dgc.begin_paint; dgc.put_picture (p,0,0); ...
GRAPE has special class ICON that represents an icon object. There are two possibilities:
There is a special feature in class DISPLAY_CRAPHICS_ CONTEXT to paint a icon object on DGC.
put_icon ( ico : ICON, x, y : REAL )
The following code displays one of the predefined icons.
m_icon : ICON ... !!m_icon.make ( m_icon.OPENED_BOOK_ICON ); ... dgc.begin_paint; dgc.put_icon ( m_icon, 10, 10 ); ...
Suppose you have a painting feature that changes the current pen and brush for GC or sets some exotic drawing mode, etc. Before this feature has been finished you need to restore the state of GC - otherwise in the other features painting on the same CG you need explicitly select the painting resources before painting anything. There is another simple way how to do it. You can save the state of GC, perform any operations on it, and restore it to the original state. Class GRAPHICS_CONTEXT provides two procedures save_gc and restore_gc that perform this job for you.
dgc.save_gc ... dgc.set_draw_mode () -- some other operations ... dgc.restore_gc
When you are saving GC its contents is pushed into a small stack thus, pairs save_gc ... restore_gc can be nested. Don't forget to pop the elements from this stack - beware of possible stack overflowing.