The user peeps through their rectangular inner box onto a (i.e. seemingly real, but not there) plane that infinitely extents into all directions and on which icons of files and drawers lie at certain By means of the scrollers within the window borders, the user can shift the box around on the virtual plane, causing new things to appear in the window.
Another example would be a text editor. Once you have entered more text that the window can hold, the text extents beyond the window's bounds on its arbitrarily long fanfold paper. Then you will use the scroll bar that normally is attached to the right border of the window to look at different parts of your text.
Almost every application program that operates on an arbitrarily extensible project data base and that employs a graphical user interface will use the virtual co-ordinate plane to display its data.
Now VCB allows programs not only to share the concept, but also the code!
VCB is a BOOPSI class implementation in shape of a scanned library (for Manx/Aztec C).
At present this class is still `private� in the sense that I do not provide code that adds it to the system's public pool of named classes and therefore is not accessible by a symbolic name.
After some experiences in its use have been collected and possible bugs habe been fixed, it will be submitted to Commodore Amiga for becoming a public BOOPSI class with a registered name. This name will probably be "vcbgclass" (it is a descendant of "gadgetclass"). Maybe some day it will even be part of the OS itself (Intuition provide such a service).
You should link the library to your client code in order to create VCB gadgets and attach them to your windows. Such a gadget consists of horizontal and/or vertical scrollers (that look almost identical to those within Workbench windows) and the box in which your data will be visible. You have to supply a hook to a function of your own that will do the actual rendering within the box according to the `instructions� the gadget gives it. The internals of that function are completely It just makes no difference to that gadget whether you are going to display text, graphics, a musical score etc. or all of them at once!
As each of Intuition's own classes defines certain specific tags for setting up the instance as the client needs it, so does VCB. Here are the
Without the scroller, you cannot move the display box over the virtual
plane in that direction
but besides that there is no difference
(you can still move it via SetGadgetAttrs()).
Note: Setting the VCBGA_H/VBorder flag will adjust the window borders to accommodate
the scroller, it will not resize your gadget in any way.
(see also example).
In this version, VCB cannot emulate Workbench windows which feature an
infinitely large virtual plane. I personally don't need this (now), but
I will add it if someone misses it.
In addition to these, all tags that apply to the general remain active as well, of course.
To create the imagery for the scrollers, two additional tags should be provided. The tag values are defined in <intuition/imageclass.h>.
These are SYSIA_DrawInfo (struct DrawInfo *) (you get/free the DrawInfo structure using GetScreenDrawInfo()/FreeScreenDrawInfo, see AutoDocs) and SYSIA_Size (SYSISIZE_...). While a missing SYSIA_Size tag is defaulted to SYSISIZE_MEDRES (Workbench default resolution), a missing SYSIA_DrawInfo tag will cause NewObject() to fail.
There are five further tags that refer to read-only attributes (ignored by SetGadgetAttrs(), but retrievable by GetAttr()):
The callback function will receive arguments in the usual form: the hook pointer, an `object� and a command message.
The `object� is the usual public handle to the VCB instance. You will need this to retrieve geometric data via GetAttr() (the VCB structure is I'm doing this the clean way, despite the overhead). See the example.
The message pointer refers to an ExposureMsg structure (defined in vcb.h). It contains a command ID (the only defined command ID is VCBCMD_RENDER, but better test for this ID explicitly), a pointer to the rastport into which the renderings go and left, top, width and height values for the rectangle that has to be (re-)drawn. An `exposure� has occured if the bitmap contents do no longer reflect the data that is located at the respective position on the virtual plane. Possible reasons are that the window wasn't previously open or was exposed by some other window going away or that the display box moved to another position on the virtual plane (either by manipulation of the scrollers or by a client request via SetGadgetAttrs()).
The left, top, width and height values are in virtual units and have to be multiplied with the respective unit values to yield pixel dimensions.
Be aware that callback code is hazardous area! There are some things that be avoided.
The execution time of this function is critical. The functionality of the whole user interface depends on that your function completes as quickly as possible. Prepare all information needed for rendering in advance and store it where the function can get it (please read the ARBITRATION section below, too). Better to consume some more memory than to freeze the user interface.
Do not call dos.library functions directly or indirectly from the rendering function! This function executes in the context of the input device's task!
Likewise, do not directly or indirectly call Wait() (deadlock imminent). This implies that you cannot employ the console.device to do text rendering!
If you have to debug this part of your code, never use printf() or fprintf()! Try to kprintf() to a terminal or record to an internal data structure and evaluate it later.
Nonetheless, do the things that are necessary: Please do not make any assumptions on the state that the rastport is in when your function is called. Setup the rastport explicitly before you start rendering. In particular, set the pens and the draw mode where appropriate (text, vector drawings, area drawings), set the line pattern for vector drawings, set the area pattern for area drawings. Certainly I forgot something, so please read through the docs of the graphics.library functions that you use to find out what they depend on. Even if the OS does not make use of some rastport features now, it may do so in the future. We are all suffering the system font dependency of pre-OS 2.0 software now. Let this be a lesson to us!
The callback function executes on another task's context and time slice. If it relies on data that is going to be changed by the client task (which is most probably the case if it is a project data base that is being edited by the user), the client task has to arbitrate for the write access to that data (read access is free for the client since the callback code is not supposed to modify any static data).
To that purpose, a SignalSemaphore structure is part of the VCB instance data. The semaphore is automatically initialized during the processing of NewObject(). The gadget only performs a callback if an AttemptSemaphore() succeeds. It calls ReleaseSemaphore() after the callback completes.
Thus to prevent the gadget from rendering data that is being modified, the client must wait for ObtainSemaphore() to return (which should happen as soon as the user stops fiddling with the VCB's scrollers or moving/resizing the window). As long as the client posseses the access right, the gadget's display will not be updated, even not due to client calls to SetGadgetAttrs().
The pointer to the semaphore must be retrieved by GetAttr( VCBGA_Semaphore, ... ) (see TAGS and example program).
Click the close gadget. This changes the horizontal offset, causing the box contents to `scroll�. If the offset change conserves some old imagery, then VCB will ScrollRaster() it to its new place within the display box and only refresh those areas blanked out by the scroll. If the jump is too far, it simply runs a complete redraw.
Click again and again and again and again. The horizontal and vertical totals (the number units that the virtual plane extends horizontally and vertically) have changed to 3, 10, 20 and finally 30.
Click again. The program fetches the VCB semaphore and obtains it. Now moving the scroll bars or pressing the buttons has no visual effect. Note however that pressing a button will still move the associated scroll bar - the gadget is still alive! If you do something with the window, the display box contents will decay.
Click again. The program releases the VCB semaphore again and calls RefreshGList(). Now the gadget updates itself according to the new scroller positions. Releasing the semaphore does not trigger any display refresh. To get an immediate update, you need to call RefreshGList().
Click again and the program terminates.