WDS: A WiDget Set for the EW Event/Window Abstraction Library

Notice

Except where stated explicitly, the term "Windows" does not refer to a Microsoft product.

Purpose

The WDS is a library of derived widgets and related classes built on the EW abstraction library.

Design

The Coral libraries exploit the class inheritance provided by C++. New widgets can easily be derived by adding functionality to existing widgets. The EW/WDS classes were developed to make the creation of new widgets as easy as possible without restricting flexibility. An example of inheritance is shown here.

Coral Tree: WDS Inheritance

The derivation begins with GPL_DoubleNode, required for the intrusive doubly-linked-list functionality. The inheritance continues through EW_Node, which shares some members with windows, and EW_Widget, which is the base widget functionality.

WDS_Widget adds additional abilities that are not a part of EW and may not be shared by an alternate widget set built on EW. All WDS widgets will assume that all other widgets are derived from WDS_Widget and not directly from EW_Widget. WDS requires features in WDS_Widget such as run-time type-checking, ties, optional state-change callbacks, and inheritable look-and-feel.

Features

Platform Dependencies Completely Abstracted Out by EW

Since WDS is built over the EW abstraction, all the source code written for WDS and any applications using WDS need not have any notion what platform they are running on. This means that statements like "#ifdef __sgi" are never needed. The windowing system and graphics language can be chosen by -D flags to the compiler and should only be differentiated by EW source, including headers. Recognized windowing systems are: Win32, X, and MEX (IrisGL). Available graphics languages are: Xlib, Microsoft GDI, OpenGL, and IrisGL. The MEX and IrisGL systems are not current. The Xt and Motif headers and libraries are not used, so you won't need them. The commonly used modes are X/Xlib for Unix and Win32/GDI for Win95 or NT. Windows NT does support OpenGL.

Derived Functionality

With an existing base set of widgets, new widgets do not require writing complete functionality from scratch. C++ virtual functions can be overridden or appended to, allowing programmers to create widgets as modifications and extensions of existing widgets.

Dynamic Inheritable Look-And-Feel

Using the widget run-time type-checking, each derived widget class can register a default look including:

plus additional widget-specific values, like scrollbar width, stored union-style. The Inheritance value can optionally specify another widget class from which values can be inherited. This inheritance path does not have to follow the C++ inheritance, but that will usually be the case. Any value (except Inheritance and Initialization Callback) can be specified as default. If so, other looks are searched for a non-default values. The search order, starting with each widget instance's personal look is:

widget's instance -> widget's class -> inherited class(es) -> default look -> root window

The root window only holds colors, so any other value not found once getting to the default look is set to NULL. You can also map values to a different entry of another look. For example, the map flag could be used to map the default background color as a widget's foreground color. The inheritance step can be prevented on a per look-entry basis. For example, your class "special-button" may wish to default to the overall background color, but inherit the pen color from "button". This can be useful to map directly to the overall defaults in case the inherited class has its own undesired value.

Most of the widgets in WDS have all their looks set up from a single function in the WDS library. But, widgets derived in applications can't do this and need to be able to reset themselves "on the fly" while the application is running. This is intentionally demonstrated in the class WDS_HierarchyForm in hier.cc under WDS_HierarchyForm::InitializeLookCallbackInit(). This function, called from the constructor, sets itself as the Initialization Callback. As such, it will be called from WDS's own initialization/reset function.

This configurability allows the system (or programmer) to set the look-and-feel of the widgets to closely match existing systems that users may already be familiar with, such as Motif, Microsoft Win32, and Athena. The test example uses these and adds the additional mode, "Coral", which attempts to expand on the positive attributes of these previous systems.

Dynamic Hierarchial Arrangement

Since WDS uses EW's unrestricted widget hierarchy concept, any widget can be the child of any other widget. Also, any widget sub-hierarchy can be instantaneously moved under any other widget (or window), and the GUI restructures itself automatically. This approach not only makes builders unneccessary, but exposes their shortcomings. The structure can be easily dynamically altered The appearance is defined by user's specified (or default) contraints, not their patience or artistic skill.

Layered Scoping with Event Bypassing

User events normally flow through a subset of the widget hierarchy by following the widget bounds relative to the mouse location of the event. Many widgets, especially ones dealing with keyboard input, require specific events even when the mouse is not directly over them. A scope widget can be used to bypass this descension and pass a specific subset of events directly to a specified widget. For example, take two scopes, one each on the left and right halves of a window. Put a WDS_GetString text entry widget somewhere on the sub-hierarchy of each in the midst of other widgets. When either of the text widgets is activated, it registers an exclusive bypass with it's associated scope. If, for instance, the mouse is over the left half scope, any keyboard event will be bypassed from that scope directly to the registered text entry widget (assuming it is registered). After finishing (by hitting Return, maybe), the text widget can release its bypass.

If anotherwidget requests an exclusive bypass with an overlapping event subset from the same scope, any widget that previously held an exclusive bypass is notified that its bypass was degraded to non-exclusive. Non-exclusive overlapping bypasses can be held without conflict. In the case of the WDS_GetString text entry widget, it will respond to losing exclusivity by deregistering anyhow. In this way, you can switch to a new text entry widget in the same scope and the previously selected widget will finish itself up. But, another text entry widget in a separate scope will remain selected, but will be unresponsive until it returns to scope. When bypasses exist in scopes with overlapping bounds (one is the ancestor of the another), the child-most scope gets priority. But the ancestral scopes can still use the event when the mouse is outside the child-more scope, but still inside an ancestral scope.

An example of non-exclusive bypassing is in WDS_Button. When pressed, it graphically holds the button down until the left mouse button is released. But, if the mouse is moved and released outside the button, it would miss this event and stay down. So, it registers a non-exclusive left mouse release bypass with the root-most scope. This way, it sees the release as long as it occurs in the root-most scope, even if that event is also used by some other widget. For this reason, it is highly prefered (but not required) that widget hierarchies are based on a scope directly over the window object.

Widget Ties

Ties are used to set up a dependency on some setting of any number of widgets. For example, you can tie scrollbars together so that when one changes value, any other scrollbars tied to that WDS_Tie will change as well, automatically. The tied widgets can be of different types. Virtual tie functionality is defined in WDS_Widget, so any widget can be tied. But, not all widgets will recognize and participate in the tie since the default virtual is to only print a warning message. Each widget can only participate in one tie, but each tie can contain a list of values.

No Unusual Dependencies

Other than a minimal set of typical development software (C++, base libraries), all you need to compile are the header files and libraries for OSD, GPL, EW, and WDS, available together. No other third party software is used. None of these Coral Tree modules require daemons or run-time dependencies. The stand alone executables work by themselves; unless, of course, your application has its own run-time dependencies.

Widget Types

Our concept is to provide a minimal number of widgets that are flexible enough to cover many different needs.

Implemented

Proposed or Not Current

Related Classes

Screen Shots