3 Themes
dxtr edited this page 2026-10-20 00:28:25 +02:00

Themes

A control draws with the items of themes, as Godot's do: colours, constants, fonts, font sizes, style boxes and icons, found by name in the control's own items, in the themes of the control and its ancestors, and in the default theme.

  • Theme items are what a control draws with, by name: colours, constants, fonts, font sizes, style boxes and icons, the kinds the type theme-item-kind names, which control-color, control-constant, control-font, control-font-size, control-style-box and control-icon find. They look in the control's own items, which setf of them sets one by one, setf of control-color-overrides and the rest all at once, or :color-overrides and the rest when making one; then in the control-theme of the control and of its ancestors, nearest first; then in default-theme, of which each session has its own. In each theme, a class's items come before those of the classes it inherits from, so an item for ui:control reaches every control, and theme-item-names lists those a class finds in a theme. An item no theme gives is an error, unless the lookup is given a default.
  • Themes are resources, saved in files of their own or with the scenes that hold them. make-instance of theme takes :colors, :constants, :fonts, :font-sizes, :style-boxes and :icons, each a list of (class name value ...) entries; theme-color and the rest read an item and setf it. Icons are images, made as the program runs at the display's scale, or SVG files' pathnames, which control-icon rasterizes at the scale of the control's window in its :font-color, as the default theme gives the file dialog's; a saved theme leaves them out, as a scene leaves out a control's own. Changing a theme or a style box draws and lays out again, at the next frame, the controls of the trees of the session it is changed in, so a game played in the editor's image changes its own and not the editor's; do it on the tree's thread.
  • Icons from SVG files: an icon-set rasterizes SVG files for one window, at icon-set-scale, the window's, the shapes SVG's currentColor paints in icon-set-color, and makes them again as either changes, moving icon-set-generation on; svg-icon gives a file's image at a size, and svg-image rasterizes one once. Each window keeps the icon sets its theme's SVG icons are rasterized in. An icon keeps its drawing, and is rasterized again for a canvas drawn at another scale, as a viewport zoomed in, so it is as sharp there as raster text, as Godot's DPITexture icons are. icons-directory holds Pyssel's icons that the default theme gives. cl-svgread reads the files and cl-svgread/ft2 rasterizes them.
  • Style boxes draw backgrounds. A flat-style-box fills its rectangle with style-box-background-color, draws a border inside its edges in style-box-border-color, as wide on each side as style-box-border-width-left and the rest say, all given at once by :border-width, and rounds its corners by style-box-corner-radius; it draws style-box-expand-margin-left and the rest past the rectangle it is given, all given at once by :expand-margin. Every style box has content margins, which keep content from its edges, style-box-content-margin-left and the rest, all given at once by :content-margin; a side given its own takes that instead, as (make-instance 'ui:style-box :content-margin 4 :content-margin-left 8). A line-style-box draws a line, as Godot's StyleBoxLine, which separators draw: across the top of its rectangle, or down its left edge with style-box-vertical, in style-box-color, style-box-thickness thick, reaching style-box-grow-begin before it and style-box-grow-end past it. draw-style-box draws one in a draw method. A plain style-box draws nothing.
  • The default theme gives every item pyssel/ui's controls use, as Godot's default theme has them: Inter as :font and JetBrains Mono as :code-font, at a :font-size of 16, in a light grey :font-color; the :panel of panels and panel containers, a dark grey at 60%; the separations of boxes and grids, 4 units; margin containers' margins, 0; and the scroll bars' translucent tracks and grabbers, which brighten under the pointer and as they are dragged. The two fonts, the fonts of Godot's editor, ship with pyssel/ui as variable fonts, so a pf:font-variation of either gives its other weights.

A control class of your own draws with theme items, falling back on defaults it gives where no theme has them, and a theme may give them for it:

(sc:define-node swatch (ui:control)
  ()
  (:tool t))

(defmethod s2d:draw ((swatch swatch) canvas)
  (pyssel/2d:fill-rect canvas 0 0 (ui:control-width swatch) (ui:control-height swatch)
                       (ui:control-color swatch :swatch-color '(1 0.6 0.2))
                       :radius (ui:control-constant swatch :radius 4)))

(sc:call-in-tree *tree*
                 (lambda ()
                   (setf (ui:theme-color (ui:control-theme (screen *tree*)) 'swatch :swatch-color)
                         '(0.4 0.6 1))
                   (sc:add-child (screen *tree*)
                                 (make-instance 'swatch :preset :center-left :preset-margin 16
                                                        :custom-minimum-width 40
                                                        :custom-minimum-height 40))))

It goes in the panels of User Interface, whose screen finds the screen panel that holds their theme.