Introduction
Most ZVTM-based applications do not make use of scroll bars in Views, simply because they do not make sense as virtual spaces are infinite (unbounded) surfaces. Panning/scrolling in a View is usually achieved through direct dragging of the representation (as with the "hand" in tools such as Adobe Photoshop) or through rate-based scrolling (where the amount of dragging controls the camera panning speed). The latter is probably the most efficient way of panning a large/unbounded 2D representation.
However there are situations where client applications might want to offer more common panning controls such as scroll bars. ZVTM now makes this possible. This requires defining practical bounds to the virtual space. We chose to define those bounds as the smallest rectangular region containing all glyphs in the virtual space to which the camera controlled by the scroll bars belongs.
Scroll bars can coexist with the other navigation techniques supported by ZVTM (such as the above-mentioned rate-based scrolling). Synchronizing the scroll bar sliders is automatically taken care of by the toolkit. It is always possible to zoom in/out in a view, and the size of scroll bar sliders is updated accordingly, as illustrated in the figures below.
Instantiating the scroll bar component
The scroll bars themselves are implemented using glyphs observed through a camera in a dedicated virtual space. All these elements are managed through an instance of fr.inria.zvtm.engine.ScrollLayer which has to be created:
In the above example, scroll bar glyphs are created automatically. It is also possible to instantiate manually the eight glyphs that make both scroll bars and pass them to the ScrollLayer constructor.
Managing ViewEventHandler events sent to the scroll bar layer
Instantiating a ScrollLayer and associating it with a view and camera to be controlled by it is not sufficient to make it interactive. It is up to the client application to redirect events from the corresponding layer in the view to the ScrollLayer object.
The first thing to do is associate a specific ViewEventHandler implementation with the scroll layer:
Here we used the default, very basic implementation provided by DefaultScrollEventHandler. Buttons are actuated by clicking them with the left mouse button. Sliders are dragged with the left mouse button. Client applications are free to define scroll bar event handling through their own implementation of ViewEventHandler.
The last thing that needs to be taken care of is activating the scroll layer when the user moves her cursor in the scroll bar area. Client applications are free to do that any manner they want. The following is only one possible solution, that more or less "mirrors" what is done in DefaultScrollEventHandler to activate the main layer when the user moves her cursor outside the scroll bar area:
Updating scroll bar sliders when controlled camera is moved by other means than scroll bar widgets
If your application allows for the camera to be moved directly or indirectly by other means than the scroll bar slides and buttons, e.g., using rate-based scrolling, a key stroke that animates the camera to a position which gives an overview of the virtual space, etc. (as is the case in the Scrollbar demo), the client application must notify the ScrollLayer object about changes to the controlled camera's position whenever such changes occur outside the control of the scroll layer.
If the camera's position is changed through the animation manager, a convenient way to keep scrollbars synchronized is to call cameraUpdated() through an AnimationListener callback, as shown below:
Updating scroll bar sliders when the content of the virtual space changes
In order to keep the position and size of scroll bar sliders coherent with the virtual space's content, it is also necessary to notify the ScrollLayer object of changes to the glyphs in the virtual space observed through the controlled camera, as such changes can cause the practical bounds of the virtual space (as defined in the introduction) to be modified: new glyph added, glyph removed, glyph position, size or orientation changed...