Except where stated explicitly, the term "Windows" does not refer to a Microsoft product.
The WDS is a library of derived widgets and related classes built on the EW abstraction library.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Our concept is to provide a minimal number of widgets that are flexible enough to cover many different needs.