Scrollbar OPM Module for EPOC

Introduction, Features/Misfeatures

This OPM module emulates scrollbars (or sliders) for use in OPL on some EPOC machine. A scrollbar is a user interface object where some subinterval fully contained in another interval is displayed. This subinterval stands for some application range (e.g. consecutive visible lines from some larger text) and is graphically represented by a box (the so-called compartment) within another graphical object.

Fig. 1: Example of a horizontal scrollbar

The position of the compartment (and thus the lower and upper limit of the compartment range) can be changed by a pen event but not the length of the interval or the containing interval (the so-called scrollbar range). This is only possible by a method call. Any repositioning of the compartment is immediately reflected in some change of the underlying application range.

My implementation has the following features and misfeatures:

Installation

The following steps have to be performed to make the scrollbar module available:

  1. Download the files from here.
  2. Unpack the ZIP-archive on your PC.
  3. Connect your EPOC device to the PC.
  4. Install the scrollbar.sis file onto your EPOC machine by double clicking on it.

Usage

To use the scrollbar in your own program you have to do the following:

  1. Put an include line at the beginning of your program for "scrollbar.omh" (and possibly for the OPM loader)
          INCLUDE "OPM.omh"
          INCLUDE "Scrollbar.omh"
  2. Load the module and call its initialisation procedure similarly as with other OPM modules:
          LOADM OPM_loader$
          OPM_loadModule:("Scrollbar")
          UNLOADM OPM_loader$
          Scrollbar_initMODULE:("myFirstProcedure")

    The string parameter for Scrollbar_initMODULE: is the name of the first procedure in your program.

  3. Define a procedure to be called whenever some change happens to the scrollbar. It must have one long integer parameter and must not return a value. Neither the name of the procedure nor the name of the parameter is important.

    Later on we shall see that the scrollbar uses user specific coordinates specified by calls of Scrollbar_setRanges:. When the scrollbar is changed either by a pen or key event or by a call to Scrollbar_setRanges:, your registered procedure will be called. Its parameter will contain the value of the lower bound of the compartment interval.

  4. Any scrollbar you want to use is created by Scrollbar_create: with the following signature:
          Scrollbar_create%:

    This routine has no parameters and returns a scrollbar object identifier (which must be stored in some integer variable for later use), but it does not display a scrollbar yet! Additional steps are still necessary: the compartment and scrollbar range has to be defined and the geometry of the scrollbar must be set and a listener callback routine has to be associated with this scrollbar.

    It is necessary to identify the scrollbar in later routines as you may have several scrollbars open at a time.

  5. One step is to bind some listener to this scrollbar. Normally someone in your application is interested in the position of the scrollbar. This someone is represented by a routine in your application with a single long integer parameter. Anytime the scrollbar is changed (and redrawn) it calls this routine with the current value of the scrollbar.

    You can set this callback routine via

          Scrollbar_linkToClient:(listenerProc$)

    The only parameter listenerProc$ gives the name of the procedure to be called whenever this specific scrollbar is changed by an event or by a call to Scrollbar_setRanges:.

    If you do not specify any listener then the scrollbar works fine, but it does not do anything useful.

  6. The scrollbar geometry is specified by calling the routine Scrollbar_setGeometry: which has the following signature:
          Scrollbar_setGeometry%:(scrollbar%, isVertical%, x%, y%, thickness%,
                                  length%, buttonlength%, minCompartmentLength%,
                                  borderWidth%)

    The first parameter is the scrollbar affected and the second parameter tells whether this is a vertical or horizontal scrollbar. x% and y% give the position of the upper left corner in pixels. thickness% is the scrollbar thickness and length% the length of the scrollbar's main axis including the buttons (both dimensions in pixels). Note that it depends on the scrollbar being vertical or horizontal whether thickness% is the vertical and length% the horizontal extension or vice versa. buttonLength% (in pixels) tells the size of one button along the main scrollbar axis and minCompartmentLength% (in pixels) fixes the minimum size for the compartment . The final parameter borderWidth% (in pixels) tells how thick the border around the scrollbar is. Note that the border goes inward, that means that the outer size is not affected by the border width.

    Hence to set up a vertical scrollbar at (500,0) with a thickness of 25 pixels and a length of 240 pixels you say:

           LOCAL scrollbar%
           scrollbar% = Scrollbar_create%:
           Scrollbar_linkToClient:(scrollbar%, "myUpdateProc")
           Scrollbar_setGeometry:(scrollbar%, kTrue%, 500, 0, 25, 240, 25, 20, 1)

    Note that the buttons are also 25 pixels long, the compartment will be at least 20 pixels long and the border is 1 pixel wide.

    Now to do something useful with your scrollbar an initial call to Scrollbar_setRanges: is necessary (see below).

  7. To specify the compartment and scrollbar ranges you have to call Scrollbar_setRanges: which has the following signature:
          Scrollbar_setRanges:(scrollbar%, low&, high&, min&, max&)

    The first parameter tells which scrollbar has to be changed. low& and high& give the lower and upper values of the compartment range. min& and max& give the lower and upper values of the scrollbar range (both ranges are specified by long integers and in your own coordinates!).

    Some caveat is that you specify intervals which are semi-open. The scrollbar module assumes that the lower value specified is part of the interval, but the upper part is not. So e.g. when you define low& as 1 and high& as 2 the compartment goes from 1 to the number immediately below 2 (this is about 1.999; mathematicians will shriek in horror..;-.) or - to be more precise - covers the interval [1,2[. The same logic applies to the scrollbar range.

    If this sounds to you like the weird mathematicians taking over, then just remember that you should always give an upper bound which is one more than you would expect. E.g. when you display line 25 to 37 of a text with 1386 lines you call Scrollbar_setRanges: as follows:

          Scrollbar_setRanges:(scrollbar%, 25, 38, 1, 1387)

    The reason for this strange decision is that it is more logical. Consider a program displaying one of five pictures selected by a scrollbar. If you set up the scrollbar range as 1 to 5 and the compartment range say 3 to 3 you have a problem: the compartment should have length zero! In my opinion it is more logical to say the scrollbar covers interval [1,6[ and each picture is represented by a semiopen interval of length 1 e.g. by [3,4[. So the compartment length is exactly one fifth of the scrollbar length which should be fine...

    Whenever you fiddle around with either geometry or ranges the internal data in the scrollbar is changed but the visual representation s not updated! To do that you must issue a call to

          Scrollbar_draw:(scrollbar%)

    which visually updates the scrollbar to reflect the internal data.

    The reason for this design is that you may have many updates in geometry and ranges and do a redraw only when done. Also draw is optimized to redraw only those parts which are invalid.

  8. Feeding pointer events into scrollbars is similar to feeding them into a toolbar: a centralized procedure is called in your event loop:
          Scrollbar_offer%:(windowID%, pointerType&, x%, y%)

    The first parameter tells in which window the event has happened. The second parameter tells whether the event was a pen down, pen up or pen drag. Finally x% and y% give the position of the pen event. You can take all the information from the result of a call to GETEVENT32. It is identical to the information you would give to a call of TBarOffer.

    Some further remarks:

  9. It is also possible to feed key events into a scrollbar. As OPL does not assign a key event to a window (as with pointer events) you have to explicitly tell in your event loop which scrollbar should handle the keys. This is done via a call to
          Scrollbar_offerKey%:(scrollbar%, keyEvent&)

    The first parameter tells which scrollbar should take care of that key event, the second parameter tells which key has been pressed. Note that this routine tells you as its result whether the event has been consumed by the scrollbar or not.

    Normally a scrollbar consumes arrow keys parallel to its orientation. For example a horizontal scrollbar reacts on a left arrow key, a right arrow key, a page left key and a page right key. The normal arrow keys increment by ±1, the page keys by the ±compartment length. You can define the keys by calling

          Scrollbar_setKeyTracking:(scrollbar%, mode%)

    where the mode tells whether no arrow keys are accepted, horizontal or vertical keys or both or those parallel to the scrollbar orientation. There are constants with prefix Scrollbar_keyTracking in the include file with meaningful names for the mode. When you don't explicitly set the key tracking the default is handling of parallel arrow keys.

    Sometimes this mechanism does not fit for your application. Then you will have to handle the keys by yourself and update the scrollbar via calls to Scrollbar_setRanges:. This is also not too complicated.

  10. It is also possible to define the overlap between the compartment ranges when pressing a page cursor or clicking into the range outside of the compartment. Default is 0 which means that the intervals of two compartment ranges are directly adjacent after such an operation. Sometimes it is practical to set the overlap to another value (typically =1) to achieve that some part of the previous information is still visible after a page change.

    E.g. when the compartment range is [12,20[ and the overlap is 1 a page down button will move the compartment range to [19,27[.

    You can set the overlap via

          Scrollbar_setPageOverlap:(scrollbar%, overlap%)
    where scrollbar denotes the affected scrollbar and overlap is the integer overlap of the ranges.

  11. Sometimes it is necessary to find out whether the scrollbar is visible. A scrollbar is not displayed when the compartment range is equal to the range because obviously all relevant information is displayed and you do not need a scrollbar.

    You can find out about this via

          Scrollbar_isVisible%:(scrollbar%)

  12. Finally to get rid of a scrollbar, you have to close it as follows:
          Scrollbar_close:(scrollbar%)

    The only parameter is the scrollbar identifier (just in case you have more than one scrollbar open).

Conditions of use

The scrollbar program is put into the public domain and is unsupported. If you think there is some bug in the program you can contact me by electronic mail. Currently I cannot promise an immediate answer or even any answer at all.

You may modify the source code but you are not allowed to publish the scrollbar code as your own work when the changes are marginal. I don't like being confronted with the new OPL 5 scrollbar module by Fredi Klabuster which is nearly 100% my code.

Nevertheless you may use this code freely and of course you don't have to mention me when the scrollbar is part of your program.

Have fun,

Thomas Tensi, August 2001

Download

You can download the scrollbar module for OPL (with source code!) for use in your own programs. A detailed instruction for installation and use is available in the SIS-file as "Scrollbar_Doc". Also a tiny demo test driver is included where you can see how to practically use a scrollbar.


   HOME    UP