Element Hierarchy
PBElement
Opaque object handle: A user interface element, such as a window (PBWindow), button (PBButton), text display (PBTextDisplay) or layout grid (PBGrid). Within a window, there is a hierarchy of elements called the layout hierarchy; each element is positioning its children and painting itself. Each element has two callbacks which are sent messages (PBMessage) to determine the behavior and appearance of the element.
This object maintains an internal reference count. When the reference count reaches zero, the object will be automatically deallocated. To increment the reference count, call PBElementRetain; to decrement the reference count, call PBElementRelease. These functions are thread-safe.
PBElementFlags
Enumeration/bitset of type uint32_t: Flags controlling the behavior and appearance of a UI element. Individual element types may define bits 0-7 for their own use.
Constants
PBElement_CUSTOM_LAYOUT
PBElement_CUSTOM_LAYOUT = 1<<8
Enable custom layout for this element. It will receive PBMsg_MEASURE and PBMsg_LAYOUT messages; the element should process these messages to determine the layout of its child elements. Without the flag, a default column/row layout is provided. There are various other messages that are only sent to elements with this flag, such as PBMsg_ENSURE_VISIBLE and PBMsg_GET_VIRTUAL_CHILD.
PBElement_CUSTOM_PAINT
PBElement_CUSTOM_PAINT = 1<<9
Enable custom painting for this element. It will receive PBMsg_GET_PAINT_BOUNDS and PBMsg_CUSTOM_PAINT messages; the element should processes these messages to draw itself, and optionally its descendent elements.
PBElement_CLIP_LAYER
PBElement_CLIP_LAYER = 1<<10
Clips the element and its descendents to its bounds. Without this, descendents are not clipped, and the element's paint bounds (see PBMsg_GET_PAINT_BOUNDS) can extend outside its bounding box. This also affects hit testing: mouse events outside the bounding box of an element with this flag cannot be sent to its descendents. Furthermore, this starts a new depth stacking context: all depths in PBDepthIndex of its children will be drawn as part of its PBDepthIndex_MAIN.
PBElement_INPUT_MOUSE_LEFT
PBElement_INPUT_MOUSE_LEFT = 1<<11
Set to receive left mouse button events. If not set, a left mouse button events are passed to its parent (not overlapping siblings). Descendents can still receive these events regardless.
PBElement_INPUT_MOUSE_MIDDLE
PBElement_INPUT_MOUSE_MIDDLE = 1<<12
Similar to PBElement_INPUT_MOUSE_LEFT, but for PBMouseButton_MIDDLE.
PBElement_INPUT_MOUSE_RIGHT
PBElement_INPUT_MOUSE_RIGHT = 1<<13
Similar to PBElement_INPUT_MOUSE_LEFT, but for PBMouseButton_RIGHT.
PBElement_INPUT_MOUSE_NONE
PBElement_INPUT_MOUSE_NONE = 1<<14
Set to prevent receiving any mouse events and to additionally prevent PBElementFindByPoint from discovering the element. Like with PBElement_INPUT_MOUSE_LEFT this does not affect its descendents, but any siblings it overlaps will be affected, since the area taken by the element with this flag will be considered to be the area of its parent. Do not use with the PBElement_INPUT_MOUSE_LEFT/MIDDLE/RIGHT flags.
PBElement_TAB_STOP
PBElement_TAB_STOP = 1<<15
The element is a tab stop. When enumerated by PBWindowTabTraverse or by the user pressing PBKey_TAB, it will be focused with the flag PBElementFocus_FROM_KEYBOARD.
PBElement_ALLOW_FIRST_MOUSE
PBElement_ALLOW_FIRST_MOUSE = 1<<17
Allow receiving of mouse events that activate the window. See PBMouseInput_ACTIVATED_WINDOW.
PBElement_HIDDEN
PBElement_HIDDEN = 1<<18
Hidden elements are not drawn and are not included in standard layouts. An element with a hidden ancestor is not drawn (but see PBDrawElement for an exception). Prevents this element and its descendents from taking keyboard focus or the hovered state. Hidden elements cannot be found by PBElementFindByPoint.
PBElement_DISABLED
PBElement_DISABLED = 1<<19
Prevents this element and its descendents from taking keyboard focus or receiving mouse input. Descendents will not appear disabled however for styling purposes unless they also have the flag; see PBAppearanceCompile.
PBElement_ALIGN_LEFT
PBElement_ALIGN_LEFT = 1<<20
If the parent uses the default layout algorithm, the element will be left aligned in the parent. If the parent uses PBElement_CUSTOM_LAYOUT, then it may interpret the flag however it likes.
PBElement_ALIGN_RIGHT
PBElement_ALIGN_RIGHT = 1<<21
Same as PBElement_ALIGN_LEFT, but for right alignment. If neither flag is specified, this indicates it should be centered. If both are specified, this indicates it should fill the width of the parent (note well that this does not automatically propagate to ancestors).
PBElement_ALIGN_TOP
PBElement_ALIGN_TOP = 1<<22
If the parent uses the default layout algorithm, the element will be top aligned in the parent. If the parent uses PBElement_CUSTOM_LAYOUT, then it may interpret the flag however it likes.
PBElement_ALIGN_BOTTOM
PBElement_ALIGN_BOTTOM = 1<<23
Same as PBElement_ALIGN_TOP, but for bottom alignment. If neither flag is specified, this indicates it should be centered. If both are specified, this indicates it should fill the height of the parent (note well that this does not automatically propagate to ancestors).
PBElement_LAYOUT_HORIZONTAL
PBElement_LAYOUT_HORIZONTAL = 1<<24
For the default layout algorithm, the makes the element lay out its children in a horizontal row rather than the default vertical column. If the element uses PBElement_CUSTOM_LAYOUT, it may interpret this flag as it wishes (although it would be wise to interpret it similarly).
PBElement_LAYOUT_REVERSE
PBElement_LAYOUT_REVERSE = 1<<25
For the default layout algorithm, the makes the element treat it children as if they had been added in the opposite order. If the element uses PBElement_CUSTOM_LAYOUT, it may interpret this flag as it wishes (although it would be wise to interpret it similarly).
PBElement_DND_TARGET
PBElement_DND_TARGET = 1<<26
Indicates this element is a drag-and-drop target. It will receive PBMsg_DND_MOVE_OVER and other DND messages. Do not use with PBElement_INPUT_MOUSE_NONE.
PBElement_ANNOUNCE_EVENTS
PBElement_ANNOUNCE_EVENTS = 1<<27
See PBElementReportEvent.
PBElement_ANNOUNCE_ATOMIC
PBElement_ANNOUNCE_ATOMIC = 1<<28
If this element or one of its descendents is modified, then the entire subtree should be re-read at the end of the event.
See Also
PBMessageAddChild
Structure:
Fields
[in] child (referenced PBElement):
parent (owned PBElement):
nextSibling (nullable owned PBElement):
PBMessageRemoveChild
Structure:
Fields
[in] child (referenced PBElement):
PBMessageLowFlagsWillChange
Structure:
Fields
[in] newLowFlags (uint8_t
):
PBMessageCapturedCommand
Structure:
Fields
[in] commandID (PBCommandID):
PBElementChangeOrdering
Function: Change the layout ordering of an element with respect to its siblings.
Syntax (C/C++)
void PBElementChangeOrdering(PBElementRef element,
PBElementRef _Nullable insertBefore);
Syntax (Python)
ElementChangeOrdering(element, insertBefore)
Parameters and Return Values
[in] element (referenced PBElement): The element to move.
[in] insertBefore (nullable referenced PBElement): If non-null, this gives the element just before which it will be moved. If null, then the element is moved to the end of its parent's children. Notably, if non-null this must have the same parent as the element to move.
Discussion
This does not send PBMsg_ADD_CHILD or PBMsg_REMOVE_CHILD to the parent.
The parent will be marked for relayout.
See Also
PBElementChangeParent
Function: Change the layout parent of an element.
Syntax (C/C++)
bool PBElementChangeParent(PBElementRef element, PBElementRef newParent,
PBElementRef _Nullable insertBefore);
Syntax (Python)
ElementChangeParent(element, newParent, insertBefore) -> (success)
Parameters and Return Values
[in] element (referenced PBElement): The element to reparent.
[in] newParent (referenced PBElement): The new parent of the element. This must be in the same window as the previous parent. Elements cannot be moved between windows.
[in] insertBefore (nullable referenced PBElement): If non-null, this gives the element just before which it will be placed. If null, then the element is placed at the end of the new parent's children. Notably, if non-null this must a child of the new parent.
[out] success (bool
): False if there was not enough free memory to complete the operation.
Discussion
The new parent will be sent a PBMsg_ADD_CHILD message and the previous parent will be sent a PBMsg_REMOVE_CHILD message, in that order. Note that the PBMsg_ADD_CHILD is given an opportunity to adjust the parent and insertBefore parameters.
Affected regions of the window will be marked for repainting. The new and old parents will be marked for relayout.
If the element is moved to a parent so that it has an ancestor that is disabled or hidden then its interaction states will be removed (such as keyboard focus).
Elements cannot be moved to a different window to the one on which they were created.
See Also
PBElementCreate
Function: Create a custom element.
Syntax (C/C++)
PBElementPtr _Nullable PBElementCreate(PBElementRef parent, PBElementFlags flags,
PBElementMessageHandler messageClass);
Syntax (Python)
ElementCreate(parent, flags, messageClass) -> (element)
Parameters and Return Values
[in] parent (referenced PBElement): The layout parent of the element. The new element will be added at the end of its list of children.
[in] flags (PBElementFlags): Flags bitwise OR-ed together controlling the behavior and appearance of the element.
[in] messageClass (PBElementMessageHandler): The main message handler of the element. See PBElementMessage for more details. This cannot be changed after the element has been created.
[out] element (nullable owned PBElement): The created element, or null if there was insufficient available memory. If non-null, release with PBElementRelease when you no longer need to access the element.
Discussion
The various element creation functions call into this. You can use it manually to create custom elements.
Created elements start with a reference count of two: the first reference is returned by this function, and the second is kept by the system until the element is destroyed (see PBElementDestroy for a discussion of the stages of element destruction).
The parent element is marked for relayout after the child element is created.
On calling this function, the candidate parent is sent the PBMsg_ADD_CHILD message. This gives it an opportunity to modify the actual parent that will be used. This process repeats until the candidate does not defer the child to another parent.
Initially, the created element will have an empty bounding box at the top-left corner of the window. It will be positioned in the layout phase of the event cycle. The created element will be given the PBStyleID_EMPTY style; this can be changed with PBElementSetStyle or PBElementSetCustomStyle.
See Also
PBElementDestroy
Function: Mark an element to be destroyed and removed from its parent.
Syntax (C/C++)
void PBElementDestroy(PBElementRef element);
Syntax (Python)
ElementDestroy(element)
Parameters and Return Values
[in] element (referenced PBElement): The element to destroy.
Discussion
There are three stages to the destruction of an element. (1) The element is marked to be destroyed by PBElementDestroy. (2) At the end of the event cycle (or after the main event message has been processed), the system actually destroys all elements marked for destruction and releases them. (3) When the element's reference count reaches zero, the element object is freed (and possibly its user data pointer; see PBElementSetUserDataPtrWithOwnership).
After stage (1), most operations on the element will do nothing. After stage (2), most operations on the element will fail and trigger an assertion. After stage (3), an attempt to operate on the element will cause memory corruption. For example, within a single event cycle, repeated calls to PBElementDestroy are ignored, but calls in a later event will cause the application to crash.
In stage (1), the following steps are taken: The parent element is sent a PBMsg_REMOVE_CHILD message. The element's interaction states are removed; for example, if it has keyboard focus, this focus will be removed. All its children are passed to PBElementDestroy (and this recurses through all descendents). Any portions of elements previously visually obscured by this element are marked for repainting as necessary. The element is sent the PBMsg_DESTROY message.
In stage (2), the following steps are taken: The element is sent a PBMsg_DEALLOCATE message. Its message handlers are freed. It is fully removed from the layout hierarchy. Its reference count is decremented.
Between stages (1) and (2), the following functionality of an element will be affected: The element will be unable to take on new interaction states. The element will not be found by PBElementFindByPoint. The element cannot be drawn with PBDrawElement. The element cannot be sent messages. Child elements cannot be added to it.
Note well that these are non-exhaustive lists.
The distinction between stage (1) and stage (2) is made so that it is generally safe to call PBElementDestroy even when deep in a call stack. Outer functions that try to operate on the element can still safely do so.
See Also
PBElementDestroyDescendents
Function: Destroy all the descendents of an element.
Syntax (C/C++)
void PBElementDestroyDescendents(PBElementRef element);
Syntax (Python)
ElementDestroyDescendents(element)
Parameters and Return Values
[in] element (referenced PBElement): The parent element.
Discussion
This calls PBElementDestroy for each child of this element. It then sends PBMsg_DID_DESTROY_DESCENDENTS to this element.
See Also
PBElementIsLayoutAncestor
Function: Tests whether an element is a layout ancestor of another.
Syntax (C/C++)
bool PBElementIsLayoutAncestor(PBElementRef maybeAncestor,
PBElementRef maybeDescendent, bool orEqual);
Syntax (Python)
ElementIsLayoutAncestor(maybeAncestor, maybeDescendent, orEqual) -> (isAncestor)
Parameters and Return Values
[in] maybeAncestor (referenced PBElement): The element that may be an ancestor of the other.
[in] maybeDescendent (referenced PBElement): The element that may be a descedent of the other.
[in] orEqual (bool
): If true, an element is considered to be an ancestor of itself.
[out] isAncestor (bool
): True if maybeAncestor is an ancestor of maybeDescendent.
Discussion
An ancestor may be a parent, a grandparent, a great-grandparent, etc. A window is an ancestor of all the elements it contais.
See Also
PBElementGetWindow
Function: Get a reference to the window that contains this element.
Syntax (C/C++)
PBWindowPtr _Nullable PBElementGetWindow(PBElementRef element);
Syntax (Python)
ElementGetWindow(element) -> (window)
Parameters and Return Values
[in] element (referenced PBElement): The element in the window.
[out] window (nullable owned PBWindow): The containing window. Release with PBElementRelease when you no longer need the pointer to the window. If the element has been destroyed (and hence removed from its window), null is returned.
Discussion
If the element is a window, then the window itself is returned.
Example (C/C++)
PBWindow *window = PBElementGetWindow(element);
PBAlertAddSimpleError(window, PB_STR("Error!"), PB_STR(""));
PBElementRelease((PBElement *) window);
See Also
PBElementGetFlags
Function: Get an element's flags.
Syntax (C/C++)
PBElementFlags PBElementGetFlags(PBElementRef element);
Syntax (Python)
ElementGetFlags(element) -> (flags)
Parameters and Return Values
[in] element (referenced PBElement): The element.
[out] flags (PBElementFlags): Its flags.
See Also
PBElementSetFlags
Function: Modify an element's flags.
Syntax (C/C++)
void PBElementSetFlags(PBElementRef element, PBElementFlags flags);
Syntax (Python)
ElementSetFlags(element, flags)
Parameters and Return Values
[in] element (referenced PBElement): The element.
[in] flags (PBElementFlags): The new flags. You should call PBElementGetFlags first to get the previous value and modify that.
Discussion
The system will likely need to repaint or relayout the element in response to this call. If an input bit is removed and an interaction is ongoing (such as a mouse press), then it will cancelled here.
If bits 0-7 are changed, then PBMsg_LOW_FLAGS_WILL_CHANGE will be sent to the element.
Changing the PBElement_DISABLED and PBElement_HIDDEN bits is equivalent to calling PBElementSetDisabled and PBElementSetHidden respectively.
PBElementGetFlags will not return the new flags until it sent out all update messages.
See Also
PBElementSetCapturedCommandDisabled
Function:
Syntax (C/C++)
void PBElementSetCapturedCommandDisabled(PBElementRef element, PBCommandID id,
bool disabled);
Syntax (Python)
ElementSetCapturedCommandDisabled(element, id, disabled)
Parameters and Return Values
[in] element (referenced PBElement):
[in] id (PBCommandID):
[in] disabled (bool
):