GLAM's event handling architecture is built upon an essential dichotomy, namely the separation of user input from widget communication. Event handling in GLAM therefore consists of the following two different subsets: User Events and Widget Actions & Listeners.
In most windowing toolkits, there usually exists a master controller of some form or another. The UI toolkit assumes the responsibility of handling all user input. While this method provides a very straight-forward approach to application design, it does not fit well with most visualization-centric applications.
GLAM's event model utilizes a more free-form approach. It is up to the application to generate and send user events to the event distributor, which then sends them to the proper widget. The widget is then responsible for handling the event in an appropriate fashion. This approach allows for a much more flexible integration paradigm than the traditional "the application revolves around the UI toolkit". Rather, with GLAM "the UI toolkit revolves around the application".
There are several important user event classes that the developer should be aware of, namely:
Important event classes
The GmEvent class is the base class for all user events and encapsulates much of the information needed by events into a single object. Mouse and keyboard events are encapsulated into a single GmEvent object. These event objects are then passed around the GLAM architecture until they reach their destination. All events have a receiver ID to identify the target widget. If an event represents mouse input, the mouse's coordinates will be recorded in the event both as screen coordinates and as openGL units.
The GmEventDistributor singleton is responsible for distributing all developer generated events to their target components. The GLAM event distribution model is completely open ended, in that a developer can decide when and how to create user events and to which target that event gets delivered.
The Actions and Listener interface provides a means for inter-widget communication. The event distribution architecture handles only external input events (directly from the user), so a robust internal action architecture was created. Widgets can implement certain types of listening interfaces. Using those interfaces, they can register with other widgets to recieve actions. This allows widgets to 'talk' to each other.
Another purpose for this architecture is highlighted through an understanding of the difference between, for example, a mouse button click (a user event) and a "button press." A button press is generally not as simple as a mouse click. A user may, for instance, click on a button, continue holding the mouse button, leave the button and return before releasing the mouse button again. This action is considered a "button press." Understanding who is responsible for handling this kind of behavior is where actions and listeners play their role.
As can be seen from our previous example, it is the button widget that actually determines its own function, not a mouse click. The same is true for all other widgets in GLAM. With this in mind, the architecture for widget "action" handling was devised.
In GLAM, user events are generated and assigned to certain widgets by the developer. The widget is then responsible for how it will handle the user event. In this manner, the function of a widget will determine what a widget is. For instance, the function of a button is the abstract "button press" action, as previously described. A button widget and how the user will interact with it is determined by its function. By virtue of this important design, the form of a widget follows its function.
As user events are translated by widgets into the appropriate behavior, a more abstract communication layer is developed. The actions that widgets perform in response to a user event can be "listened" to by other widgets or classes. This is accomplished through the implementation of various listener interfaces. For each type of abstract widget action, a widget listener interface is available. In keeping with the previous button examples, button actions can be listened to by implementing a button listener.
The developer is expected to extend the core set of action and listener classes provided in GLAM when necessary to accomplish the specific goals of his application. Below are the base action and listener classes, as well as some core action & listener classes and some widgets that support them.
Base Action & Listener in GLAM
The GmWidgetAction class is the base class for all widget actions.
The GmWidgetListener class is the base interface for all widget listeners.
Examples of Core Actions & Listeners in GLAM
The GmButtonAction class describes a button action. A button widget generates a button action when it is "pressed."
The GmButtonListener class handles GmButtonActions.
Examples of supporting widgets
GmButton
GmCheckBox
GmRadioButton
The GmFocusAction class describes a focus action. A focusable widget generates a focus action when a user event modifies its focus.
The GmFocusListener class handles GmFocusActions.
Examples of supporting widgets
All GmInteractiveWidgets
The GmScalarAction class describes a scalar action. A scalar widget generates a scalar action when its value is changed.
The GmScalarListener class handles GmScalarActions.
Examples of supporting widgets
GmBarMeter
GmScrollbar
GmSlider
The GmSelectionAction class describes a selection action. A widget that supports selection generates a selection action when one of its components is selected.
The GmSelectionListener class handles GmSelectionActions.
Examples of supporting widgets
GmCheckBox
GmMenu
GmMenuBar
GmRadioButton