Back to Contents        Previous        Next





22. Printing

Dr Wimp provides comprehensive facilities for you to print via the standard RiscOS printer drivers. These make the programming for printing very much simpler - but you still need to have a fairly good grasp of how to use DrWimp before you ‘boldly go’.

As there a quite a bit to set up before the printing actually starts - and nothing can be tested until its mostly all done - it is not practicable to have a step-by-step tutorial for this section. However there is a pretty comprehensive example application in the Examples folder. Further, at the end of this section, there is a suggested sequence for practical programming. ( .... and “Dr Wimp’s Surgery” covers printing in more detail.)

General points
Dr Wimp provides two methods of printing and which you choose depends on the application - and there is no reason why you can’t use both methods for different purposes within the same application.

If you want to print out what is being shown in a window which has all been written/drawn in PROCuser_redraw, then you would normally use what we will call the ‘redraw method’ (which is, essentially, ’wysiwyg’).

If on the other hand you want to print out something that is independent of the display, then you do all the work in a user-function PROCuser_print. We will call this latter the ‘user method’.

(Note that there is a PROCuser_print, a FNuser_printing and a PROCwimp_print. Don’t mix them up!)

With either method, the main workload involved is coordinate conversion between screen/work area and paper. This is fairly straightforward with the wimp-functions provided, but it needs a methodical approach.

DrWimp also provides facilities to find out about the paper size, the printer driver and a means for the application to tell the user what is going on and giving them the option to cancel the printing.

Also, with Dr Wimp’s introduction of scaling for outline fonts, it becomes much easier to offer a ‘Print preview’ option in your applications.

Early checks and setting-up
The first thing your application needs to do is have some sort of 'Printing choices' window (or menu) where the user can specify the range of pages to print, how many to fit onto a page and the number of copies to print etc. As a bare minimum, a simple ‘Print’ button will suffice.

Another early check needed is to ascertain that a printer driver is loaded, otherwise your application will produce errors and probably quit. For example, using:

loaded%=FNwimp_pdriverpresent

will result in loaded% being TRUE (-1) if a printer driver is loaded, or FALSE (0) if not. (Note the difference from the usual Dr Wimp practice of returning 1 or 0.)


This isn’t the end of printer driver checking though. Remember that users can load, change and quit printer drivers at any time whilst your application is running. So it needs to be checked continually and Dr Wimp has a user-function to do just this. It is PROCuser_printerchange and it is automatically called any time the status of the printer driver changes. Thus you can fill this user-function with routines to react as you wish when it is called. For instance, you could check if a driver is still loaded, show its name, and enable/disable icons accordingly e.g. to prevent a ‘Print’ button from being pressed if no driver is present and/or to show different print margins.


A common practice is to put the name of the current printer in the titlebar of the 'Printing choices' window. So, for example you could use:

loaded%=FNwimp_pdriverpresent
IF loaded%=TRUE THEN
         printername$=FNwimp_getpdrivername
         PROCwimp_putwindowtitle(print%,printername$)
ELSE
         PROCwimp_putwindowtitle(print%,"No printer loaded")
ENDIF

with print% being the handle of your 'Printing choices' window. Its easy to see that in the above IF..ELSE..ENDIF structure you can enable and disable icons in the print window depending on whether the printer driver was loaded or not.

Paper size and printing borders
If you wish you can also get information about the paper size and the printer borders (i.e. the areas in which you can't print). With this you could, for example, draw grey and white rectangles in a 'Printing choices' window to depict the page and its borders. But be careful not to try and get any information about the page unless a printer driver is loaded!

As a very brief example, here is a sample piece of code that could go in PROCuser_redraw for a 'Printing choices' window (assuming its auto redraw flag is not set):


IF window%=print% THEN
         IF
FNwimp_pdriverpresent=TRUE THEN
         w%=
FNwimp_getpapersize(0,0)
         h%=FNwimp_getpapersize(1,0)
         IF h%>=w% THEN scale=h%/120
         IF w%>h% THEN scale=w%/120
         w=w%/scale
         h=h%/scale
        
PROCwimp_setcolour(160,160,160,0)
                  PROCwimp_plotwindowrectangle(print%,0,-h,w,h,1)
         lm=FNwimp_getpapersize(0,1)/scale
         r=FNwimp_getpapersize(0,3)/scale
         bm=FNwimp_getpapersize(1,1)/scale
         t=FNwimp_getpapersize(1,3)/scale
         PROCwimp_setcolour(255,255,255,0)
         PROCwimp_plotwindowrectangle(print%,lm,-h+bm,r-lm,t-bm,1)
         ENDIF
ENDIF

which will draw in the window a small depiction of the paper with its printing borders.


We haven’t finished with the 'Printing choices' window quite yet!

Currently DrWimp supports printing ranges of pages, multiple copies and fitting one, two or four A4 pages onto a single physical A4 page, so these are further options you can provide in your print window. For an example see the template file “Print” in the Tutorials folder.


Further, as was said before, at any time the user could change the current printer, and then PROCuser_printerchange will be called automatically. When it is, you would check to see if the printer driver is still loaded, and update all your page measurements, what icons to enable and disable in the print window etc. Basically do all your checks again just as if the print window was being opened for the first time.



Catering for Postscript printers
If you are printing with outline fonts, which is probably very likely, then there is one more preparatory consideration to take into account. The users of your application may be using Postscript printers and therefore it becomes a sensible precaution to ‘declare’ all outline fonts that are going to be used - before you use them in printing.

This is done in the user-function PROCuser_declarefonts by using, as appropriate, PROCwimp_declarefont(), PROCwimp_declarefonth() and PROCwimp_declaredfilefonts() - the latter only if drawfiles are to be printed.

Initiating the printing
Once you have everything set up you are ready to print and, for either method of printing, one wimp-function initiates it.

PROCwimp_print(user%,window%,fpage%,lpage%,persheet%,interval%, copies%,orient%,xscale,yscale,order%,invert%)

Setting the parameter user% to 0 prints using the redraw method and setting it to 1 prints using the user method. Both of these will be discussed in more detail later, but an initial look at the parameters of PROCwimp_print will be helpful.

If using the redraw method then window% is the handle of the redraw window. In other words the window whose contents you want to print out (wysiwyg). The value in the parameter window% is ignored if printing with the user method (i.e. when user%=1) - but a value must be present, of course, and 0 will be acceptable.

fpage% and lpage% are the page numbers of the first page to print and the last page, respectively. These are inclusive, and it doesn’t really matter to DrWimp what they are as long as lpage% is equal to or larger than fpage%. The numbers you specify for the range of pages are arbitrary as far as DrWimp is concerned, as the whole range of page numbers will be returned to you one by one as you are requested to print each page.

persheet% can currently be either 1, 2, or 4. If you set it to 1 then each ‘page’ to be printed will be printed normally on 1 sheet of the printer-configured paper (usually an A4 sheet). If you specify 2 then two ‘pages’ will be scaled to about 70%, rotated through 90 degrees, and placed side by side on a single sheet of paper. If you specify 4 then each ‘page’ will be scaled to 50% and four pages will be printed on a single sheet of paper. All this is done automatically and the printing process as far as you are concerned is exactly the same - only the actual output is affected.

interval% allows pages in a print sequence to be skipped - for example, to allow only odd/even pages to be printed. If interval%=1 it means that every page will be printed. Setting it to 2 means every other page, etc.

copies% is the number of copies to print. For example if you want to print from page 1 to 4, with two copies, then eight pages will be printing, two lots of four. The number of physical pages printed depends on persheet% though.

orient% specifies the orientation of the paper. If orient%=0 then the paper is portrait, but if you set orient% to 1 then the paper will be treated as landscape. The orientation parameter is also required when converting to and from paper coordinates, as the orientation of the paper affects where the work area and screen coordinates translate to on the paper.

xscale and yscale allow the printed output to be scaled. A value of 1 means ‘no scaling’ i.e. 100% - with values less than 1 being a reduction in size and values greater than 1 being an enlargement. (There is an arbitrary lower limit of 0.05 for both values.)

order% applies only when persheet% is 2 or 4 and allows the position of each ‘page’ on the sheet to be changed. When order% is 0 (the normal setting) the position of the ‘pages’ is as follows:


When persheet%=2

Picture Pics/pic010.png

and when persheet%=4

Picture Pics/pic011.png

However, if order% is set to 1 then the positions become:

When persheet%=2

Picture Pics/pic012.png

and when persheet%=4

Picture Pics/pic013.png

Finally, if invert% is set to 1 the output ‘page’ will be printed upside down on the paper sheet. Please note that if persheet% is 2 or 4 then the inverting will apply to each ‘page’ individually rather than to the printed sheet as a whole.

(When persheet% is 2 the effect of setting invert% to 1 will be effectively the same as setting order% to 1 - apart from any printing margin differences.)

Progress of the printing job
During printing you may wish to keep the user informed of the progress of the printing and give them the option to cancel. This is achieved using FNuser_printing which is repeatedly called automatically by Dr Wimp. From its parameters you can read the current copy being printed, the current page number, the total number of pages that are being printed, and the current page being printed (from one to the total number). The return from this user-function is used to tell Dr Wimp whether to continue with the printing or not - see below.

From the total number of pages and the current page being printed, you could calculate the percentage of pages already printed and display a progress bar using PROCwimp_bar. You could also display the current copy and current page out of interest.

Finally, in the progress window you could add a ‘cancel’ button, and when it is clicked on you set a global variable to indicate that the user wishes to cancel printing. Then, when FNuser_printing is next called, you look at the variable and return a 1 if the printing is to be cancelled. Otherwise you return a 0.

Here is an example of the sort of thing you might put into this user-function:

DEF FNuser_printing(copy%,page%,totpages%,pagepos%)
PROCwimp_puticontext(progress%,0,“Printing page”+STR$(page%)+ “(copy ”+STR$(copy%)+“)”)
PROCwimp_bar(progress%,2,(pagepos%/totpages%)*466,0)
=cancel%

In this example, progress% is the handle to the progress window, the progress bar is icon number 2, which is 466 OS units long, and icon 0 is just a text icon to display information.

cancel%, a global variable, would be set to 0 just before PROCwimp_print is called, and in PROCuser_mouseclick there would be a line like the following:

IF window%=prog% AND icon%=4 THEN cancel%=1

where icon 4 is the cancel button. FNuser_printing can then simply return cancel% to indicate if printing is to be cancelled or not.

Here are a couple of further examples to help you understand the difference between page% and pagepos%:

Say the user wanted to print pages 2 to 8, one copy. Then, as printing progresses, copy% will stay at 1, page% will start at 2 and increase to 8, totpages% will stay at 7 (printing pages 2 to 8 inclusive), and pagepos% will start at 1 and increase to 7 (totpages%).

If the user was printing pages 4 to 6, 2 copies, then copy% will start at 1 and increase to 2, page% will start at 4 and increase to 6, totpages% will stay at 3, and pagepos% will start at 1 and increase to 3 (totpages%).

Now, at last, we come to the actual printing: the actual construction of the pages. (Don’t forget that you have already called PROCwimp_print somewhere.)


The ‘redraw’ page construction
First, using the redraw method i.e. you called PROCwimp_print with its first parameter set to 0.

In this case, PROCuser_redraw is called automatically and Dr Wimp will set its penultimate parameter printing% to TRUE, and its last parameter page% will contain the page number to print.

Let’s take a simple example of plotting on the screen one line of text in Trinity.Medium at 12pt and printing it. We will assume a handle for the font has already been obtained and is in trinity12%. The window we are displaying/plotting in has the handle main% (ie. the window handle passed to PROCwimp_print was main%), and the unscaled text is placed at the work area coordinates 50,-100 left-aligned.

Firstly, looking at just the screen display needs:

DEF PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%, printing%,page%)
IF window%=main% THEN
         x%=50:y%=-100
         string$="DrWimp printing test."
         PROCwimp_plotwindowtexth(main%,string$,trinity12%,0,x%,y%, 0,0,0,255,255,255,minx%,miny%,maxx%,maxy%,1,1,0)
ENDIF
ENDPROC


Now take a look at how it would be modified to allow these same contents of the window main% to be printed on a portrait page.

DEF PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%, printing%,page%)
IF window%=main% THEN
         x%=50:y%=-100
         IF printing%=TRUE THEN
         x%=FNwimp_worktopaper(x%,0,0)
         y%=FNwimp_worktopaper(y%,1,0)
         ENDIF
         string$="DrWimp printing test."
         PROCwimp_plotwindowtexth(main%,string$,trinity12%,0,x%,y%, 0,0,0,255,255,255,minx%,miny%,maxx%,maxy%,1,1,0)
ENDIF
ENDPROC


That is, we simply keep the same routine but do a work-to-paper coordinate conversion of the plotting position whenever the penultimate parameter printing% is set to TRUE (by Dr Wimp automatically). (”work” coordinates being synonymous with “window” coordinates.)

One thing to note is that the top left corner of the window main% matches up with the top left corner of the paper.

And - after all that setting up - that’s it!


Now for an example of printing the page number at the bottom of each page.

The following example assumes the work area of the window main% has been set to the size of an A4 piece of paper. That can be done with:

width%=FNwimp_lengthtoOS(210,100,0)
height%=FNwimp_lengthtoOS(297,100,0)
PROCwimp_resizewindow(main%,width%,height%)


The FNwimp_lengthtoOS calls convert 210mm and 297mm at 100% scale to OS units. The window is then resized. The example also assumes the programmer is keeping track of which page is being displayed with currentpage%.

So, for a portrait page:

DEF PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%, printing%,page%)
IF window%=main% THEN
         x%=50
         y%=FNwimp_getwindowworksize(main%,1)+150
         IF printing%=TRUE THEN
         x%=FNwimp_worktopaper(x%,0,0)
         y%=FNwimp_worktopaper(y%,1,0)
         ENDIF
         string$="Page "+STR$(currentpage%)
         PROCwimp_plotwindowtexth(main%,string$,trinity12%,0,x%,y%, 0,0,0,255,255,255,minx%,miny%,maxx%,maxy%,1,1,0)
ENDIF
ENDPROC

The text is plotted (left-aligned) 150 OS units up from the bottom of the actual paper to allow for printer borders, and to give a bit of space. As stated before, currentpage% contains the number of the page currently being displayed.

There is one problem with this however. It will be displayed fine, but when it comes to printing out, every time currentpage% will contain the page number of the current page being displayed, so it won't change on paper. What is required is a way of using the variable page% passed to PROCuser_redraw to make currentpage% change, but without corrupting it, so when the printing has finished the redraw won't try to show a different page on the screen. Here is one method:

DEF PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%, printing%,page%)
IF window%=main% THEN
         IF printing%=TRUE THEN c%=currentpage%:currentpage%=page%
         x%=50:y%=FNwimp_getwindowworksize(main%,1)+150
         IF printing%=TRUE THEN
         x%=FNwimp_worktopaper(x%,0,0)
                  y%=FNwimp_worktopaper(y%,1,0)
         ENDIF
         string$="Page "+STR$(currentpage%)
         PROCwimp_plotwindowtexth(main%,string$,trinity12%,0,x%,y%, 0,0,0,255,255,255,minx%,miny%,maxx%,maxy%,1,1,0)
         IF printing%=TRUE THEN currentpage%=c%
ENDIF
ENDPROC


If PROCuser_redraw is being called for printing (printing% is TRUE) then currentpage% is stored in c% for safekeeping, and set to the number of the page being printed. Then, when the redraw has finished, currentpage% is restored to its initial value.

There is a comprehensive application called !PrintTest in the Examples folder to show many practical aspects of multi-page ‘redraw’ printing.


‘Screen’ and ‘Paper’ coordinates in ‘redraw’ printing

In the examples above we have used the “window” versions of the text-plotting wimp-functions - because these are the most easy to use for displaying in windows. We have then converted from “work” coordinates to ‘paper’ coordinates when printing - and we commented that this conversion effectively makes the top of the paper the same position as the top of the window.

You will also note that we have referred to - but not yet given an example of - ‘screen’ coordinates i.e. with reference to the bottom left corner of the screen.

Very occasionally you will need to use screen coordinates for plotting in a window. For example, when using Basic’s PLOT codes. In these cases, you would decide the required ‘work’ position i.e. window coordinates, and then use FNwimp_worktoscreen() to provide the ‘screen’ coordinates for the PLOT code. The following example will help:


DEF PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%, printing%,page%)
IF window%=main% THEN
         x%=50
         y%=-200
         PROCwimp_setcolour(255,0,0,0):REM** Red **
         x%=FNwimp_worktoscreen(main%,x%,0)
         y%=FNwimp_worktoscreen(main%,y%,1)
         PLOT 69 x%,y%:REM** Plot a point at x%/y% **
ENDIF
ENDPROC

If you wanted to print this using the ‘redraw’ method then the code would need to become:

DEF PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%, printing%,page%)
IF window%=main% THEN
         x%=50
         y%=-200
         PROCwimp_setcolour(255,0,0,0):REM** Red **
         x%=FNwimp_worktoscreen(main%,x%,0)
         y%=FNwimp_worktoscreen(main%,y%,1)
         IF printing%=TRUE THEN
                  x%=FNwimp_screentopaper(main%,x%,0,0)
                  y%=FNwimp_screentopaper(main%,y%,1,0)
         ENDIF
         PLOT 69 x%,y%:REM** Plot a point at x%/y% **
ENDIF
ENDPROC

That is, solely because - unusually - we need here to display something in a window using ‘screen’ coordinates, we need to convert screen-to-work for the display and screen-to-paper for the printing. But it is important to note - as will be seen in the next sub-section - that screen-to-paper conversion is a need which is only ever encountered with ‘redraw’ printing.



The ‘user printing’ page construction
Now for the ‘user method’ of printing i.e. you called PROCwimp_print with its first parameter set to 1.

Instead of PROCuser_redraw being called by Dr Wimp, PROCuser_print is automatically called instead.

The page is described in much the same way. As there is no window involved you do not need to convert between work area, screen and paper coordinates. You simply work in paper coordinates, which are exactly the same in this case as OS screen units i.e.with the origin at the bottom left corner of the paper.

The “window” versions of the various available text and/or graphics plotting calls cannot be used, but all their counterparts can be, such as:

PROCwimp_rendersprite()
PROCwimp_render()
PROCwimp_renderjpeg()
PROCwimp_plottext()
PROCwimp_plottexth()
PROCwimp_deskplottext()

as well as all the Basic PLOT commands.

For example, to print a black square, slightly in from the bottom left corner of the paper:

DEF PROCuser_print(minx%,miny%,maxx%,maxy%,page%)
PROCwimp_setcolour(0,0,0,0)
RECTANGLE FILL 100,100,50,50
ENDPROC


You can be more precise with your position in “real” units, for example:

DEF PROCuser_print(minx%,miny%,maxx%,maxy%,page%)
inch%=FNwimp_lengthtoOS(1,100,1)
4cm%=FNwimp_lengthtoOS(40,100,0)
PROCwimp_setcolour(0,0,0,0)
RECTANGLE FILL inch%,inch%,4cm%,4cm%
ENDPROC


will print out a black square one inch from the bottom of the page and one inch from the left edge of the page, with sides 4cm long.

Similarly, if you wanted to print a drawfile (already loaded into memory in accordance with Section 2.12, of course) then you might use:

DEF PROCuser_print(minx%,miny%,maxx%,maxy%,page%)
inch%=FNwimp_lengthtoOS(1,100,1)
4cm%=FNwimp_lengthtoOS(40,100,0)
PROCwimp_render(dfile%,inch%,4cm%,minx%,miny%,maxx%,maxy%,1,1,1)
ENDPROC

which would place the bottom left corner of the drawfile’s bounding box 1in in and 4cm up from the bottom left corner of the paper.


With PROCuser_print there is no printing% nor currentpage% variable to use because it is only called when printing is taking place, and the final parameter page% holds the current page number of the page being printed.

There is a standard clipping rectangle supplied in page coordinates which you can use for optimisation, however it is doubtful if the performance gains would be big enough to warrant the extra effort of using the clipping rectangle.



Suggested practical programming sequence for printing
There has been a lot to absorb in this section - mainly to do with the preliminary checks and setting up rather than the printing itself, which latter is fairly straightforward.

When you are programming for printing it is suggested that you deal with the printing process first and return to the checks etc. subsequently. For example a typical programming sequence might be:

1) Make sure you have a printer driver loaded and the printer ready to print.
2) Provide a simple means to trigger the printing process e.g. a ‘Print’ button in a window or a menu item.
3) Decide whether you want to use the ‘redraw’ or ‘user’ method.
4) Program PROCuser_redraw
or
PROCuser_print accordingly.
5) Cause the ‘Print’ button/menu item to call PROCwimp_print in the simplest possible way i.e. probably with its last nine parameters set to 1,1,1,1,0,1,1,0,0 respectively.
6) Load the application and try the printing action.
Then revisit steps 4), 5) and 6) to fine-tune and/or extend the process gradually until you are happy with what is happening.

Don’t forget that there will probably be a pause between pressing the ‘Print’ button and the printer starting to operate. Dr Wimp helps here by automatically displaying the hourglass during its own processing time.

If the hourglass comes and goes and there are no error messages and yet your printer does nothing (or produces a blank sheet) take this as good news! The chances are that it is only due to your coding attempting to print ‘off the paper’ due to wrong coordinate conversions. Also, check that you have set the foreground plotting colour correctly: printing white on white is not difficult to arrange!

If you get an error message you will almost certainly have made a ‘silly’ coding error somewhere e.g. a variable name without its final “%” etc. - which can be frustrating to search for (speaking from first-hand experience!). So try to keep to small changes when in Step 5 above.

Until you try it yourself you will have to accept on faith that, so far, the Dr Wimp printing routines have proved to be extremely robust and have not needed modification for some years. They work if you let them!

When you have got the basic process working OK, then go back and tackle the user-friendly bits such as checking for printer driver presence/change, providing a ‘Printing choices’ window, showing progress etc. Again, take it a step at a time - integrating and checking things gradually.


Note that if you simply wish to send an existing file to the printer - with exactly the same effect as if you had dragged the file from a Filer directory window to the printer icon on the iconbar - then there is a separate wimp-function to do this. It is PROCwimp_sendfiletoprinter() - see Section 3.1 or 3.12.







Top of page        Back to Contents        Previous        Next