AG_Widget is the base class for GUI widgets (and windows) in Agar GUI.
AG_Widget can be attached (using
AG_ObjectAttach(3)) to any other
AG_Widget (known as the
General-purpose container widgets include
The class registration interface of AG_Object(3) allows new widgets to be implemented (or derived from existing classes). Widgets use the object system's AG_Event(3) to handle (and deliver) events. AG_Variable(3) provides the basis for memory bindings (see BINDINGS section).
Object operations specific to the
AG_Widget class are defined as follows:
draw() renders the widget to the graphics display. The code under draw() is referred to as the Rendering Context. Some functions (such as AG_WidgetBlitSurface()) are unsafe to call outside Rendering Context.
size_request() should return an initial, preferred geometry in px (without any guarantee that the request will be satisfied). For example, an AG_Label(3), might return the expected size of a rendered text label.
size_allocate() is called once the widget has been successfully allocated a new size or position within its parent (as described by the w, h, x and y members of the AG_SizeAlloc argument). Container widgets allocate the position and size of their children in size_allocate().
size_allocate() should return 0 on success and -1 if the allocation is not satisfactory for draw() to work at all (in which case the UNDERSIZE flag will be set and draw() will not run).
AG_Expand() makes the widget fill all available space in the parent. AG_ExpandHoriz() and AG_ExpandVert() makes the widget fill the available space horizontally or vertically.
Note: Most widget constructors accept EXPAND, HFILL and VFILL as option flags. Setting them is equivalent to calling AG_Expand(), AG_ExpandHoriz() and AG_ExpandVert().
AG_WidgetSizeReq() invokes the size_request() operation of the widget and returns its size requisition into req. AG_WidgetSizeAlloc() allocates the given position and geometry of the widget. If the w or h argument is <= 0, the AG_WIDGET_UNDERSIZE flag is set, preventing the widget from subsequent rendering.
AG_WidgetSizeReq() and AG_WidgetSizeAlloc() are meant to be called only from within the size_request() and size_allocate() functions of a container widget implementation, in order to size and position the child widgets attached to the container (if you must set widget geometries explicitely, use either the AG_Fixed(3) container, or create your own container widget).
The AG_SizeReq and AG_SizeAlloc structures are defined as follows:
AG_WidgetSetPosition() sets the effective position of the widget relative to its parent container. AG_WidgetSetSize() sets the size of the widget in pixels. AG_WidgetSetGeometry() sets both position and size of a widget from the specified AG_Rect. These functions are typically only used in the context of the size_request() and size_allocate() routines of container widgets.
AG_WidgetUpdate() requests an update of the computed coordinates and geometries of all widgets attached to the widget's current window. The widget may or may not be attached to a parent window (the actual update will be performed later, before rendering starts in AG_WindowDraw()). AG_WidgetUpdate() should be called following AG_ObjectAttach(3) or AG_ObjectDetach(3) calls made in event context, or manual modifications of the x, y, w, h fields of the AG_Widget structure.
The focus state of widgets enables the reception of specific types of
events which are filtered by default.
The focus state also affects the behavior and appearance of some widgets.
A widget holding focus (in a currently focused window) will receive mouse
mouse-motion(), mouse-button-up(), as well as keyboard events
key-down() (note that unfocused widgets can be configured to receive those events
unfiltered as well using the
AG_WidgetSetFocusable() sets the AG_WIDGET_FOCUSABLE flag which allows the widget to receive focus (0 = ignore, 1 = accept focus). Returns the previous setting.
AG_WidgetFocus() gives focus to the specified widget and all of its parent widgets including the parent AG_Window(3). Returns 1 on success and 0 if the widget is not accepting focus.
AG_WidgetUnfocus() removes the focus state from the given widget (including its child widgets, if any).
AG_WidgetIsFocused() returns 1 if the widget is currently holding focus (i.e., the widget has the focus flag set, and its parent window, if any, is focused as well). AG_WidgetIsFocusedInWindow() returns 1 if the widget has the focus flag set (without evaluating the focus state of any parent windows).
AG_WidgetForwardFocus() arranges automatic forwarding of the focus to a specified widget. Whenever AG_WidgetFocus will be invoked on widget, the focus will be given to widgetToFocus instead.
The AG_WidgetArea() routine tests whether view coordinates x and y lie inside of the widget's allocated space. The AG_WidgetRelativeArea() variant accepts widget coordinates.
These routines allow graphical surfaces to be managed (mapped in hardware or
software) and efficiently copied.
They must be called from Rendering Context (i.e., the
draw() operation of
The AG_WidgetBlit() function performs a software->hardware blit from the surface src to the video display at the given widget coordinates. AG_WidgetBlit() must invoked in Rendering Context. See AG_Surface(3) for more information on the Agar surface structure.
Software to hardware blits are slow, so the widget system provides an interface to efficiently take advantage of graphics hardware where it is available. AG_WidgetMapSurface() registers the specified AG_Surface(3) with the widget, returning an integer handle to that surface. The surface can be subsequently rendered by calling AG_WidgetBlitSurface() or AG_WidgetBlitFrom() using this handle. The exact manner in which the surface is rendered depends on the Agar driver in use. For OpenGL-based drivers, a matching hardware texture will typically be generated for the surface on the first call to AG_WidgetBlitSurface(), and cached.
By default, mapped surfaces are automatically freed once the widget is destroyed. The AG_WidgetMapSurfaceNODUP() variant sets the "NODUP" flag on the given surface, so the widget system will never attempt to free the surface.
Note that AG_WidgetMapSurface() will never duplicate the surface. The function merely registers the provided surface pointer with the widget structure. The surface pointer must remain valid for the lifetime of the widget (if in doubt, use AG_SurfaceDup(3)).
Under multithreading, AG_WidgetMapSurface() may be invoked from any context, but the returned name is only valid as long as the widget is locked (see AG_ObjectLock(3)).
AG_WidgetReplaceSurface() replaces the contents of a previously-mapped surface with the contents of newSurface. The AG_WidgetReplaceSurfaceNODUP() variant avoids duplicating the surface.
AG_WidgetUnmapSurface() destroys the given surface mapping. It is equivalent to invoking AG_WidgetReplaceSurface() with a NULL surface. The function is safe to use from any context.
It is important to note that in OpenGL mode, AG_WidgetReplaceSurface() and AG_WidgetUnmapSurface() will not immediately delete any previous texture associated with the previous surface. Instead, it will queue the delete operation for future execution from Rendering Context, as required by thread safety.
The AG_WidgetUpdateSurface() function should be invoked whenever a mapped surface is changed. If hardware surfaces are supported, it will cause an upload of the software surface to the hardware (otherwise it is a no-op).
The AG_WidgetBlitFrom() function renders a previously mapped (possibly hardware) surface from the source widget srcWidget (using source rectangle rs) onto the destination widget dstWidget, at coordinates x, y. This function must be invoked in Rendering Context.
The AG_WidgetBlitSurface() variant invokes AG_WidgetBlitFrom with the same argument for both srcWidget and dstWidget (and rs set to NULL).
Widget states can be bound to memory locations containing data in a
For example, the "state" binding of
AG_Button(3) can be tied to an integer (or bits in an integer), such that the user pressing
the button directly manipulates the integer value in memory.
Bindings are documented under the BINDINGS section of the widget's manual page. For instance, AG_Slider(3) mentions "value" bindings to integers. Therefore, to control a byte of memory, one might use:
Or alternatively, using a shorthand constructor:
This method is not limited to primitive data types. For example, AG_Textbox(3) can bind to a fixed-size memory buffer containing a C string in ASCII, UTF-8 or other supported encoding.
The AG_Bind<Type>() family of functions bind widget states to memory data. The AG_Bind<Type>Mp() variants accept a pointer to a mutex which will be acquired prior to accessing the data. The AG_Bind<Type>Fn() variants accept a pointer to a function instead of a memory location (the widget state will then be obtained by evaluating that function).
Note: The AG_Variable(3) API is actually part of AG_Object(3), and is not GUI-specific. It can be useful in non-GUI applications as well.
Since the state of a widget can influence its appearance (e.g., AG_Button(3) is drawn as a pressed button if its "state" is 1), it may be necessary to monitor the value and redraw when it changes. AG_RedrawOnChange() arranges for this to occur automatically (see below).
The AG_Redraw() function signals that the widget must be redrawn to the video display. It is equivalent to setting the dirty variable of the widget's parent window to 1. If called from Rendering Context, AG_Redraw() is a no-op.
The AG_RedrawOnChange() function arranges for the widget to be automatically redrawn whenever the value associated with the existing binding binding_name changes. The value of the binding will be checked at the specified interval refresh_ms in milliseconds. If a refresh_ms argument of -1 is passed, the effect of any previous AG_RedrawOnChange() call with the specified binding is disabled.
The AG_RedrawOnTick() function arranges for the widget to be unconditionally redrawn at the specified interval in milliseconds. If a refresh_ms argument of -1 is passed, the effect of any previous AG_RedrawOnTick() call is disabled.
AG_ParentWindow() returns a pointer to the parent AG_Window(3) for the given widget instance. The pointer is valid only as long as the parent VFS remains locked. If the widget is not attached, NULL is returned.
AG_WidgetFind() locates a widget instance by name, where path is a " / " separated path name relative to the AG_Driver(3) VFS root, for example: "My Window/Box #1/My button". If the widget exists, the function returns a pointer to the AG_Widget instance. The returned pointer is valid only as long as the parent VFS remains locked.
AG_WidgetFindFocused() returns the top-most focused widget under win.
AG_WidgetFindPoint() returns the top-most widget at display coordinates x, y, which also is an instance of a the given className (see AG_ObjectClass(3), AG_OfClass(3)). The AG_WidgetFindRect() variant requires that the widget enclose the whole given rectangle.
Similarly to AG_WidgetFind(), the AG_Widget pointer returned by AG_WidgetFindFocused(), AG_WidgetFindPoint() and AG_WidgetFindRect() should be considered valid only for as long as the parent VFS is locked.
The AG_PushClipRect() function pushes a rectangle (in widget coordinates) onto the stack of clipping rectangles, and AG_PopClipRect() pops the last entry from the clipping rectangle stack. The effective clipping rectangle will be the intersection of all rectangles on this stack. AG_PushClipRect() and AG_PopClipRect() must be invoked in Rendering Context.
The AG_WidgetDraw() routine renders a widget to the display. It is typically invoked from an event loop routine (such as AG_EventLoop(3)), to recursively draw the hierarchy of visible GUI elements.
In the event loop, AG_WidgetDraw() invocations must be enclosed between calls to AG_BeginRendering() and AG_EndRendering().
The AG_WidgetHide() and AG_WidgetShow() functions toggle the visibility of the specified widget (setting the AG_WIDGET_HIDE flag as appropriate).
The AG_WidgetHideAll() and AG_WidgetShowAll() routines toggle the visibility of the specified widget and its children by setting the AG_WIDGET_VISIBLE flag (which works independently of AG_WIDGET_HIDE). These routines are intended to be used by container widgets (for example, AG_Notebook(3) which needs to show or hide tabbed containers).
AG_WidgetVisible() returns 1 if the widget is currently visible (equivalent to checking the AG_WIDGET_VISIBLE flag).
The AG_WidgetSurface() routine renders the widget to a newly-allocated AG_Surface(3). This surface should be freed after use.
Presentation settings such as fonts and colors are stored as named
AG_Variable(3) properties (e.g., "font-size", "color", "color#hover", etc.)
Those properties should be set using the following functions:
The AG_SetFont() function sets the widget's default font attributes to match those of the specified font object.
The AG_SetStyle() function sets the specified style attribute to the given value. Accepted attributes are as follows:
An optional selector may be appended to the attribute names. Accepted selectors include "#disabled", "#hover" and "#selected". Selectors may be interpreted differently on a per-widget basis.
STANDARD WIDGET ACTIONS
User-generated events such as key presses or mouse button events can be
actions, such as executing a specified routine or controlling
a boolean variable.
Registered actions are described by the
Where the conditions for execution of an Action are fixed (e.g., a specific mouse button was clicked, or a specific key was pressed), use of AG_ActionOn*() is preferred over low-level event handlers (such as "key-down" or "mouse-button-down"), because it allows keyboard and mouse bindings to be configured by the end-user in a standard way. AG_Menu(3) also provides interfaces for working with widget actions.
AG_ActionFn() registers a new widget action which is to invoke a callback function fn, with arguments fnArgs. See AG_Event(3) for a description of the fnArgs format.
AG_ActionSetInt() registers a new action which is to set an integer variable to a specified value. Instead of an integer variable, AG_ActionSetFlag() sets the bits specified by bitmask to the specified value (of 1 or 0). The AG_ActionToggleInt() and AG_ActionToggleFlag() variants do not take an explicit value argument, and toggle the current value instead.
AG_ActionOnButtonDown() and AG_ActionOnButtonUp() tie an action to a button press and a button release event, respectively. The button argument specifies the button index (see AG_MouseButton(3)). AG_ActionOnKeyDown() and AG_ActionOnKeyUp() tie an action to a key press and key release event, respectively. The sym argument specifies the key (see AG_KeySym(3)), and mod specifies the modifier keys which must be in effect. To match any key or any modifier state, AG_KEY_ANY or AG_KEYMOD_ANY can be used.
With AG_ActionOnKeyDown() and AG_ActionOnKeyUp(), the action is triggered once immediately on key press or key release. The AG_ActionOnKey() variant ties an action to a key press, but with "key repeat" behavior. The action is triggered immediately once after an initial key press. If the key combination is held longer than the "key delay" (by default 250ms), the event is repeated with the "key repeat" interval (by default 30ms).
If there are currently no event handlers registered for "key-up", "key-down", "mouse-button-up" and "mouse-button-down", the AG_ActionOn*() functions automatically register event handlers which will invoke AG_ExecMouseAction() or AG_ExecKeyAction() as appropriate (see below).
AG_ExecMouseAction() executes any action associated with mouse button events. It is typically invoked from the "mouse-button-down" and "mouse-button-up" event handlers of the widget. Accepted type values are AG_ACTION_ON_BUTTONDOWN and AG_ACTION_ON_BUTTONUP. button is the pressed button index (see AG_MouseButton(3)). x and y is the position of the cursor in the widget's coordinate system.
AG_ExecKeyAction() executes any action associated with keyboard events. It is typically invoked from the "key-down" and "key-up" event handlers of the widget. Accepted type values are AG_ACTION_ON_KEYDOWN and AG_ACTION_ON_KEYUP. sym and mod specify the key index and modifier state (see AG_KeySym(3) and AG_KeyMod(3)).
AG_ExecAction() executes the specified action. AG_ExecAction() is rarely used directly, but it is invoked internally by the AG_ExecFooAction() functions.
The GUI system may send
AG_Widget objects the following events:
The following events are usually generated by input devices:
flags member of the
AG_Widget structure accepts the following flags:
|AG_Cursor(3), AG_KeyMod(3), AG_KeySym(3), AG_Rect(3), AG_StyleSheet(3), AG_Surface(3), AG_Variable(3), AG_WidgetPrimitives(3), AG_Window(3)|
|The AG_Widget interface first appeared in Agar 1.0. Widget-level variable bindings have been replaced by generic AG_Variable(3) pointers in Agar 1.3.4. The Actions interface first appeared in Agar 1.4. The AG_WIDGET_USE_OPENGL feature first appeared in Agar 1.5.|