Multi-page+graphics

//by Richard Russell, November 2007//

Some dialects of BASIC provide the ability to have multiple //pages// of graphics, whereby you can draw text and/or graphics into each //page// and then switch 'instantly' between them. Such a facility could be used for simple animation, or simply to avoid having to redraw the screen (possibly taking a significant time) each time a particular layout is needed by your program. It also has the advantage of 'remembering' the contents of each page without any extra effort by you.

Although //BBC BASIC for Windows// doesn't provide this facility as a built-in feature, it is relatively easy to achieve by means of calls to the **Windows API**. The routine **PROCpage** listed below allows you to create, and subsequently select, up to 15 extra pages (you can increase the number if necessary); it also allows you to delete the new pages when you have finished with them (by passing the parameter **-1**).

To avoid a resource leak you will probably want your program to incorporate **ON CLOSE** and **ON ERROR** routines so that the additional pages can be deleted on exit. For example these routines might be as follows:

code format="bb4w" ON CLOSE PROCpage(-1) : QUIT ON ERROR PROCpage(-1) : SYS "MessageBox", @hwnd%, REPORT$, 0, 48 : QUIT code Of course you may need to perform other 'cleanup' operations as well as deleting the extra graphics pages, so in that case you can replace the **PROCpage(-1)** with a call to a more general routine which itself then calls **PROCpage**.

No specific initialisation is required; when you first select a page it will be created. However for the purposes of demonstration you could initialise and label each of the pages as follows:

code format="bb4w" FOR Page% = 0 TO 15 PROCpage(Page%) VDU 30 PRINT "This is page ";Page% NEXT code As it stands the **PROCpage** routine doesn't keep independent text cursor positions for each page, so the **VDU 30** is used to //home// the cursor each time. Neither does the routine keep independent settings for colours, fonts, graphics pointers etc. so you must remember to reset these as required whenever a new page is selected. With some extra complication this could be made automatic (**PROCpage** would need to store the settings for each page).

Selecting each page as required will obviously depend on the specific requirements of your program, but again for the purposes of demonstration the following code uses the function keys to select the different pages:

code format="bb4w" REPEAT K% = INKEY(10) CASE TRUE OF         WHEN K%>=136 AND K%<=139: VDU K%-128 WHEN K%>=145 AND K%<=159: PROCpage(K%-144) WHEN K%=13: VDU 13,10 WHEN K%=-1: OTHERWISE: VDU K%       ENDCASE UNTIL FALSE code This code also allows you to write text into each page, to demonstrate that they are truly independent. Note that **page 0**, which is the normal default screen, cannot be selected using this code. The page currently being //displayed// is also the page into which text and/or graphics will be //drawn//, but if you need to draw into one page whilst displaying another this is easily arranged by means of the [|*REFRESH] command.

Finally, here is a listing of the **PROCpage** routine:

code format="bb4w" DEF PROCpage(Page%) PRIVATE hdc% DIM hdc%(15) : REM. Maximum number of pages IF hdc%(0) = 0 hdc%(0) = @memhdc% : REM. Page 0 is default IF Page% >= 0 THEN IF hdc%(Page%) THEN @memhdc% = hdc%(Page%) ELSE LOCAL bitmap%, font%, X%, Y%         SYS "GetSystemMetrics", 0 TO X%          SYS "GetSystemMetrics", 1 TO Y%          SYS "CreateCompatibleBitmap", hdc%(0), X%, Y% TO bitmap% SYS "CreateCompatibleDC", 0 TO @memhdc% SYS "SelectObject", @memhdc%, bitmap% SYS "PatBlt", @memhdc%, 0, 0, X%, Y%, &FF0062 SYS "GetStockObject", 16 TO font% SYS "SelectObject", @memhdc%, font% SYS "SelectPalette", @memhdc%, @hpal% hdc%(Page%) = @memhdc% ENDIF ELSE LOCAL newbm%, oldbm% @memhdc% = hdc%(0) FOR Page% = 1 TO DIM(hdc%,1) IF hdc%(Page%) THEN SYS "CreateCompatibleBitmap", @memhdc%, 0, 0 TO newbm% SYS "SelectObject", hdc%(Page%), newbm% TO oldbm% SYS "DeleteObject", oldbm% SYS "DeleteDC", hdc%(Page%) ENDIF NEXT ENDIF SYS "InvalidateRect", @hwnd%, 0, 0 ENDPROC code