JX
Version 1.0.0

Reference Manual

(c)1996-97 by John Lindal

Disclaimer

    JX was originally conceived for my own personal use.  As it evolved, it
became apparent that others could also benefit from using it.  I can make no
guarantees as to how well it works or how stable it is other than that it works
for me and that I have so much code that depends on it that I am unlikely to
make major modifications without a really strong reason.  The file
JXLibVersion.h defines the current version of the library and contains comments
describing major changes.

    If you find errors, need documentation on something that has been left out,
or find something to be confusing, please let me know so I can fix the problem.
My email address is jafl@alice.wonderland.caltech.edu.

Background material

    Since JX is built on top of the JCore library, you should read the JCore
manual before reading this manual.  JCore is included in the JX distribution.

Availability

    JX is available via anonymous ftp:

    http://www.cco.caltech.edu/~jafl/jx/download.html

Sample code

    Sample code is included with the JX library.  When compiled, it produces a
program that demonstrates all the major features of the library.  By reading the
code and this manual, one will hopefully be able to understand how to use the
classes in the library to produce one's own applications.

Mailing list

    The discussion mailing list provides a way for users to share ideas,
problems, and solutions.  I try my best to follow the discussions and provide
the best possible answers to questions.  To subscribe or unsubscribe, send email
to majordomo@cco.caltech.edu with a message saying "subscribe jx" or
"unsubscribe jx".  To send a message to the list, send email to
jx@cco.caltech.edu.

    The announcement mailing list provides a way to listen for new versions
without having to wade through the discussions.  To subscribe or unsubscribe,
send email to majordomo@cco.caltech.edu with a message saying "subscribe
jx-announce" or "unsubscribe jx-announce".  You cannot send messages to this
list.

Legal stuff

    JX is not public domain.  The library and associated documentation files
(the "Software") are copyright (c) 1996-97 by John Lindal and Glenn Bach (the
"Authors").

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

The Software is distributed under the SYPP license:

Preamble

    In an ideal world, all software would be free.  In the real world, however,
most people cannot afford to give away what they create because they do not have
sufficient income from other sources.

    Shareware is the accepted compromise for stand-alone programs.  Users only
have to pay if the software is useful.  SYPP provides an equivalent compromise
for libraries of code by asking the program's author to share the profits from
the program with the library's author.

License

*    The Software is free for non-commercial use.

*    Any commercial or government use of the Software must be accompanied by a
license agreement.

*    In the special case of a shareware program, one is only required to pay a
one-time library shareware fee for the Software and only after the program has
brought in 10 times as much as the library shareware fee.  (This means that one
only needs to pay when the program is successful, thereby avoiding any financial
risk to the shareware author.)

*    The Software may be freely redistributed in its original form.  If you make
modifications to the Software you may not redistribute it without express,
written consent from the Authors.

    The official text of the SYPP license is on the World Wide Web:

     http://www.cco.caltech.edu/~jafl/sypp/

    The above copyright notice and this text shall be included in all copies or
substantial portions of the Software.

Table of Contents

Introduction

    5    About this Manual
    5    Design Philosophy
    5    User Interface Guidelines
    6    The Object Hierarchy
    7    Typical Usage

Library components

    8    Displays
    8    Documents, Directors, and Dialogs
    9    Windows
    9    Widgets
    10        Drawing Widgets
    11        Colors
    11        Drawing during a mouse drag
    12        Dragging a dividing line
    13        Scrolling
    13        Handling events
    15        Shortcuts
    15        The X Selection (clipboard)
    15    Periodic background tasks
    15    Urgent updating tasks
    16    Images
    17    Tables
    18    Menus
    20    Custom menus

    21    User Interface Classes from JCore

    22    Miscellaneous Class Summary

    24    Hidden Feature Reference

About this Manual

    This manual was written to provide an overview of the JX library.  Function
level documentation can be found in the doc directory in the official
distribution.  In case of a conflict with this manual, the function level
documentation should be considered correct.

Design Philosophy

    JX is designed to be as flexible as possible within the limits of good
program design and good programming style.  This manual aims to explain both the
possibilities and the limitations.

    One important limitation is that JX is not designed to be cross-platform.
My opinion is that this is impossible because the details of "native
look-and-feel" are so different on each platform.  As an example, the Macintosh
provides a menu bar that is global to the application, while X doesn't even know
what a menu bar is.  Of course, the simplest issues, such as a keyboard and a
mouse, are standard, but the Macintosh mouse has one button while X supports
mice that have as many as five buttons.  Since the basics are the same, but the
details are so different, I have built objects that have one foot in JCore and
the other foot in JX.  The base class in JCore does as much work as possible
without reference to any particular system, and the derived class in JX fills in
the details in compliance with the X and Motif user interface standards.  If
anyone is interested in using the JCore classes with other systems such as the
Macintosh or Windows, please contact me.

User Interface Guidelines

    Regardless of whether or not one likes the Macintosh user interface, it is a
fact that Apple has done a lot of research into what the "average" person
prefers.  One issue they emphasize is that consistency between applications is
crucial for most users.  The details of every application must be different, but
the basic ideas should be the same.  Given that X imposes absolutely no
restrictions on appearance or functionality, JX tries to provide it instead.  A
suggestion for consistency:

*    The Meta key should activate shortcuts for all buttons, checkboxes, menus,
etc.  (e.g. Meta-S could trigger a Save button.)

    Since there are two major, competing operating systems, here is how to
simulate each one:

*    For a Macintosh style application, menus can only be pulled down with the
mouse, and all menu shortcuts are activated by the Meta key.

*    For a Windows style application, menus can be pulled down with Meta
shortcuts, menu items have plain text shortcuts when the menu is pulled down,
and other menu shortcuts use Ctrl, Meta, or function keys.

    It is probably reasonable to use either of these styles since most people
are familiar with both.

The Object Hierarchy

    From the point of view of the JX user, the hierarchy of objects at run-time
is more important than the hierarchy of inheritance because the former decides
how one uses the library in practice while the latter is only useful when
extending the library with custom objects.

    The object hierarchy can be separated into three layers:

    1)  Application
    2)  Displays
    3)  Documents, WindowDirectors, and DialogDirectors
    4)  Containers (Windows and Widgets)

    The Application manages the main event loop, facilitates interaction between
Documents, and creates gUserNotification, gChooseSaveFile, and gCreatePG.  There
is always exactly one Application object in any program, which is normally
created in main().

    Each X display that the application connects to has an associated JXDisplay
object.  Every Document, WindowDirector, DialogDirector, and Window is
associated with a particular Display.

    Each Document is responsible for a collection of data and a Window to
display it in and is usually owned by the Application.  A WindowDirector is only
responsible for a Window and is usually owned by a Document or another
WindowDirector.  A DialogDirector is also responsible only for a Window.  If it
is modal, it suspends its owner while its Window is active.

    Every Container can contain other Containers.  Windows are top level
Containers because they are not contained by anything else.  Windows contain
Widgets, which in turn can contain other Widgets.

    When an object is deleted, it deletes all the objects that it owns or
contains.

Typical Usage

    Programs that require a graphical user interface typically fall into one of
three categories:

    1)  Single document
    2)  Multiple documents
    3)  Utility

    Single document applications store one related set of data.  The
archetypical example is a simple text editor.  The user runs a separate copy of
the program for each file to be edited.  Such programs can be handled with a
single Document owning the main Window.  Auxiliary information can be displayed
in WindowDirectors owned by the Document.  If the information displayed by a
WindowDirector is actually part of the Document, then one can set the
WindowDirector to only hide itself instead of closing so that the data isn't
lost.  (via SetCloseAction())

    Sometimes, it is necessary or desirable to have interaction between
different sets of data.  One example is an interpreted language where each
subroutine is stored in a separate file.  To run a particular routine, all the
subroutines have to be loaded, and the user will appreciate the ability to pop
up subroutines and edit them without having to leave the program.  The most
obvious way to handle such programs is with a WindowDirector that manages a
control panel for creating and opening files, and multiple Documents that are
all owned by the Application.  If it doesn't make sense to have a separate
window for creating and opening files, one can derive a class from Application
to handle these commands (i.e. the Application object is of type MyApplication
instead of JXApplication) and then let the user select the commands from one of
the Document's menus.  As an example, the left-most menu could be:

    About      <-- Show dialog describing the program
    New    <-- Create a new Document
    Open       <-- Open another Document
    Close    <-- Close this document

The Document can easily pass these commands to the Application.  This way, the
user never needs to see that there is a single Application.  Every request for
New and Open creates a new window, and the Application automatically quits when
the last Document (technically, the last WindowDirector) is closed.

    Utility programs aim to help the user perform some task related to
controlling their computer.  This can range from a simple CPU load monitor to a
CD sound system control panel.  The feature shared by all such programs is that
they don't need to save anything other than some user preferences.  When the
user tells the program to quit, there is no danger of losing any valuable data.
Such programs can typically be handled with one or more WindowDirectors owned by
the Application.  User preferences can be saved by the destructor of each
WindowDirector or by the destructor of the Application, as appropriate.  (cfr.
JUNIXPrefsFile)

Displays

    Display objects often need to be passed as parameters to functions, but
application code will rarely need to use Display objects directly.  The
exception is when creating cursors.

    To create a Window on a particular display, call
JXApplication::SetCurrentDisplay() and then create the JXWindow object.
JXDisplayMenu provides an automated way to let the user open new displays and
select which display to put new Windows on.

Documents, Directors, and Dialogs

    Each Document is responsible for a collection of data and a Window to
display it in.  When the user asks to close a Document, the OKToClose() method
is invoked.  Derived classes must override this to let the user decide whether
to save the data or toss it.

    A WindowDirector is only responsible for a Window and is usually owned by a
Document or another WindowDirector.  (It can be owned by the Application, too.)
When the user asks to close a WindowDirector, the data displayed in the window
is summarily tossed.  However, if the user only asks to deactivate the
WindowDirector, the data that is displayed is verified on the assumption that
hidden data should not be invalid because the user can't get to it and fix it.

    A DialogDirector is also responsible only for a Window.  If it is modal, it
suspends its owner while its Window is active.  Closing a DialogDirector also
summarily tosses the data it contains.  Since one usually wants to at least look
at the information that was entered before tossing it, deactivating (via
EndDialog()) is the correct way to finish a dialog.  DialogDirectors always call
Close() after successfully deactivating.
    DialogDirectors automatically support OK and Cancel buttons (via
SetButtons()--modal dialogs must have an OK button) and deactivate themselves
when either one is pressed.  (The OK button only succeeds if the information
that was entered is valid.)  In order to notify the dialog's owner about this,
DialogDirectors always broadcast a message (JXDialogDirector::Deactivated) when
they are deactivated.  After activating a dialog, the owner simply has to listen
for this deactivate message in Receive() and then extract any information it
wants.
    To provide custom buttons in the dialog, the class derived from
JXDialogDirector merely has to create them and ListenTo() them.  If part of the
action for such a button should be to close the dialog, simply call EndDialog().
Since this generates the deactivate message, extracting the data can still be
done in the deactivate message handler.
    JXInputField objects automatically provide for simple checks on the
information being entered.  JXStringInput objects can be set to require a
non-empty string and/or have a maximum allowable length.  JXFloatInput and
JXIntegerInput objects require numbers and integers, respectively, and can also
constrain the value entered to be within specified limits.  Derived classes can
be created to implement more complex restrictions.  For restrictions involving
more than one value, the class derived from JXDialogDirector should override
OKToDeactivate(), check that the Dialog wasn't cancelled, then check whatever
conditions are required, and finally, notify the user if there is a problem.  If
the routine returns kFalse, the dialog window will not close.  (Of course, the
best approach is always to redesign the interface so that the graphical display
itself enforces the restrictions.  Popup menus, radio buttons, and checkboxes
are the most familiar examples.)
    Dependencies between items in a dialog window should be handled in the
Receive() method of the class derived from JXDialogDirector.  For example, if an
InputField is associated with a particular choice in a RadioGroup and should
only be active when this choice is selected, then the DialogDirector can listen
for changes in the RadioGroup selection and activate or deactive the InputField
as appropriate.

    The constructor for classes derived from JXDocument, JXWindowDirector, and
JXDialogDirector must create a Window and then call SetWindow().  (Code
generated by jxlayout does this automatically.)

Windows

    Each window must be owned by a class derived from JXWindowDirector.  Most of
the methods are self-explanatory, but a few deserve some comment.

    Close() always closes its WindowDirector.  However, selecting Quit from the
window menu provided by the X Window Manager can perform one of four actions:

    1)  Deactivate its WindowDirector (i.e. hide the window)
    2)  Close its WindowDirector
    3)  Close the X Display
    4)  Quit the Application

    The action is selectable via SetCloseAction().

Widgets

    Widgets provide the functionality required by all objects displayed in a
Window.  All Widgets must have an enclosure.  This can be either the Window or
another Widget.  The enclosure determines a lot about how the Widget acts.
Showing, hiding, activating, deactivating, moving, and resizing messages are all
passed down from the enclosure.  This makes it possible to group a set of
Widgets together inside an enclosure (usually derived from JXWidgetSet) and have
them all stay together and act as a unit.  (The classic example is a set of
radio buttons.)  In addition, the image of a Widget is always clipped to the
enclosure's Aperture.

    There are three rectangles associated with every Widget:  Bounds, Frame, and
Aperture.  The Bounds is the actual size of the Widget.  The Frame is the
bounding rectangle that the user sees in the window.  The Aperture is the frame
inset by the border width.  This is the visible part of the Bounds and the area
to which enclosed Widgets will be clipped when they are drawn.  The Bounds can
be larger or smaller than the Aperture.  If it is smaller, it is stuck in the
upper left corner of the Aperture.  If it is larger, it can scroll, but the
Aperture must always remain entirely inside the Bounds.  The default is for the
Bounds to be locked equal to the Aperture.  Use UnlockBounds() to change this,
and then use SetBounds() to change the size of the Bounds.
    Global coordinates are defined by the upper left corner of the window.
Local coordinates are defined by the upper left corner of the Bounds.  Enclosure
coordinates are the local coordinates of the enclosing Widget.  Moving the Frame
(Place(), Move()) is done in enclosure coordinates.  Changing the Frame size
(SetSize(), AdjustSize()) and incremental scrolling (Scroll()) are obviously
independent of the coordinate system.  Absolute scrolling (ScrollTo(),
ScrollToRect()) uses local coordinates.
    When a Widget's enclosure's Bounds is resized, the Widget will adjust itself
according to its resizing options.  If an edge is fixed, it always remains the
same distance from the corresponding edge of its enclosure.  If a dimension is
elastic, both edges remain the same distance from the corresponding edges of its
enclosure.

    Most of the methods are self-explanatory.  To redraw a Widget at the next
convenient updating point, call Refresh().  To redraw a Widget immediately, call
Redraw().  ScrollTo() scrolls the Widget so that the given point (in local
coordinates) is at the upper left corner of the Aperture.  ScrollToRect()
scrolls the Widget as little as possible to make the given rectangle (in local
coordinates) visible in the Aperture.
    Never call KillFocus() because it removes the focus from a Widget regardless
of the value returned by OKToUnfocus().  This is dangerous because information
entered by the user should always be verified.  It is provided only because
DialogDirectors need to be able to respond correctly to the Cancel button.

Drawing Widgets

    Unlike all other windowing systems, X Windows does not support printing.
JPainter was created to fill this gap so that the same code can be used to draw
to the screen and to a Postscript page.  JPainter encapsulates all the functions
that can be supported by both X and Postscript.  Thus, code written to use only
JPainter methods will work with both JXWindowPainter and JXPrinter objects.

    WindowPainter objects are always created by JX and passed to the appropriate
Draw() function.  JXPrinter objects are usually created by Documents.

    If you need to move the drawing origin at any time, use ShiftOrigin() rather
than SetOrigin().  It is also a good idea to always put the origin back where it
was after you are finished.

    If you need to change the clipping rectangle at any time, use SetClipRect()
rather than SetDefaultClipRect().  (The latter requires global coordinates,
which your code shouldn't use.)  It is also a good idea to always use
ResetClipRect() after you are finished.

    After creating a JXPrinter object, the correct procedure is to enter a loop
as follows:

    JBoolean done      = kFalse;
    JBoolean cancelled = kFalse;
    printer->OpenDocument();
    while (!done)
        {
        if (!printer->NewPage())
            {
            cancelled = kTrue;
            break;
            }

        // your code -- calls printer->LockHeader()

        DrawHeader(printer);

        // your code -- calls printer->LockFooter()

        DrawFooter(printer);

        // your code -- gets page number from printer->GetPageInfo()

        done = DrawPage(printer);
        }

    if (!cancelled)
        {
        printer->CloseDocument();
        }

    Headers and footers are best implemented inside the loop as shown.  Simply
draw the header and footer information and then use LockHeader() and
LockFooter() to prevent any more drawing in these regions.  When the main
drawing code calls GetPageInfo(), it will see only the area that remains after
removing the header and footer.

    OpenDocument() creates a ProgressDisplay window that tells the user which
page is being printed and lets the user cancel the process.  If the user decides
to cancel, NewPage() will automatically call CancelDocument() and then return
kFalse.  It is important to note that doing anything after printing has been
cancelled is considered to be a fatal error.  Thus, in the above code, the loop
is terminated immediately after cancellation, and CloseDocument() is only called
if the process was not cancelled.

Colors

    jXColors.h defines the colors pre-allocated by JX in every Colormap.  To
allocate other colors, use the Widget's JXColormap object.  (You can get this
from the Widget's Window.)  The Colormap is responsible for managing both static
and dynamic colors in an efficient way.  The Widget that allocates a particular
color is also responsible for deallocating it, in its destructor at the very
latest.

    Not all Colormaps can allocate dynamic colors.  If a Widget needs dynamic
colors and the default Colormap provided by the Display cannot provide them, one
can create a new Colormap and pass this to the Window via its constructor.  The
Colormap of a Window cannot be changed once the Window has been created because
X does not support it.

    JXColormap returns values of type JColorIndex instead of raw X pixel values.
This is done for several reasons.  First, the application code is easier to
write if the default colors allocated by JX are the same on every display, but
each X server will provide different pixel values.  In addition, JXDisplay will
automatically switch to a private colormap if the default colormap runs out of
space.  JColorIndex insures that nobody has to recalculate color indices when
this happens.  (For you efficiency fanatics, using a JColorIndex is just as
efficient as an X pixel value because it only requires a single lookup in an
array to convert a JColorIndex to an X pixel value.)

Drawing during a mouse drag

    Normally, all drawing for a Widget should only be done inside Draw().
However, it is sometimes necessary to draw things while the user is dragging the
mouse. (e.g. a selection rectangle)  JXDragPainter was created for this purpose.
JXWidget provides two ways to create a DragPainter:  CreateDragInsidePainter()
and CreateDragOutsidePainter().  The first function creates a DragPainter for
dragging inside the Widget's aperture.  This is typically what you will use.
The second function creates a DragPainter for dragging inside the Widget's
enclosure's aperture.  This is useful if you need to draw outside the Widget's
aperture, e.g. if you want to drag the Widget itself around.

    The only correct way to create a DragPainter is via JXWidget.  In addition,
you must call DeleteDragPainter() when you are done with the object.  This is
required because JXWidget keeps track of the DragPainter object in order to keep
it up to date when the Widget scrolls.  JXWidget only allows one active
DragPainter at a time, so you will trigger an assert if you forget to call
DeleteDragPainter().  One should never need more than one DragPainter object
because there is only one mouse.

    Thus, the simplest is to call the appropriate create routine in
HandleMouseDown(), call GetDragPainter() in HandleMouseDrag(), and then call
DeleteDragPainter() in HandleMouseUp().

Dragging a dividing line

    Dividing lines allow the user to decide how an area should be partitioned.
JXHorizPartition provides a horizontal partitioning of a rectangle, and
JXVertPartition provides a vertical partitioning.  These Widgets are not derived
from JXScrollableWidget because one only needs adjustable partitions when there
is a fixed amount of space.

    The default behavior when the entire partition is resized is as follows:

    1)  If all compartments are elastic, each one changes size by the same
amount.
    2)  If a single compartment is designated as elastic, only this one changes
size.

    All compartments are elastic if elasticIndex is zero.  In this case, the
width of every compartment must be specified in the constructor.  If
elasticIndex is non-zero, then the widths of all but one compartment are
specified and fixed, and the width of the elastic compartment is calculated
automatically.  To change this behavior, derive a new class and override
ApertureChanged() to adjust the width of each compartment as follows:

    void
    MyHorizPartition::ApertureChanged
        (
        const JRect& newApertureGlobal
        )
    {
        // First, let the base class do whatever it wants to.

        JXHorizPartition::ApertureChanged(newApertureGlobal);

        // Now call your code to adjust the widths of the compartments.

        AdjustCompartmentWidths(newApertureGlobal);
    }

    Since one can place one type of Partition inside the other, one can achieve
almost any conceivable geometry.  For custom arrangements, the correct way to
handle dividing lines is described below.  (It is important to remember that the
method for adjusting the arrangement must be easy for the user to comprehend.)

1)    Derive a class from JXWidgetSet to contain all the other Widgets.
2)    In this derived class, implement Draw() to draw the dividing lines.
3)    Implement mouse dragging to allow dragging of each dividing line.  After a
mouse drag, adjust the sizes and positions of the enclosed Widgets.

Scrolling

    Plain Widgets do not scroll because the Bounds is locked equal to the
Aperture.  To make a scrollable Widget, derive the class from JXScrollableWidget
instead of JXWidget.  This automatically unlocks the Bounds, so the derived
class only has to call SetBounds().  It also automatically supports the Page Up,
Page Down, Home, and End keys.  If your derived class needs to handle key
presses, be sure to call the inherited HandleKeyPress() function so that these
keys can be processed correctly.

    JXScrollbarSet manages a pair of scroll bars and provides a Container (via
GetScrollEnclosure()) within which to place ScrollableWidgets.  To scroll a
single Widget, pass the ScrollbarSet to the ScrollableWidget's constructor.  The
scroll bars will then automatically stay in sync with the ScrollableWidget's
Bounds.
    To scroll several Widgets simultaneously, you must write custom code to
arrange them inside the Container returned by GetScrollEnclosure() and then keep
the scroll bars in sync with the display.

Handling events

    All events are processed by virtual functions defined in JXContainer and
JXWidget.  All event handlers are protected unless stated otherwise.

virtual void Draw(JXWindowPainter& p, const JRect& rect);
virtual void DrawBorder(JXWindowPainter& p, const JRect& frame);
virtual void DrawBackground(JXWindowPainter& p, const JRect& frame);

    Draw() and DrawBorder() must be overridden by every new derived class.
DrawBackground() is implemented by JXWidget.  Use SetBackColor() and
SetFocusColor() to change the color drawn by JXWidget.

virtual void HandleMouseEnter();
virtual void HandleMouseHere(const JPoint& pt, const JXKeyModifiers& modifiers);
virtual void HandleMouseLeave();

    These functions are called when the cursor is inside the Widget's Frame and
the mouse is not pressed.

virtual void AdjustCursor(const JPoint& pt, const JXKeyModifiers& modifiers);

    This function is called while the cursor is inside the Widget's Frame.

    To change the default cursor for a Widget use SetCursor().  Custom cursors
can be created with the functions in JXDisplay.  For more control over the
cursor (e.g. different cursors in different regions or at different times),
override AdjustCursor().  To animate the cursor, use CreateCursorAnimator() to
attach a JXCursorAnimator object to the Widget.  Use RemoveCursorAnimator() to
stop the animation.

virtual void HandleMouseDown(
                const JPoint& pt, const JXMouseButton button,
                const JSize clickCount, const JXButtonStates& buttonStates,
                const JXKeyModifiers& modifiers);
virtual void HandleMouseDrag(
                const JPoint& pt, const JXButtonStates& buttonStates,
                const JXKeyModifiers& modifiers);
virtual void HandleMouseUp(
                const JPoint& pt, const JXMouseButton button,
                const JXButtonStates& buttonStates,
                const JXKeyModifiers& modifiers);

    These functions are called to report mouse clicks.  clickCount in
HandleMouseDown() specifies the number of consecutive, rapid-fire clicks
performed with the same button in the same part of the Widget.

    It is safe to delete a Widget in HandleMouseDown() and in HandleMouseUp(),
but not in HandleMouseDrag().  The code is written this way because the
application should wait until the user makes a decision by releasing the mouse
button.

virtual JBoolean HitSamePart(const JPoint& pt1, const JPoint& pt2) const;

    To control when a set of rapid-fire clicks should increment clickCount in
HandleMouseDown(), override HitSamePart() and return kTrue if the two given
clicks should be considered as a double click.

virtual void HandleKeyPress(const int key, const JXKeyModifiers& modifiers);

    This function is called whenever a key is pressed.  If the key is not
needed, is must be passed to the base class.

    WantInput() must be called in order to receive keypress events.  Since JX
uses Tab to switch focus between Widgets, there is a special flag for requesting
this key.  It is suggested that derived classes not request it unless they
really need it.  This helps to make the user interface more uniform.

virtual void HandleShortcut(const int key, const JXKeyModifiers& modifiers);

    Each Window maintains a list of shortcut keys.  These keys are used to
activate button, checkboxes, menu items, etc.  All shortcut keys are sent to
HandleShortcut() instead of HandleKeyPress().  If the key is not recognized, is
must be passed to the base class.

virtual JBoolean HandleClientMessage(const XClientMessageEvent& clientMessage);

    This function is called every time an X client message is received.  If the
message is not recognized, this function should always pass it to the base
class.  If the message is recognized, it should handle it and then return kTrue.

    Special routines are provided to deal with the X Selection mechanism.  Refer
to the section on the X Selection for details.

Shortcuts

    As described above, shortcuts for a Widget generate calls to
HandleShortcut().  Shortcuts are normally specified by a single string with the
following format "<modifier><character><modifier><character>...".  The modifier
is optional and is either an up caret (^) to indicate Control or a hash (#) to
indicate Meta.  Modifiers that cannot be represented this way can be installed
by calling JXWindow::InstallShortcut(JXWidget* widget, const int key, const
JXKeyModifiers& modifiers) where key can be any X keysym.

    Shortcuts are sent directly to the Widgets that requested them and not to
the Widget that currently has focus.  It is therefore a good idea to require a
modifier for all shortcuts.  For consistency with JX, it is suggested that Meta
always be used.

    Each Widget is responsible for somehow showing the user that it has a
shortcut.  As an example, each button searches its label for the first character
in its shortcut list and underlines it.

The X Selection (clipboard)

    Support for the X Selection mechanism is built into JXWidget.  To support
Copy, derived classes must first call AddSelectionTarget() for each target that
they can support and then call BecomeSelectionOwner().  They must also override
ConvertSelection() to service Paste requests.  When the Widget loses ownership
of the selection, LostSelectionOwnership() will be called.  Derived classes can
override this if they need to perform special actions (e.g. deselecting text),
but must always remember to call the inherited version first.  If the class
supports different targets at different times, it should use
AddSelectionTarget() and RemoveSelectionTarget() to notify JX.

Periodic background tasks

    Since UNIX is a multi-tasking operating system, one never has to worry about
giving time to other programs.  However, sometimes one would like to give time
to several different tasks within the same program.  JXIdleTask provides a
solution.  Simply create a derived class and override Perform().  Then use
JXApplication::InstallIdleTask() to start the task.  Note that this is mainly
useful for lightweight tasks such as updating a Widget's appearance.  Heavy
processing should either force the user to wait by displaying a ProgressDisplay
or use fork().

Urgent updating tasks

    In some rare cases, one needs to change a Widget in a way that is illegal
within the given execution context.  As an example, it is not safe to change the
size of a Widget inside the Widget's drawing code because this will cause an
immediate redraw, a call to the drawing routine from within the drawing routine.
In such cases, one should create a derived class of JXUrgentTask, override
Perform(), and use JXApplication::InstallUrgentTask().  Urgent tasks are
automatically deleted after Perform() is called.

Images

    JXImage provides a clean interface to both Pixmaps and XImages.  There are
several different constructors, including ones for XBM and XPM data.  Drawing to
the Image is done via a JXImagePainter object obtained by calling
JXImage::CreatePainter().  There can be an unlimited number of active
ImagePainters for each Image.

    Each Image can also have a mask specified by a JXImageMask object.  The
constructor JXImageMask(const JXImage& image, const JColorIndex color) creates a
mask to remove all pixels of the specified color from the given image.  Since
JXImageMask derives from JXImage, one can draw to an ImageMask using an
ImagePainter.  JXImageMask::kPixelOff (kJXTransparentColor) is provided so one
can erase pixels from the mask.  All other colors add pixels to the mask.  This
way, the code that draws an image will also draw the mask for that image when
passed an ImagePainter associated with the mask.

    JXImageWidget provides a simple way to display an Image.

    Conversion between Pixmaps and XImages is handled internally, so clients
never need to worry about it except for efficiency concerns.  Drawing to the
Image requires a Pixmap, while GetColor() and SetColor() require an XImage.  To
avoid excessive swapping, one should try to group all calls to GetColor() and
SetColor() together.

    SetDefaultState() allows one to set whether the image data should normally
be stored on the server side or the client side.  Images that are being drawn in
visible windows should be stored on the server side to avoid having to
retransmit the data every time the window is redraw.

    X also puts another restriction on how Images can be used.  Each Image is
associated with a particular Display and a particular Colormap.  An Image can
only be drawn on its own Display and will be garbled if drawn to a Window using
a different Colormap.

Tables

    JTable from the JCore library implements all the system independent routines
for dealing with tables.  (Refer to the JCore manuals for the details.)  JXTable
implements all the system specific routines required by JTable, except for
TableDrawCell().  All table classes should therefore be derived from JXTable
instead of JTable.  JXEditTable implements all the system specific editing
routines required by JTable, so derived classes only need to override
JTable::ExtractInputData() and then implement the following routines:

CreateXInputField

    Create an input field to edit the specified cell and return the object as a
JXInputField.  Normally, one will create an object of type JXStringTableInput,
JXFloatTableInput, or JXIntegerTableInput because these are tuned to work with
tables derived from JXEditTable.

DeleteXInputField

    Delete the active input field.

    Some useful tables are provided as part of the JX library.  JXStringList
displays a column of strings stored in a JPtrArray<JString>.  JXStringTable
works with JStringTableData to display a table of strings.  JXFloatTable works
with JFloatTableData to display a table of numbers.  String and Float tables
also implement the routines required by JXEditTable, so derived classes only
have to call BeginEditing() to allow editing of the data displayed in the table.
To place simple restrictions on the input (e.g. length of string or range of
values), override CreateXInputField() to call the inherited function and then
install the restrictions.  For restrictions beyond those provided by classes
derived from JXInputField, override JTable::ExtractInputData() and display an
error message and return kFalse if the data is not acceptable.

    JXRowHeaderWidget and JXColHeaderWidget are provided to simplify the process
of displaying row and column headers for a table.  The sample code in
TestStringTable and TestNumberTable shows how to arrange the Widgets properly
inside the scrolling area.  To draw the row and column header labels
differently, create derived classes and override TableDrawCell().
JXRowHeaderWidget and JXColHeaderWidget also allow the user to change the row
heights and column widths, respectively, by dragging the dividing lines between
cells.  This behavior is off by default, and is usually only useful for column
widths since row heights are determined by the current font size.  To turn on
resizing, call TurnOnRowResizing() or TurnOnColResizing().  TurnOffRowResizing()
and TurnOffColResizing() turn the behavior off again.

Menus

    The JX menu system is very simple and also very powerful.  JXTextMenu
provides all the functionality that one expects from a menu, and it can be
placed anywhere in a Window or can be used as a sub-menu.  JXMenuBar manages the
geometry of a horizontal list of menus.  These two classes are sufficient for
most purposes.  The power comes from the fact that one can derive classes from
JXMenu to create menus to do anything.  Custom menus are simply derived classes
of JXMenuTable and work just like any other Table.

    Menus, like all other Widgets, can be placed anywhere in a window.  In
addition, menus can be attached as sub-menus for items on other Menus.  This
means that once the Menu is created, client code cannot tell the difference
between a Menu in a MenuBar, a Menu that is acting like a popup somewhere else
in the Window, and Menu that is a sub-menu of another Menu.  To make a popup
Menu of choices display the currently selected choice, call SetToPopupChoice().
Menus can be attached as sub-menus either via the second JXMenu constructor or
by calling AttachSubmenu().

    Menus broadcast two messages.  Just before the Menu opens, it broadcasts
JXMenu::NeedsUpdate.  Clients should respond to this message by activating or
deactivating menu items, turning checkboxes on or off, selecting the appropriate
items in radio groups, adjusting the text of items, etc.  The function
SetUpdateAction() can be used to set the default state of the menu items.  All
checkboxes and radio buttons are intially off because it is the responsibility
of the client to keep track of the settings.  CheckItem() turns on both
checkboxes and radio buttons.

    When an item is selected, the Menu broadcasts JXMenu::ItemSelected which
contains the index of the item.  This message will only be broadcast if the user
actually chooses a particular item.

    JXTextMenu supports styled text, an optional Image for each item, key
shortcuts for use when the menu is open, key shortcuts for use when the menu is
not open (non-menu shortcuts, NM for short).  SetItemShortcuts() sets the key
shortcuts for an item when the menu is open.  If the first character in this
list is found in the text of the menu item it is underlined when the menu is
open.  SetItemNMShortcut() sets the single key shortcut for an item when the
menu is not open.  The string passed to this function is parsed as follows:

    Prepended "Ctrl-", "Meta-", "Ctrl-Shift-", and "Meta-Shift-" are converted
into modifier flags.  If the rest of the string is a single character, then this
is the key.  The strings "dash", "minus", "plus", "period", and "comma" are
translated to characters because the actual characters can confuse the user.
(e.g. Use "Ctrl-dash" instead of "Ctrl--")  The strings "F1" through "F35" are
translated to the corresponding function keys that X provides.  The resulting
character and modifiers is registered as a shortcut and generates a
JXMenu::ItemSelected message when pressed.  It is legal to pass in a string that
cannot be parsed.  (e.g. "Ctrl-middle-click")  In this case, the string will
simply be displayed without registering a shortcut.

    JXTextMenu actually has the ability to display two different sets of menu
items:  one set when the Shift key is not pressed and one set when the Shift key
is pressed.  The JXMenu::ItemSelected message includes the state of the Shift
key so that one can tell which action to take.  Since the presence of this
feature will not be obvious to the user, it should only be used for menu items
that are clearly duals (e.g. Search forward and Search backward) and should be
clearly mentioned in the documentation.  When using this feature for menu items
with non-menu shortcuts, one should always use a pair like "Meta-S" and
"Meta-Shift-S."

    JXTextMenu::SetMenuItems() is useful for building a menu from a single
string.  The format is "<item text> <options> | <item text> <options> | ...".
The options are as follows:

    Option    Effect
    %d    item is disabled
    %l    item is followed by a separator line
    %b    item is a checkbox
    %r    item is a radio button
    %h <chars>    specify shortcuts for item (a list of single characters)
    %k <chars>    specify non-menu shortcut
    %S <chars>    specify item string when Shift is pressed
    %K <chars>    specify non-menu shortcut when Shift is pressed

    In addition to JXTextMenu, JX also includes JXIconMenu which provides a way
to display a grid of Images in a menu.  You specify the width of the menu and
the height is determined by the total number of items.

    Note that, since Images are constructed for a particular Colormap, and Menus
use the Colormaps of the Windows that they pop up from, Images in a Menu must
use the same Colormap as the Menu's Window.

Custom menus

    This section describes how to create custom menus.  Since this is not a
trivial task, the entire source for the TextMenu and IconMenu suites is included
with the JX distribution as examples.

1)    Create a derived class of JXMenuData to store the information that the
menu will display.  InsertItem(), DeleteItem(), and DeleteAll() must call the
base class version at some point so that the data stored in JXMenuData will stay
in sync with the data in your derived class.

2)    Create a derived class of JXMenuTable to display the information.  There
is no fixed mapping between menu items and table cells.  You can implement
CellToItemIndex() to implement any mapping you want.  (Be sure that the user can
understand the it.)  MenuHilightItem() and MenuUnhilightItem() must be
implemented so JXMenuTable can tell you which item (if any) is currently under
the mouse cursor.  You must use this information to hilight the item in some
way.  GetSubmenuPoints(const JIndex itemIndex, JPoint* leftPt, JPoint* rightPt)
must be implemented to return two points (in local coordinates) where a sub-menu
could be placed.  rightPt should be somewhere to the right of the item's cell,
while leftPt should be somewhere to the left of the item's cell.  rightPt gets
preference. leftPt is used if rightPt would cause part of the sub-menu to be off
the screen.

3)    Create a derived class of JXMenuDirector that overrides CreateMenuTable()
to create the correct MenuTable object.

4)    Create a derived class of JXMenu to provide an interface to your derived
class of JXMenuData and to override CreateWindow() to create the correct
MenuDirector object.

User Interface Classes from JCore

JXUserNotification

    This implement JUserNotification for JX.  It displays a dialog window that
blocks the entire application until it is dismissed by the user.

JXStandAlonePG

    This implement JProgressDisplay for JX.  If the process is to run in the
foreground (e.g. a tight loop that ignores the event loop), it displays a dialog
window that blocks the entire application until the process is finished.  If the
process is to run in the background (e.g. via an IdleTask), it displays the same
dialog window, but does not block.

JXProgressDisplay

    This implement the functionality of JProgressDisplay for JX, but not the
display.  The client must create the Widgets to display the progress and then
call SetItems().  This is useful when one wants to display the progress of an
operation without creating a new window.

JXChooseSaveFile

    This suite of classes implements JChooseSaveFile for JX.  It displays a
dialog window that blocks the entire application until it is dismissed by the
user.

    Each dialog window is encapsulated in a separate class:  JXChooseFileDialog,
JXSaveFileDialog, and JXChoosePathDialog.  The unique feature is that these
classes are designed to allow further derived classes.  This allows one to add
functionality to each dialog window.  Derived classes must create a
BuildWindow() function to create the Window.  (The constructor must not call
this.)  Inside BuildWindow(), they must call <inherited>::SetObjects() and then
set up the extra items that the derived class adds.  (To allow further derived
classes, this code should be put in a SetObjects() function instead of being
inlined after the Window creation code.)

    To use these derived classes, one simply creates a derived class of
JXChooseSaveFile and overrides the appropriate Create*Dialog() function to
create the appropriate derived class and then call BuildWindow().

Miscellaneous Class Summary

JXDecorRect

    The class itself doesn't actually do anything, but it does define the useful
concept of a decorative enclosure for a set of related Widgets.  Derived classes
implement DrawBorder().

JXFileDocument

    This class provides functionality for Documents that are stored in a file on
disk.  It implements all functions required by JXDocument.  The only function
that it requires from derived classes is WriteFile().

    JXFileDocument handles all the dialog windows:  Save as, OK To Close, and OK
To Revert.  These can be triggered via SaveInNewFile(), OKToClose(), and
OKToRevert().  The messages can also be changed.  All occurrences of %f in these
messages are replaced by the name of the file.  One can also replace the file
chooser object via SetChooseSaveFile().  This is required in order to display
custom dialog windows.

    SaveInCurrentFile() saves the data in the current file, if it exists on
disk.  Otherwise, it calls SaveInNewFile().  The user is automatically warned if
the file exists on disk but has been modified since it was read in.

    Call DataModified() to specify that the data needs to be saved before
closing.  ChangesDiscarded() does the opposite.

    DefaultCanReadASCIIFile() provides a convenient way to check the type of a
file if one adheres to the format "<file signature> <version number> <data>".

    ShouldMakeBackupFile() can be used to specify whether or not a backup file
(<name>~) should be created when saving changes to the data.

JXHelpDirector

    This provides a simple way to display help for an application.  Pass the
text to be displayed into the constructor and everything else is taken care of
automatically.

JXInputField

    This is the base class for all dialog window input fields.  Derived classes
include JXStringInput, JXFloatInput, and JXIntegerInput.

JXScrollbar

    Scrollbars take integer values from zero to a client specified maximum.
Sliders (see below) provide the general case.

JXScrollbarSet

    This manages the geometry of a pair of scrollbars and an enclosure for the
Widgets that listen to the scrollbars.  GetScrollEnclosure() returns this
enclosure.  The ScrollableWidgets that listen to the scrollbars should all be
placed inside this enclosure.

JXSliderBase

    This is the base class for all Slider classes.  Sliders provide a way for
users to graphically set a value between specified limits with a specified
increment between values.  The limits and the step size are all floating point
numbers.

JXStaticText

    This class displays a non-editable text string.  The font is adjustable.

JXWidgetSet

    The class itself doesn't actually do anything, but it does define the useful
concept of a passive enclosure for a set of related Widgets.  Derived classes
should construct and arrange the Widgets so that clients can create the entire
package with one call.  As an example, refer to JXScrollbarSet above.

Hidden Feature Reference

    Tab shifts focus to the next Widget.  Shift-Tab shifts focus to the previous
Widget.

JXChooseSaveFile

    Meta-up-arrow switches to the parent directory.  Meta-down-arrow switches to
the selected directory.  Both of these shortcuts work regardless of which Widget
has focus.

JXHoriz/VertPartition

    The cursor will change shape when it is placed in the regions between
compartments.  Clicking and dragging moves the dividing line between adjacent
compartments.  Holding down the Meta key when clicking and dragging forces all
the compartments to shrink to make extra space for the compartment being
resized.

JXInputField

    If text is selected, Ctrl-K cuts the selection.  Otherwise, it cuts to the
end of the text.

JXRow/ColHeaderWidget

    When resizing is enabled, the cursor will change shape when it is placed on
the border between cells.  Clicking and dragging resizes the cells.  Holding
down the Meta key when clicking and dragging forces all the cells to end up
having the same width.

JXScrollableWidget

    Understands XK_Home, XK_End, XK_Page_Up, and XK_Page_Down.

JXTEBase

    Forward delete (0x7F) deletes the character following the caret.  Meta-D
deletes all the characters to the end of the word that the caret is in.
Shift-Meta-D deletes all the characters to the start of the word that the caret
is in.

    The arrow keys obviously move the caret around inside the text.  Holding
down the Meta key makes the left and right arrows move the caret by one word at
a time.  Holding down the Shift key makes the up and down arrows move the caret
to the beginning and end of the file, respectively, while the left and right
arrows move the caret to the beginning and end of the current line,
respectively.

    Meta-Z, Ctrl-Z,Ctrl-_    Undo
    Meta-X, Ctrl-X, Ctrl-K    Cut
    Meta-C, Ctrl-C    Copy
    Meta-V, Ctrl-V, Ctrl-Y    Paste
    Meta-A, Ctrl-A    Select all

    Note that these features work with or without an Edit menu, so all
InputFields have these functions.  Note also that selecting text does not
automatically perform a copy.  This allows pasting to replace the selection.