Skip to content

UXRscGem

UXRscGem loads an interface from a .rsc file on GEM. The rest of the design follows from one property: there is no inflation step. Until 0.7 this class was UXRsc; UXRsc is now the loader for every backend, GEM included, and reads layout themes and scoped connections, which this one does not.

#use <UXKit> // or #import "UXRscGem.xc"

A GEM resource already contains an OBJECT tree, and a UXView is backed by an OBJECT. Loading a rsc means loading that tree and binding a view onto each entry. Nothing is copied or rebuilt, and on GEM the AES walks the resource’s own array directly.

Rocks (macOS) --writes--> app.rsc --load--> OBJECT[] --bind--> UXViewTree

The resource editor is the interface builder. A dialog designed there becomes a live view hierarchy with no conversion, rather than a description that a loader reconstructs.

UXViewTree* tree = UXRscGem.load((u8*)"app.rsc", 0); // tree 0 of the file

Views are chosen by ob_type. The resource supplies the type, frame, flags and state; your code supplies the behaviour.

Loading gives you a hierarchy. Connecting it to a controller is the other half, and it needs no per-application code:

UXViewTree* tree = UXRscGem.loadWired((u8*)"app.rsc", 0, (UXDesignable*)controller);

loadWired reaches your controller through UXDesignable and connects the rsc’s outlets and actions by name.

Your controller declares, the compiler generates

Section titled “Your controller declares, the compiler generates”
class MainController : Object
{
outlet UXLabel* statusLabel;
outlet UXView* canvas;
void onSave(UXControl* sender) :action { … }
void onQuit(UXControl* sender) :action { … }
}

Declaring any outlet field or :action method auto-conforms the class to UXDesignable, and the compiler generates both method bodies from the decorations:

  • setOutlet(name, value): a checked assignment per outlet, returning false on an unknown name or a type mismatch
  • wireAction(name, control): control.setAction(&self.<method>) per action

There is no reflection beyond what the decorations declare, and the compiler checks every connection. An rsc file naming an outlet your controller does not have fails at load with a false return, instead of leaving a null field that crashes later.

load · loadWired · loadWiredMem · loadDoc · viewForType · classOverride

static UXViewTree* load(u8* path, i32 treeIndex)

Loads one tree from a .rsc file and binds views onto it. A resource holds several trees (a dialog, a menu, an about box), addressed by index.

static UXViewTree* loadWired(u8* path, i32 treeIndex, UXDesignable* owner)

load, then connect outlets and actions on owner by name.

static UXViewTree* loadWiredMem(u8* data, i32 len, i32 treeIndex, UXDesignable* owner)

The same from bytes already in memory: a resource compiled into the binary, or fetched rather than read from disk.

static UXViewTree* loadDoc(pointer doc, i32 treeIndex, UXDesignable* owner)

From an already-parsed document, when you load several trees out of one file and do not want to re-read it per tree.

static UXView* viewForType(u16 gtype)

The type-to-view mapping: G_BUTTON becomes a UXButton, and every other type a plain UXView that the AES draws from the resource. Classes named by the document are made through UXRsc.make.

static u8* classOverride(pointer doc, i32 ncl, i32 tree, i32 obj)

The class name a resource records for a particular object, when it wants something other than the default for that type. This is the stored form of “this button is a FancyButton”.

The resource owns the layout; you own the behaviour. Frames, flags and initial state come from the file, so moving a control is an edit in the editor instead of a recompile. Anything you set in code after load is overwritten on the next load, because the file is the source of truth for those fields.

A tree index is positional. Trees are addressed by number, not name, because .rsc does not store tree names. If you delete a tree in the editor, every index after it shifts. Rocks renumbers the links it owns, but you must keep any index hard-coded in your source correct.

  • UXRsc: the loader for every backend

  • UXDesignable: the two generated methods, and the outlet / :action decorations

  • UXRscV2: the newer format, with variants per form factor

  • UXViewTree: what a load produces

  • UXView: adoptObject, the binding step