UXWindow
UXWindow binds one native window to one
UXViewTree. The platform draws the frame
(title, closer, mover, all themed), and the toolkit does not handle it. The
window supplies the content: the tree, whose stock widgets draw themselves and
whose custom views call back through
drawRect.
#use <UXKit>Overview
Section titled “Overview”Opening is one call. open attaches your content view to the
tree at the window’s size, creates the native window, registers the paint
callback, shows the window, and does the first full paint:
UXWindow* win = new UXWindow();app.addWindow(win); // register BEFORE openwin.open((u8*)"Editor", UXGeom.make(20, 20, 320, 200), content);(The .rsc/rsc path is openWithTree: the resource already
defines its tree and sizes, and the window adopts it.)
Repaints are damage-driven at two levels. Views mark rects
(setNeedsDisplayInRect),
and display repaints the union under a clip. During the walk, a
view whose absolute frame misses the damage is skipped before its drawRect
runs. Because of this second check, one typed character repaints one line and
does not run every drawRect in the window.
Events enter here. The run loop routes a decoded event to the window, and
the window routes it inward. dispatchMouse goes through the
tree’s shared hit-test to the deepest willing view.
dispatchKey goes to the first responder; Tab/Shift-Tab move
focus between editable and selectable controls, and Return fires the
default button. A headless test uses the same entry with a
synthesized event, so a test click and a native click are indistinguishable
above the driver.
Closing is explicit and idempotent. close destroys the native
window and zeroes the handle (isOpen becomes false); dealloc
closes as a backstop. From a control’s action, prefer
UXApplication.closeWindowLater.
Conforms to
Section titled “Conforms to”- Inherits
UXResponder: the content view’snextResponderis the window, so unclaimed events arrive here.
Topics
Section titled “Topics”Opening · open · openWithTree · close · isOpen Chrome · setTitle · setSubtitle · setModified · setInfo · setIcon · orderFront · setMinimumSize · toolbarInChrome · showLine · hideLine Scrolling · setContentSize · scrollTo · scrollX · scrollY Painting · display · displayAll · snapshot Views · viewAt · layoutFor Focus & dispatch · makeFirstResponder · setDefaultButton · moveFocus · dispatchMouse · dispatchMouseDragged · dispatchMouseUp · dispatchKey · dispatchWheel · keyDown
void open(u8* title, UXRect f, UXView* content)Attaches content (it becomes the tree’s root, sized to the window), creates
and shows the native window, and does the first paint. The content view’s
responder chain ends at the window.
openWithTree
Section titled “openWithTree”void openWithTree(u8* title, UXRect f, UXViewTree* vt)The rsc path: adopts a tree that already exists.
UXRsc built it from the resource, with behaviour
already bound.
void close(void)Destroys the native window and zeroes the handle. Safe to call twice; dealloc
calls it as a backstop.
isOpen
Section titled “isOpen”bool isOpen(void)True while a native window exists. The window object may outlive its native window; the handle shows which state it is in.
setTitle / setSubtitle / setModified / setInfo / setIcon
Section titled “setTitle / setSubtitle / setModified / setInfo / setIcon”void setTitle(u8* s)void setSubtitle(u8* s) // a path, a second linevoid setModified(bool m) // the edited dotvoid setInfo(u8* s) // the footer linevoid setIcon(u8* slice) // a theme slice NAME, not an imageWindow chrome, where the platform has it. macOS renders the subtitle and the modified dot; other platforms ignore what they lack. The toolkit never draws chrome.
setInfo sets GEM’s footer line, which has no macOS or Windows equivalent and
is a no-op there. setIcon takes a theme slice name, not an image, so the
icon is whatever the current theme draws for that name. This is the same
indirection as drawTheme.
orderFront
Section titled “orderFront”void orderFront(void)Raises and focuses the window, for example on a Windows-menu pick or when re-selecting an open document.
setMinimumSize
Section titled “setMinimumSize”void setMinimumSize(i32 w, i32 h)The smallest the window’s content may be made by hand. AppKit and GTK keep to it, and Windows from 0.71; on a backend whose windows are not resized by hand it does nothing. From 0.7.
toolbarInChrome
Section titled “toolbarInChrome”static bool toolbarInChrome(void)Whether a UXToolbar is drawn in the
window’s own chrome, as AppKit draws it in the title bar, so the content need
leave no room for it. From 0.7.
showLine / hideLine
Section titled “showLine / hideLine”bool showLine(i32 x0, i32 y0, i32 x1, i32 y1, UXRect hot)void hideLine(void)A line between two points of the content, drawn above everything in the
window, native controls included, with hot framed when it is not empty: the
guide for a drag, such as a connection being drawn. showLine returns false
where the backend cannot draw one, and the app then draws its own. From 0.7
on AppKit, and on GTK, Windows and the web from 0.71.
setContentSize
Section titled “setContentSize”void setContentSize(i16 w, i16 h)Reports the CONTENT’s full extent. The platform frame owns the scrollbars and
shows them when this exceeds the work area. On GEM the result is asynchronous:
call pump before reading geometry
back.
scrollTo / scrollX / scrollY
Section titled “scrollTo / scrollX / scrollY”void scrollTo(i16 x, i16 y)i16 scrollX(void)i16 scrollY(void)Sets the scroll offset from code (to reveal a row or restore a position) and reads back the resulting offset.
viewAt
Section titled “viewAt”UXView* viewAt(u16 i)A view by its object index. An application uses this to reach a control that a rsc made.
Write views[MAIN_OK], not views[3]. A resource editor exports symbolic names
for its objects, so the index is a named constant and does not shift when
someone inserts a control.
moveFocus
Section titled “moveFocus”void moveFocus(bool forward)Tab and Shift-Tab. Walks the tree for the next view whose
acceptsFirstResponder is true.
display
Section titled “display”void display(void)Repaints the accumulated damage (or everything, if nothing was marked) under one clip, then clears the marks.
displayAll
Section titled “displayAll”void displayAll(void)Full repaint. On the native-overlay backends this is also where realizeTree
reconciles native controls with the tree, so the examples call it after building
the view hierarchy.
snapshot
Section titled “snapshot”UXImage* snapshot(UXRect* r)The window’s content as it is on screen, as a UXImage:
the views, the native controls and any GL view’s frame, composited. r is a
region in content coordinates, clipped to the content, or null for the whole
content. Answers null if the window is not open or the region is empty. The
image is at the window’s own size in points, whatever the screen’s scale.
UXImage* whole = win.snapshot((UXRect*)0);UXRect map = UXGeom.make((i16)0, (i16)40, (i16)1280, (i16)792);UXImage* part = win.snapshot(&map);movie.add(part); // UXMovie| backend | how |
|---|---|
| macOS | the content view and its subviews rendered into a bitmap |
| Windows | PrintWindow; under Wine, the window’s own surface |
| GTK | the window rendered through its paintable, for the current frame |
| web | the window’s region of the canvas, GL views composed under the 2-D layer |
| iOS | drawViewHierarchyInRect: |
| Android | the window’s layout drawn into a bitmap |
| GEM | the window repainted, and its work area read back from the surface it drew into: its own backing store under gemd |
A whole-window snapshot takes a few milliseconds on most backends. On GTK it waits for two frames to be painted, about 33 ms at 60 Hz.
makeFirstResponder
Section titled “makeFirstResponder”bool makeFirstResponder(UXResponder* r)Moves keyboard focus, honouring acceptsFirstResponder. Returns false if the
target declined.
setDefaultButton
Section titled “setDefaultButton”void setDefaultButton(UXControl* b)The control that Return fires when no more specific view has focus.
dispatchMouse
Section titled “dispatchMouse”void dispatchMouse(UXEvent* e)Takes window-local coordinates, as the window shows on screen. The tree’s hit-test finds the deepest visible, willing view, and the click walks the responder chain from there. Synthetic tests and the platform share this entry.
Over a scroll view whose native container owns the offset, the window adds that
offset itself and hit-tests the document again, so the view gets the point in the
document’s coordinates, as it would after a toolkit scroll. The press’s drags and
release get the same offset. dispatchMouseMoved, dispatchWheel and
dispatchRightMouse do the same.
The view hit becomes the window’s grab until the press is released (see
below), and the press point is recorded on the tree (pressX, pressY).
dispatchMouseDragged / dispatchMouseUp
Section titled “dispatchMouseDragged / dispatchMouseUp”void dispatchMouseDragged(UXEvent* e)void dispatchMouseUp(UXEvent* e)A held press moving, and its release. Both go to the view that took the
press (the grab), not to whatever is under the pointer now: a drag that
leaves its view still belongs to it. Unhandled, they climb the responder
chain, which is how a drag that starts on a list row reaches the
UXScrollView holding it.
These matter on iOS and Android. There the platform owns the run loop, so a
view cannot track a drag modally
(dragTrackingIsModal
is false). Native widgets take their own touches. Everything drawn
(tables, custom views, an editor’s canvas) receives its touches as these
events:
| finger | event |
|---|---|
| down | dispatchMouse: a press at that point, which takes the keyboard if the view wants it, as a click does |
| moving | dispatchMouseDragged, to the grab |
| up, or cancelled by the system | dispatchMouseUp, to the grab |
A display pass follows each one, as after any native event. On the desktops
these are never called: a view that drags loops on trackDragStep inside its
mouseDown. A view written for both asks gDriver.dragTrackingIsModal()
and, when it is false, continues its drag from mouseDragged and mouseUp.
dispatchKey
Section titled “dispatchKey”void dispatchKey(UXEvent* e)Sends the key to the first responder; Tab/Shift-Tab move focus; Return fires the default button.
dispatchWheel
Section titled “dispatchWheel”void dispatchWheel(UXEvent* e)A scroll-wheel or trackpad event, routed like a click: to the deepest view under the pointer, then up the responder chain until something handles it.
A wheel over a scrolling list therefore scrolls the list and not the window, because the list is deeper and gets the event first.
keyDown
Section titled “keyDown”void keyDown(UXEvent* e)Receives a key that climbed the whole responder chain unconsumed. The window is the last stop before the application.
It handles two keys: Tab traverses focus (see moveFocus), and
Return fires the default button. Other keys continue up the chain.
A control consumes the keys it understands, and the window implements only the keys that belong to being a window and not to any control in it.
layoutFor
Section titled “layoutFor”void layoutFor(i32 wx, i32 wy, i32 ww, i32 wh)Re-places the root for a new work area. A resize or a scroll calls it.
The driver reports the work area on every draw and the root tracks it, so the whole tree moves with the window: children are parent-relative, and moving the root moves everything under it without walking the tree.
The scroll offset is also applied here, so a non-scrolling window pays nothing for scrolling: a window that never reported a content size reads a scroll of zero and behaves as if scrolling did not exist.
You rarely call this; the window calls it on the events that change its geometry.
Example
Section titled “Example”Two windows sharing one controller, with key status and dispatch handled by the app:
UXWindow* doc = new UXWindow();UXWindow* pal = new UXWindow();app.addWindow(doc);app.addWindow(pal);doc.open((u8*)"Document", UXGeom.make(20, 20, 360, 240), docView);pal.open((u8*)"Palette", UXGeom.make(400, 20, 120, 240), palView);pal.setSubtitle((u8*)"tools");doc.setModified(true); // the close-button dot, where the platform has one