Programming Guide:xppguide

Output to window and printer - WYSIWYG Foundation

A presentation space contains all device-independent information of a drawing. It can be linked to different output devices and therefore, a drawing can be displayed in a window or output to a printer. Depending on the device context a presentation space is linked to, printer output can be previewed in a window. In order to comply with the WYSIWYG rule (What You See Is What You Get), a drawing must be displayed in the window in correct scale. The proportions of a drawing displayed in a window must be the same as on paper after printing.

Displaying printer output in a window in correct scale involves three different levels of abstraction: one presentation space and device contexts for both window and printer. In addition, the device contexts for the two output devices have different units of measurement for their coordinate system. A window displays a drawing based on pixel while a printer uses units of 1/10th of a millimeter.

Previewing printer output in a window

This illustration is based on the example program PREVIEW.PRG. It demonstrates various aspects for correctly scaled output on different devices. The program lists database records in a window and can print them. The contents of database fields are drawn with the function GraStringAt().

On the left of the illustration, the application window is shown which is created by the example program. Database records are displayed in this window by an instance of the user-defined XbpPreview class, implemented in the example program. Its size is 270 x 380 pixel. On the right side of the XbpPreview object, there are pushbuttons that enlarge (zoom ++), reduce (zoom --) or print the display. If the display is enlarged, it can be scrolled by means of two scroll bars. The XbpPreview object provides the device context for screen output (window device).

A sheet of paper is shown on the right of the illustration. It represents printed output (the printer device) and has A4 format. This means its size is 2100 x 2970 units, one unit being 1/10th of a millimeter.

Between window device and printer device, a presentation space is displayed. Depending on the device context this presentation space is linked to, the output appears either in the window or on paper. The different aspects resulting from WYSIWYG display are demonstrated in PREVIEW.PRG.

Scaling

An automatic scaling of the drawing and the transformation of the coordinate systems of both output devices is done by the presentation space. It defines unit and size of the coordinate system. For printed output, the coordinate system must be dimensioned according to the paper size. It can be determined with the :paperSize() method of an XbpPrinter object. This method returns an array containing the size of a sheet of paper in 1/10th mm units. For some printers, especially laser printers, the size must be adjusted since there are margins that cannot be printed on.

Printer coordinates are used for drawing in the presentation space. This means that the page size of the presentation space is identical to the printable area on a sheet of paper. In order to display the complete page of the presentation space in the window, the viewport must be set to the window's size. In this case, window coordinates are used (pixel). If page size and viewport are dimensioned properly, all graphic output drawn at printer coordinates appears in correct scale in a window.

In addition to viewport and page size, it is necessary to select a vector font in the presentation space. This is required for correct scaling of text since bitmap fonts cannot be scaled. Therefore, a presentation space must be prepared in several steps to achieve a WYSIWYG preview of printed output. These steps are discussed in the following code.

It is assumed that the variable oPrinter references an XbpPrinter object and oWindow references an Xbase Part:

// Determine page size 
aSize := oPrinter:paperSize() 

// Deduct margins that cannot be printed on 
aSize := { aSize[5]-aSize[3], aSize[6]-aSize[4] } 

// Link presentation space with window device context 
// but use printer coordinates and units 
oPresSpace := XbpPresSpace():new() 
oPresSpace:create( oWindow:winDevice(), ; 
                   aSize              , ; 
                   GRA_PU_LOMETRIC      ) 

// Set viewport to the size of the window 
aSize := oWindow:currentSize() 
oPresSpace:setViewPort( {0, 0, aSize[1], aSize[2] } ) 

// Select vector font for presentation space 
oFont            := XbpFont():new( oPresSpace ) 
oFont:familyName := "Helvetica" 
oFont:nominalPointSize := 12 
oFont:create() 
oPresSpace:setFont( oFont ) 

When a presentation space is prepared in this way, Gra..() functions can be used to produce graphic output. Display in the window then corresponds to printed output and appears in correct scale. However, screen output is extremely reduced in size compared to printed output.

Zooming

If details of a print preview are to be checked, the display in the window must be enlarged (zoomed). This is achieved by enlarging the viewport of the presentation space. In this case, only a part of the viewport is visible in the window. Assume the following code:

// Get current viewport size (e.g. { 0, 0, 270, 380 } ) 
aViewPort := oPresSpace:setViewPort() 

// Double height and width of the viewport 
// Its size is now 540 x 760 pixel 
aViewPort[3] *= 2 
aViewPort[4] *= 2 

// Set new viewport in presentation space 
oPresSpace:setViewPort( aViewPort ) 

The window is assumed to be 270 pixel wide and 380 pixel high. If the viewport is enlarged to double width and height (540 x 760 pixel), the window displays only the lower left quarter of the viewport. Since the window's size is unchanged, only one-quarter is displayed instead of the entire drawing. This part of the drawing appears four times enlarged.

Scrolling

As soon as the viewport is larger than the window, only a part of a drawing is visible and the rest is clipped. To see different parts of the drawing, it must be scrolled inside the window. Scrolling is done by changing the origin of the viewport relative to a window's origin. The origin of the viewport is set to negative coordinates:

// Get current viewport size (e.g. { 0, 0, 540, 760 } ) 
aViewPort := oPresSpace:setViewPort() 
aViewPort[1] -= 270 
aViewPort[2] -= 380 
aViewPort[3] -= 270 
aViewPort[4] -= 380 

oPresSpace:setViewPort( aViewPort ) 

In this example, the viewport of the size 540 x 760 pixel is set to the coordinates {-270,-380,270,380}. This is relative to the point {0,0} in the window. The viewport origin has moved down left while its size is unchanged. As a result, the upper right part of the drawing becomes visible in the window.

If the viewport origin is set to negative coordinates, all parts of an enlarged drawing can be viewed in a window. In the PREVIEW.PRG example program, this is accomplished by using two scroll bars so that the drawing can be scrolled with mouse clicks.

Printing

When a presentation space is created using printer coordinates, a drawing visible on screen can be printed easily by exchanging the device context of the presentation space. For printing, an XbpPrinter object is used as device context and the drawing must be redisplayed for appearance on paper. The following steps are necessary to print a drawing:

// Save current viewport 
aViewPort := oPresSpace:setViewPort() 

// Link presentation space with printer device 
oPresSpace:configure( oPrinter ) 

// Open the spooler 
oPrinter:startDoc() 

// Redisplay the drawing 
Gra..( oPresSpace ) 

// Close the spooler 
oPrinter:endDoc() 

// Link presentation space to window device 
oPresSpace:configure( oWindow:winDevice() ) 

// Reset viewport for window 
oPresSpace:setViewPort( aViewPort ) 

The device context is exchanged by passing a corresponding object to the :configure() method of the presentation space. This switches graphic output from screen to the printer. Since the viewport is lost when devices are changed, it must be saved and reset.

Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.