This chapter describes the basics of the X-Plane widgets library.
What Is the Widgets Library
The X-Plane Widgets library is a code library that implements a high-level
cross-platform UI framework inside X-Plane. The widgets library makes it
easy to create complex user interfaces and provides for most of the common UI
components a plugin will need.
A widget is a single user interface element, like a push button, scroll bar,
text entry field, etc. The widgets library provides many kinds of widgets
and the code necessary to work with them.
Why Use the Widgets Library
There are many reasons to use the Widgets library:
Widgets are cross platform. With the widgets library we can easily
create one user interface for Macintosh and PC.
Widgets match X-Plane's appearance and look consistent within the simulator.
Widgets are high-level. We need to write no OpenGL code and very
little event-handling code to use widgets.
Widgets are fast. They use X-Plane's built in UI textures and have been
tuned to run without slowing the sim down.
Widgets are extensible. We can easily write our own widgets and
integrate them with the existing ones for complex user interfaces.
Widgets provide an API that is similar to what we might find on Macintosh
Widgets provide many premade user interface elements that require very little
or no modification.
How Using Widgets are Different from the XPLM UI APIs
The XPLM display APIs are not persistent. Every time the sim redraws the
screen, we are asked to redraw the window. Widgets are
persistent. We create a widget once and it manages itself,
calling we back only when something interesting happens (like the user
clicking a button).
The XPLM display APIs provide a very general "window" with no special
behaviors. The Widgets premade window classes have title bars, are
draggable, select themselves, and have several preset styles; these are
"windows" as users know them.
The XPLM display APIs provide a flat space; a plugin gets a window and fills in
the blanks. Widgets are nestable into widget hierarchies that can
represent complex user interfaces.
A widget is a single roughly rectangular user interface elements.
Examples of widgets include windows, buttons, text entry fields and
Widgets are refered to via widget ID s. A widget ID is an opaque 32-bit
handle to the widget. A widget ID is similar to an HWND on Windows or a
ControlRef on Macintosh. We never manipulate the widget ID
directly; we only pass it back to the widgets library.
Each instance of a widget has a number of properties. A property
is a 32-bit value assigned to a widget. Each property has a 32-bit property
ID that describes it. Any widget can have any number of
properties. Typically each widget will have properties that are useful to
its widget callback (see below). Examples of properties include the style
of a window or the state of a check box (checked or unchecked).
A widget also has a descriptor, a variable-length string attached to the
widget. The widget's descriptor may be interpretted differently depending
on the widget, but often is used for the title of a window or the text for a
Widget Callback Functions and Messages
Each widget has a callback function that implements the widget's behavior.
Widgets send each other messages to cause actions to happen. The
widgets library also sends widgets messages, as can the plugin. Examples
of messages include "draw ourselves", "a child was added" and "a push button
Widgets can actually have multiple callback functions. When a widget has
multiple callback functions, they are called in order. This
allows we to specialize a widget's behavior. Adding a callback to a
widget is called subclassing a widget. A widget with multiple
callback functions is similar to a class that inherits from another class;
behavior not provided by the subclassing callback is handled by the original
We use subclassing to customize widget behavior and to receive messages
from the widget system. For example, we can subclass a push button.
When the push button is clicked, it sends itself an "I was pushed"
message. The callback function for the push button can intercept
this message and take action.
Widget Hierarchy, Coordinates and Exposed Areas
Widgets are arranged in a tree known as a widget heirarchy. If one
widget contains another, they are known as parent and child widgets.
All widgets may have zero or more children and zero or one parents.
A widget may be an actual window in the plugin system, or it may not. If
it is, it is said to be a root widget. If a widget is nested
inside a widget that is a root wiget then the widget hierarchy is rooted.
Rooted widget hierarchies may be seen by the user, but rootless ones will
not be. In other words, for the widget to be seen, it must have a parent
that is a root widget.
Widgets have a rectangular area described by its top, bottom, left and right,
called its geometry. These coordinates are always in global screen
coordinates, e.g. 0,0 is the bottom-left corner of the screen, and 1024, 768 is
the top right. (The size of the screen may vary with user settings and
the version of x-plane; use the XPLM Display APIs to determine the upper right
corner of the screen.) The motivation for this coordinate system will be
Only the portion of a widget's area that is contained in all of its parent
widget's area can be seen by the user. This property is recursive; each
widget is clipped by all of its parents. This guarantees that a button
will not draw outside of a window, for example. The widgets libary uses
the OpenGL scizzors function to clip widgets to their parents' rectangles.
Just about any OpenGL hardware capable of running X-Plane provides this
function in hardware, so the clipping does not have a frame-rate penalty.
The area of a widget that is actually visible is its exposed geometry.
Exposed geometry can be used to implement a scrolling display. Simply
move a large widget that is inside a window up and down in screen space; only
the portion of the widget that is visible through the window will be drawn.
For performance we can determine the exposed geometry and only draw
The motivation for using a single global coordinate space is the following:
The global coordinate space is probably one of the least conventional design
decisions for the widgets system, but so far it has proven to be significantly
simpler to work with than nested coordinate-system frameworks.
It eliminates all coordinate conversions when moving between widgets in a
hierarchy, which makes development and debugging of complex UI code easier.
For any widget that is expensive to draw and not fully exposed the widget
should only draw its exposed geometry, so the area it draws will not be
anchored at 0,0 even when using widget-specific coordinates.
For most OpenGL code an offset must be provided as well as a width and height,
so having a widget's upper-left always be 0,0 doesn't provide a significant
simplification of performance enhancement to the code.
Standard Widget Types
The widgets library comes with a number of built in widgets. They are
identified by widget classes. Each widget class represents a built-in
premade widget that implements a useful behavior. Often several similar
widgets will have the same class. For example, push buttons, radio
buttons and check boxes are all one widget class. A property of the
widget identifies which type of button to implement.
The standard widgets are not special; they are simply implementations layered
on top of the widgets library. There is nothing in the standard widgets
that a plugin could not implement by hand.
Procedural Vs. Object-Oriented Programming
For programmers that are used to UI frameworks in object oriented languages
(such as would be found in Delphi, or PowerPlant or MFC in the C++ world)
programming widgets in C will be an adjustment.
A widget callback function essentially implements all of the overridden virtual
functions for a subclass of a widget. Multiple callback functions provide
inheritence. The widget message ID describes which virtual function is
being called. The default widget implementation does nothing, so we
do not need to provide implementations for 'empty' virtual functions.
Widget properties represent member data on a widget. Users can set and
get these properties arbitrarily, and extra properties may be present; widgets
do not have as strong encapsulation of data as some object oriented languages.
Using the Widgets Library
This section describes how to creaet user interfaces using the Widgets library.
Creating Widget Hierarchies
Widget hierarchies can be created in any order, but usually they are created
from the top down. The basic step is to create the widgets and set their
The function XPCreateWidget is used to create a widget and takes a number of
arguments: the location of the widget on screen (in screen coordinates; the
bottom left is 0, 0), whether the widget is initially visible, whether it is a
root widget, its descriptor string, any widget containing it, and its class.
< Code Example: using XPCreateWidget to create a few widgets.>
The top widget in the hierarchy must be a root widget. This means that it
will be visible on the screen. All other widgets should not be root
widgets, but should have a parent widget. Pass 0 or NULL for the parent
widget of the root widget to indicate that it has no parent.
Given a widget or widget hierarchy, we can rearrange the hierarchy by
calling XPPlaceWidgetWithin. XPPlaceWidgetWithin will remove the moving
widget from its parent (if it has one) and embed it in a new parent. The
most recently added child of a parent will be visually "on top" of its
sibblings but clipped to its parent.
We can use XPUCreateWidgets to easily create a number of widgets in a
hierarchy. We pass in an array of structures describing each widget
and the widgets are created and nested for we. Often when dealing with a
complex widget hierarchy it may be easiest to work with the widgets in an
array; this function makes building this array from a table of geometry
< Code Example: a dialog box using XPUCreateWidgets. >
Once we have created the widgets, we use XPSetWidgetProperty to
configure them by setting properties.
< Code Example: setting XPSetWidgetProperty to set up the dialog box. >
Most widgets will initialize their properties to reasonable values when
created; set widget properties to access customized behavior (to change a
window's style, for example).
Sometimes we may have to change the appearance of the widgets. The
most common task is to show or hide a widget. This can be done using the
XPShowWidget and XPHideWidget routines. Being visible is recursive;
if we hide a widget, all of its children are hidden too.
We can position a widget or widget hierarchy on screen using the
XPSetWidgetGeometry function. The movement of the children of the
widget we position is a function of the wiget class. Most root
widgets will move their children with them to keep the relative position
of the window's elements constant.
We can change widgets' appearance by using XPSetWidgetProperty or calling
XPSetWidgetDescriptor to change the string associated with a widget. This
is often used to change a dialog box's strings.
<Code Example: setting up a widgets dialog box.>
Handling Messages from Widgets
Once we have created the widget hierarchy, it takes care of itself until
the user wants to do something. The widget hiearchy will draw itself,
buttons will be clickable, the usere will be able to type. When we
need to respond to an action (for example, the enter or escape keys being
pressed or an 'OK' button being clicked) we write a widget function and
subclass one of the widgets to receive messages we are interested in.
Widgets are constantly sending messages to each other to accomplish the basic
user interface management tasks. When we attach the own widget
function to a widget, we will receive all of those messages before the
widget's normal handler. We return either 0 if we did not
handle the function or 1 if we did. The widget function can
then respond to a few widget functions uniquely.
Sometimes widget messages are sent up the widget hiearchy for convenience.
For example, when the push button widget is clicked, it sends an "I was
pushed" message to itself. If the push button does not handle this
message (which by default it does not), the message is sent to every widget in
the hierarchy up the root until someone handles it. One of the parameters
is the ID of the widget that first originated the click.
This pattern of sending widget messages up the hierarchy is done for most
messages that a plugin would be interested in overriding. This
allows us to provide one widget message function for an entire widget
hierarchy rather than one per widget.
< Example code: writing a widget message function >
We use the function XPAddWidgetCallback to add a new widget function to an
existing widget, changing its behavior. Typically we install the
widget function when we initialize the widgdet.
Cleaning Up Widgets
When we are done with the widgets, we must dispose them or
else we will leak memory! To dispose widgets, use the
XPDestroyWidget function. If we destroy widgets we can
recursively destroy their children too (which will clean up the whole
hierarchy), or just destroy the root widget, leaving all children parentless
<Example Code: Cleaning up Widgets>
Introduction to the Standard Widgets
The widgets library comes with a number of standard widgets that provide many
user interface features. This document will not get into the details of
the standard widgets; the standard widgets web page in the reference section of
the SDK describes each widget in detail. This section describes some of
the design ideas behind the standard widgets.
The standard widgets are divided intowiwdget classes. Each class handles
a similar set of widget behaviors. For example, one widget class handles
push buttons and check box buttons. We set a property on a widget to
customize its behavior and appearance.
< TODO: include a general table of the widget class and its overall purpose.
The standard widgets send messages to themselves that then go up the hierarchy
to notify we of user interactions. Each standard widget defines
unique message IDs for widget events and property IDs and enumerations to
control widget behavihors.
Creating Our Own Widgets
We can create our own widgets. Simply provide a widget function that will
handle the entire widget's set of behaviors. We then use
XPCreateCustomWidget to create the widget, passing in the widget function.
Widget Message Dispatching
Widget messages can be dispatched based on a number of modes:
Use the routine XPSendMessageToWidget from the plugin or within the wigets to
send messages to the widgets.
Direct. The message is sent to each widget function of the widget from
the most recently added to the original widget function until one returns that
the message has been handled.
Up Chain. The message is sent to each widget function of the widget from
the most recently added to the original widget function until one returns that
the message has been handled. If no handler handles the widget function,
the message is then sent to the parent of the widget (if it has one) in Up
Recursive. The message is sent to each widget function of the widget from
the most recently added to the original widget function until one returns that
the message has been handled. The message is then sent to all of the
widget's children in recursive mode.
Direct All Callbacks. The message is sent to each widget function of the
widget from the most recently added to the original widget function, even if
the callback is handled.
Once. The message is only sent to the most recent widget function of the
widget. This mode isn't commonly used.
Key Widget Messages
The widgets library defines some basic messages that are sent to the custom
Remember that multiple widgets might use the widget function. Attach
widget-specific information to widgets using properties. Do not use
global variables for per-widget data!
Create, Destroy. The create and destroy messages are sent to the widget
function when a wiget that uses the function is created and
destroyed. We should set any properties we must set on the
widget and use these functions for setup and cleanup of the widget.
Paint, Draw. The draw message is sent to the widget once per frame in
X-Plane to redraw the widget. We can intercept the paint message
instead for lower level drawing control, or draw to have the widets library
take care of clipping and child widgets for us..
KeyPress, KeyTakeFocus, KeyLoseFocus. These messages are sent when keys
are pressed or when the widget gains or loses keyboard focus. Key presses
are passed up the widget hierarchy if they are not handled by a child widget,
but only one widget can have 'focus' at a time in the entire system; this is
the widget that gets keystrokes first.
MouseDown, MouseDrag, MouseUp. These messages are sent to the widget to
track the mouse. There is no roll-over message; to implemenet roll-over
behaviors, simply check whether the mouse is over the widget's exposed geometry
from our draw function.
Reshape, ExposedChanged, AcceptChild, Shown, Hidden. These messages are
sent to the widget when it is moved, shown, hidden, or topology is changed.
DescriptorChanged, PropertyChanged. These messages are sent to the widget
when the properties or descriptors change. This can be useful if the
widget calculates internal cached state when these values change.
We can define the own widget properties and widget messages to provide an
API to the widget's unique functionality.
See the reference section for the specific functional areas:
XPWidgetDefs - Basic widget definitions.
XPWidgets - Core widget management functions.
XPStandardWidgets - Built in widget types.
XPWidgetUtils - Helper routines for implementing our own widgets and using
XPUIGraphics - Routines that draw standard UI elements using X-plane's UI
bitmaps. These are used by the standard widgets.