moonegui

    moonegui — an immediate-mode GUI toolkit for MoonBit (after egui): context, layout, widgets, and a backend-agnostic list of shapes to paint.

    gui
    immediate-mode
    egui
    widget
    canvas
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    22 hours ago
    Downloads
    2

    #moonegui

    check and test

    An immediate mode graphical interface for MoonBit, after egui.

    An interface here is a function of your state, called once a frame. There is no widget tree to keep in step with anything, no callbacks and no subscriptions: you ask for a button and are told whether it was clicked, on the line below.

    if @widget.button(ui, "Press me").clicked {
    clicks = clicks + 1
    }
    clicks_shown = @widget.slider(ui, clicks_shown, low=0, high=10).0
    name = @widget.edit(ui, name, hint="your name").0

    #What is here

    PackageWhat it does
    emathVec2, Rect, Align, Margin, and the interpolation everything else is built from
    idIds derived from a parent and a piece of salt, which is what connects a widget to the same widget last frame
    inputThe events a host hands over, folded once a frame into the state widgets ask questions of
    memWhat survives a frame: focus, the widget being dragged, and a value per widget, tidied at the end of every frame
    paintColours, strokes, fonts, and the five shapes a frame is made of
    layoutPlacers: where the next widget goes, in four directions, aligned or stretched across the flow
    hitWhat the pointer is over, and the Response a widget answers with
    textBreaking, aligning, eliding, and turning a click into a caret position
    ctxThe frame itself, and Ui — the value you spend the frame with
    widgetLabel, heading, separator, button, checkbox, radio, slider and text field
    backThe backend contract: three ways to measure, nine to draw, and a recorder that writes them down
    back/webWhat both browser backends share: the surface, the text metrics, and the input coming the other way
    back/canvasA frame painted on a 2D canvas
    back/htmlThe same frame as elements in the document, for pages that want selectable text and the rest of what H5 already has

    #Design

    Three decisions shape everything else.

    The core is synchronous. wasm-gc has no async, and a browser cannot be blocked, so the frame is a function the host calls — ctx.run(raw, ui) — rather than a loop the library owns.

    A backend measures and draws, nothing more. Twelve functions, all of which a plain 2D canvas already has. There is no triangulation, no glyph atlas and no shader anywhere in the library, and adding a backend is an afternoon — which is how the same frame reaches both a canvas and the document itself, measured by one piece of code so that the two lay out identically.

    Hit testing uses the previous frame's rectangles. This frame's widgets do not exist yet when the pointer has to be matched to one. That is where immediate mode's one frame delay comes from, and it is written down in the tests rather than left to be discovered.

    #Use it

    { "deps": { "moonbitstack/moonegui": "0.1.0" } }

    A frame, in full:

    let canvas : @canvas.Canvas = @canvas.Canvas::new()
    let context = @ctx.Ctx::new(canvas)
    canvas.listen()
    // then, once a frame:
    let out = context.run(canvas.raw(now, dt), fn(ui) {
    @widget.heading(ui, "moonegui") |> ignore
    if @widget.button(ui, "Press me").clicked {
    clicks = clicks + 1
    }
    })
    canvas.clear(context.style().background)
    @back.play(out.shapes, canvas)

    examples/browser is that program, with every widget in it. To run it:

    moon build --target js python -m http.server 8741 # then open http://127.0.0.1:8741/examples/browser/index.html # and the same page as elements: .../index.html?html

    #Tests

    177 tests, run on all four backends. The recording backend turns a frame into a list of text commands, so a test compares drawing to a string and needs no screen, no font file and no browser. Its font is deliberately regular — every character the same width — which is what lets a test work out the expected numbers by hand.

    moon check --target all --deny-warn moon test --target all

    Numbers reaching a snapshot are printed as sixty-fourths, since a floating point number does not print the same on every backend.

    #Not in this version

    Meshes and triangulation, glyph rasterisation, images, multiple windows and viewports, drag and drop, animation, and a colour picker. Text is drawn a row at a time by the backend; glyph positions are used only for carets and selections.

    #License

    Apache-2.0.