← Back to Docs
  • index.html
  • Clayground
  • Clayground.Lab
  • InstrumentBelt
  • Clayground 2026.7
  • InstrumentBelt QML Type

    What the viewer can pick up: the kernel's instruments in every lab, plus whatever the kit brought. More...

    Import Statement: import Clayground.Lab

    Properties

    Methods

    Detailed Description

    One line inside a lab's View3D and the lab has a tape measure and a stopwatch:

    View3D {
        OrbitInput3D { id: nav; rig: rig; view: view3d }
        InstrumentBelt { id: hands; pointer: nav; unit: "m" }
    }

    A ruler you have to install first is a ruler nobody reaches for, so the kernel's instruments are here by default rather than declared per lab; a kit's own instrument is declared inside the belt and joins the same row:

    InstrumentBelt {
        pointer: nav
        Voltmeter { circuit: sim }
    }

    It owns the hand's click

    The left button is the lab's, always - OrbitInput3D never takes it - so something has to decide what a left click means while an instrument is out. That is this: press, move and release are the hand's half of the lab's mouse handler, and they apply one rule, a click versus a drag. A click asks the pointer what was under it and hands the answer to the instrument; a drag hands over nothing, because a drag with a tape measure in hand is somebody dragging, not measuring.

    onPressed: (m) => {
        if (nav.begin(m.x, m.y, m.button, m.modifiers) !== "") return
        if (hands.held) { hands.press(m.x, m.y); return }
        // ...the lab's own tool
    }

    The instruments themselves never see the pointer; they are handed picks. There is no mode anywhere in this, and the belt writes no state on the pointer - taking an instrument out changes what a click does and nothing else, which is why it can be done at any moment.

    Coordinates

    It fills its parent, which is the View3D, so its children draw in view coordinates and an instrument's screen-space overlay lines up with the scene without any mapping of its own.

    See also HandheldInstrument, TapeMeasure, Stopwatch, and OrbitInput3D.

    Property Documentation

    clickSlop : real

    Pixels a press may travel and still count as a click.

    The same number OrbitInput3D uses for the right button, for the same reason: a click and a drag arrive as the same events and only the distance travelled tells them apart. A hand that trembles is not a drag.


    defaults : bool

    Carry the kernel's own instruments. On, and rarely off.


    empty : bool [read-only]

    The hand is empty.


    held : var [read-only]

    The instrument in hand, or null.


    heldIndex : int

    Which instrument is in hand; -1 for none.


    instruments : var [read-only]

    Everything on the belt: the kernel's, then the kit's, in order.


    key : string

    The key that cycles the belt, for hints.


    pinKey : string

    The key that keeps a reading.


    pinning : bool [read-only]

    The name prompt is open.


    pointer : var

    The OrbitInput3D whose picks feed the hand.


    rowMargin : real

    How far above the bottom of the view the belt sits.

    Defaults to just clear of a HintBar. A lab with more bottom chrome than that - sensor-fusion parks a full-width plot down there - raises it, because the belt has to be visible to be a belt.


    unit : string

    The unit this lab's world is in: "m", "mm", "u" ...

    The kernel cannot know - one lab's cell is a metre of tarmac and another's a millimetre of board - so the lab says, once, and the instruments that measure lengths follow.


    view : var

    The View3D; defaults to the pointer's.


    Method Documentation

    bool beginPin()

    Opens the name prompt for the reading in hand.

    The name is asked for rather than generated because it becomes a column in the run record, and a run record is what a paper cites: dist_1 is a bad citation forever. The suggestion is pre-filled and Enter takes it, so the fast path is still one key.


    void cancelPin()

    Closes the prompt, keeping nothing.


    bool commitPin()

    Keeps the reading under the typed name.


    void cycle()

    Next instrument, then back to an empty hand.

    Empty is a position on the belt, not the absence of one: cycling past the last instrument puts everything down, which is how you get the plain camera back without hunting for a key.


    var info()

    The belt as plain values, for an agent or a test.


    bool move(real x, real y)

    Continues the press; false when none is running.


    void press(real x, real y)

    Begins a press at viewport pixel (x, y).

    Records where, and decides nothing: whether this is a click cannot be known until the button comes up.


    void putAway()

    Empties the hand.


    bool release()

    Ends the press; true if it was a click that reached an instrument.

    The pick is taken at the pixel that was pressed rather than the one released: within a click the two are the same to within clickSlop, and asking about the press is what makes the answer independent of the wobble.


    void take(int i)

    Puts instrument i in the hand.


    void takeNamed(string n)

    Takes the instrument called n.