Table of Contents
Widgets
pyssel/ui's widgets are Godot's, with the looks of Godot's default theme: ranges, labels, buttons and button groups, check boxes, colour rects, separators, sliders, progress bars, text fields, spin boxes, lists and trees. A settings form at the end puts several together.
-
Ranges hold a value between
range-minimumandrange-maximum, on steps ofrange-step, and at most the maximum lessrange-page, the part that shows at once; settingrange-valuekeeps it so and emitsvalue-changed, andrange-ratiois where it is between them.range-allow-greaterandrange-allow-lesserlet the value past the maximum or below the minimum, as Godot'sallow_greaterandallow_lesser. The numbers are double-floats, as Godot's are, taken from any real, so that a spin box edits a 2D node's position a million units out to the thousandth; their readers and writers are inline, and setting the value allocates nothing.value-changedgives the new value, a double-float, which Lisp makes anew each time, so a range emits it only while something is connected to it. The steps are the decimals they stand for, as in Godot: 250.5 in steps of 0.001 stays 250.5, although the double-float 0.001 is a little more than a thousandth, and a step given as a single-float, as Lisp reads 0.1, stands for the decimal it was written as. Scroll bars,hscroll-barandvscroll-bar, are ranges, drawn as the theme's:scrolltrack with a:grabberon it; moving a scroll container's bar scrolls it. -
Widgets, Godot's, with the looks of Godot's default theme:
labelshowslabel-text, aligned across bylabel-horizontal-alignment(:start,:center,:endor:fill) and down bylabel-vertical-alignment; withlabel-autowrapits lines wrap at its width, and it is as tall as that makes it; withlabel-clip-textthey are cut short there with an ellipsis, so it needs no width.texture-rectshows an image,texture-rect-image, as Godot's TextureRect: stretched to fill it, or kept at its size or in shape, astexture-rect-stretch-modesays, and tinted withtexture-rect-color. It needs its image's size in units, its pixels over its scale, unlesstexture-rect-expand-modeis:ignore-size, so an image made at the display's scale with that scale is as large as at a scale of 1, and sharp. A scene saves how it draws, but not its image.viewport-containershows the root viewport of another tree, as Godot's SubViewportContainer shows its SubViewport, and as an editor shows the scene it edits:viewport-container-tree, a tree on the same engine made with:window nil(see Scene tree), whose root is a viewport, or another set withsetf. The engine draws that root viewport into a render target of the container's size, at its window's scale, in the framesviewport-container-update-modeallows, as Godot'srender_target_update_mode::when-visible, each frame in which the container is shown, by default, so a hidden one costs nothing;:always;:once, after which it is:disabled; or:disabled, so the container shows the picture drawn last. In those frames it draws the tree only when what the tree draws changed, aspyssel/scene-2d:prepare-viewportfinds, so a still scene keeps its picture however often the container's window is drawn. It draws it overviewport-container-clear-color, transparent by default, and the container draws the target, a pixel of it to each of the window's. The root keeps its own size, which its controls are laid out in; its canvas transform zooms and pans its own canvas in the container, and its global canvas transform all it draws, andtarget-to-canvastakes the container's units to the root's canvas. A tree is shown by one container at a time. The container hands the tree no input: its pointer's events are its own, as any control's.buttonshowsbutton-text, andbutton-icon, an image, before it, its text cut short at its width withbutton-clip-text, as Godot'sclip_text, so that it needs none of the text's width, and emitspressedas it is clicked, or pressed with Return or Space while it has the focus; it acts as it is released over it, unlessbutton-action-modeis:press. An icon alone makes an icon button, whosecontrol-tooltip-textsays what it does; the theme tints it as the button is hovered, pressed or disabled, and a scene does not save it, as images are made as the program runs. With:toggle-mode tit stays pressed until pressed again,button-pressed, and emitstoggled. Itsbutton-shortcut, an action or a binding such as(:symbol :s :control), acts on it from the keyboard while it shows, and its tooltip shows the shortcut's text; with abutton-shortcut-context, a node, as Godot'sshortcut_context, only while the keyboard focus is in that node, as a toolbar's shortcuts act only while its part of the window has the focus.button-disabledturns it off;button-draw-modesays how it looks now, for a button class of your own onbase-button.- A
button-group, a resource that toggle buttons hold as theirbutton-group, as Godot's ButtonGroup, presses them one at a time: pressing one turns the others off, and pressing it again leaves it on, unlessbutton-group-allow-unpressis true. It emitspressedwith the button pressed on, a signal of the group;button-group-buttonslists the buttons in a tree that belong to it, andbutton-group-pressed-buttongives the one pressed. A scene saves the group once, which its buttons share. check-boxis a toggle button with a box before its text, checked while it is on; in a button group it is a radio button, a circle with a dot.color-rectfills its rectangle withcolor-rect-color, as Godot's ColorRect: a background, a veil over a paused game, or a bar a game stretches. It stops the pointer, as a control does, unless its pointer filter is:ignore.hseparatorandvseparatordraw a line across or down between controls, as Godot's separators: their theme's:separatorstyle box, aline-style-box, in their middle, and:separationunits across their line.hsliderandvsliderare ranges set by dragging a grabber, or by the wheel and the arrow keys.progress-baris a range shown filled as far as its value, from the sideprogress-bar-fill-modesays, with its percentage, in whole percent rounded down. The percentage is counted in its steps, a hundredth by default, so that 0.29 of 1 shows 29%, where Godot 4.5 shows 28%, as the double-float nearest 0.29 is a little less.line-editis a line of text to type into,line-edit-text, with a caret and a selection. The arrow keys, Home and End move the caret, by words with Control, and Shift selects; a click puts the caret, a drag selects, and a double or triple click selects a word or the line. Control and X, C and V cut, copy and paste, on the clipboardclipboard-textreads: the desktop's, or, for a user interface that draws into no window, one its session shares. Control and Z undoes, and Control and Y redoes. What an input method composes, as for Chinese or Japanese, shows at the caret, underlined. It emitstext-changedas the user changes the text,text-submittedat Return, andtext-change-rejectedwhenline-edit-max-lengthleaves text out.line-edit-placeholdershows while it is empty, andline-edit-secretshows a password as bullets. Withline-edit-clear-button-enabled, a button at its right, while it has text, clears it, as Godot's clear button, an edit Control and Z undoes;line-edit-right-icondraws an image there, as a search field's magnifier.text-editis text of several lines to type into,text-edit-text, as Godot's TextEdit: a place in it is a line and a column,text-edit-caret-lineandtext-edit-caret-column. Its lines wrap at its width withtext-edit-wrap-mode:boundary, or scroll across with:none, the default, and scroll bars show where its text does not fit. Its keys are Godot's: Up and Down move by rows, Home and End to a row's ends and then the line's, Page Up and Page Down a page, Return breaks the line, and Tab types a tab whiletext-edit-tab-input-mode, which Control and M switch. Copying or cutting with nothing selected copies or cuts the caret's line, which pasting then puts in above the caret's line. As the user changes its text it emitslines-edited, with the first line the change touched, the last line it replaced and the last line it put there, as Godot'slines_edited_fromtells, thentext-changed, with nothing, as Godot'stext_changed:text-edit-textgives the text.text-edit-versionnumbers the text's versions, as Godot'sget_version: each change makes a new one, undoing it takes it back, andtext-edit-tag-saved-versionmarks one saved, so a text whose version istext-edit-saved-versionis as it was saved, as an editor shows a file unchanged once undone back to it.text-edit-set-linessets a text from a sequence of lines, without making them one string, as a file read into lines is shown. A text of any length types as quickly as a short one: its lines are its text, and the stringtext-edit-textgives is made from them when asked for; a line is laid out when it first shows, or the caret needs its rows, so a text of 100,000 lines lays out a screenful as it is set; and a long text keeps the layouts of the lines that show and of the 2,048 it laid out last, and the heights of all.text-edit-searchfinds text from a place, line by line, andtext-edit-search-text, withtext-edit-search-match-caseandtext-edit-search-whole-words, marks the occurrences in the lines that show, as a find bar does;text-edit-center-caretscrolls the caret's row to the middle, as going to a line does.text-edit-highlight-current-lineshows the caret's line behind its text, and withouttext-edit-deselect-on-focus-loss-enabledthe selection stays as the keyboard goes elsewhere. It needs only its style box's margins, so give it a custom minimum size or room in a container:text-edit-line-heighttimes the rows to show. A text edit for code, with colours, gutters, folding, completion and a find bar, is a code edit.spin-boxis a range shown as a field with two buttons: the buttons step its value, again and again while held, and dragging from them moves it; the number typed, or a sum such as2*(3+4), sets it at Return or as the field loses the focus. The number shows with as many decimals as the step has, less the zeros at the end but one, as Godot's: 2.5 and 3.0 in steps of 0.25.spin-box-prefixandspin-box-suffixshow around the number.item-listshows items of text to choose from, in a column or, withitem-list-max-columns, a grid: a click selects one, or several asitem-list-select-modeallows, emittingitem-selectedormulti-selected, and a double click or Return emitsitem-activated. The arrow keys move through them, typing goes to the item that starts so, and the wheel scrolls them. Its items arelist-itemobjects, whichmake-list-itemmakes, of a text, an icon, an image drawn before the text, tinted with itslist-item-icon-modulate, a tooltip, whether it is disabled or selectable, a colour of its own for its text,list-item-custom-fg-color, a smalllist-item-tag-icondrawn at the icon's corner, and metadata, any value;item-list-itemgives the one at an index,list-item-atthe index under a point, andlist-item-rectanglewhere an item is. Withitem-list-icon-mode:top, icons go above their text, as thumbnails do, each fitted toitem-list-fixed-icon-widthbyitem-list-fixed-icon-height, the text wrapped onitem-list-max-text-lineslines at most, the rest left out with an ellipsis; with:left, the default, text too wide for its item is cut short so.treeshowstree-itemobjects in a hierarchy, each a row of cells intree-columnscolumns, with titles iftree-column-titles-visible:create-tree-itemmakes them, the first the root, andsetfoftree-item-text,tree-item-icon, an image drawn before the text,tree-item-cell-mode,:stringor:check,tree-item-editable,tree-item-custom-color, a colour of the cell's own for its text,tree-item-custom-bg-color, one for its background, the first column's taking the row's indentation too, and the rest sets a cell.add-tree-item-buttonputs a button at the end of a cell, as Godot's TreeItem.add_button, which emitsbutton-clickedwith the item, the column and its id as it is clicked, and shows its tooltip;tree-item-buttonslists them. An item's children show under it, behind an arrow that folds them away. A click selects a cell, or astree-select-modesays a row or several cells, emittingitem-selected,cell-selectedormulti-selected; a click on an editable cell checks its box, or edits its text in place, emittingitem-edited, asedit-tree-selecteddoes for the cell chosen, with:selection-startand:selection-endthe part of the text selected, as a file's name without its extension, and with:forcea cell that is not editable, as Godot's file system dock renames its files; and a double click or Return emitsitem-activated. The arrow keys move through the rows and fold them, typing goes to the row that starts so, and the wheel scrolls them. Text too wide for its cell is cut short with an ellipsis, and shows whole as the cell's tooltip.
Their text is drawn in the theme's
:fontat:font-size, laid out once, and again only when it changes.
The widgets make a settings form:
(defpackage #:settings
(:use #:cl)
(:local-nicknames (#:sc #:pyssel/scene) (#:s2d #:pyssel/scene-2d) (#:ui #:pyssel/ui)))
(in-package #:settings)
(defun add (parent &rest children)
(dolist (child children parent)
(sc:add-child parent child)))
(defun save-settings (form &optional text)
"Print what FORM says: as its Save button is pressed, and with the TEXT
of its name field as Return is pressed there."
(declare (ignore text))
(format t "~&~S: volume ~D, music ~:[off~;on~].~%"
(ui:line-edit-text (sc:find-node form "box/name"))
(round (ui:range-value (sc:find-node form "box/volume-row/volume")))
(ui:button-pressed (sc:find-node form "box/music"))))
(defun make-form ()
(let ((form (make-instance 'ui:panel-container
:name "form" :preset :center
:style-box-overrides
(list :panel (make-instance 'ui:flat-style-box
:background-color '(0.15 0.15 0.2)
:corner-radius 6 :content-margin 16))))
(name (make-instance 'ui:line-edit :name "name" :placeholder "Your name"))
(save (make-instance 'ui:button :name "save" :text "Save")))
(sc:connect save 'ui:pressed form 'save-settings)
(sc:connect name 'ui:text-submitted form 'save-settings)
(add form
(add (make-instance 'ui:vbox-container :name "box" :custom-minimum-width 260)
(make-instance 'ui:label :text "Settings" :horizontal-alignment :center)
name
(add (make-instance 'ui:hbox-container :name "volume-row")
(make-instance 'ui:label :text "Volume")
(make-instance 'ui:hslider :name "volume" :value 70 :expand-horizontal t
:size-vertical :shrink-center))
(make-instance 'ui:check-box :name "music" :text "Music" :pressed t)
(make-instance 'ui:progress-bar :name "download")
save))))
(defvar *tree* (s2d:run (make-form) :title "Settings" :width 480 :height 320))
Type your name, drag the slider, click the check box, or Tab to them and
use the arrow keys and Space; Save, or Return in the name, prints the
settings in your REPL. The form's state is in its controls: the
connections give save-settings the form, a node, which finds its parts
by their paths, and *tree* is the REPL's way in. Fill the progress bar
from there:
(defun form (tree)
(sc:find-node (sc:tree-root tree) "form"))
(sc:call-in-tree *tree*
(lambda () (setf (ui:range-value (sc:find-node (form *tree*) "box/download")) 60)))
Popups, Menus and Dialogs adds to the form.
Getting started
The core
Drawing
Scenes
User interface
Games and the editor
- Playing a Game
- Projects
- The Editor
- The File System Dock
- The Script Screen
- The REPL
- The Debugger
- Lisp Text
- Code Services
- Project Manager
- Undo and Redo
- Exporting
The project