Skip to content

UI

Window methods use :; module functions such as ui.createWindow use .. Calls return true when admitted or nil, error unless a row states another result. Errors have operation = "ui", code, and message. Admission does not mean the Window has painted. Handles belong to the script runtime that created them and cannot be reused after reload. See Script-Created Windows for a complete input/action example and lifecycle behavior.

APIPurposeImportant contract
ui.createWindow(options)Create a TaskManSync-owned WindowReturns handle or nil, error; title up to 1,024 UTF-8 bytes, integer width/height 160..4096 (defaults 400/240), visible defaults true
ui.createRichText(html)Construct rich-text input dataReturns a typed value or nil, error; bounded HTML, not TDML
window:setTitle(title)Set Window titleUTF-8 string up to 1,024 bytes
window:setSize(width, height)Change Window sizeInteger dimensions 160..4096
window:show()Show and activateMay recreate native realization
window:hide()HideDoes not close the logical Window
window:close()CloseCloses current realization and records Window closure
window:isVisible()Read logical visibilityBoolean
window:toggleVisibility()Taskbar-style toggleShow/activate, or hide when visible and active
window:setContent(content)Replace Window contentAtomic complete replacement
window:getInput(id)Read an inputLatest valid typed value; nil when no value, nil, error for an unknown input/invalid handle
window:applyCellMutations(mutations)Update Cell SpaceAtomic batch, max 8,192 entries
window:fullScreen()Enter fullscreenCommand
window:maximize()MaximizeCommand
window:minimize()MinimizeCommand
window:restore()Restore normal presentationCommand
window:raise()RaiseCommand
window:activate()Request activationCommand

Settings/preview Windows validate calls but perform no native operations. Menus are not available to Scripted Decorations.

Content Values

window:setContent({ text = "...", inputs = {...}, actions = {...}, animated = false, visual = {...} }) replaces everything, including input values. Omitted collections become empty. Invalid fields, duplicate IDs, missing callback functions, or invalid values reject the whole replacement. text is a UTF-8 string, limited to 65,536 bytes, not taskbar TDML. Actions and inputs each have at most 16 entries. IDs are non-empty, at most 64 characters, and use ASCII letters, digits, _, or -. Labels are UTF-8 up to 1,024 bytes.

An action is { id = "apply", label = "Apply", enabled = true, callback = "applyValue" }. enabled defaults true; callback names an existing global function, not a function value. A complete example shows the callback reading form data. Required-input validation also applies to visual buttons.

The optional visual table has these fields:

FieldRecord or valueLimits and defaults
background, fontFamilyColor string, font-family stringColors up to 64 UTF-8 bytes; family up to 256 bytes
items{ x=32, y=18, text="A", color="#39FF72", pixelSize=16, opacity=1, bold=false }Up to 2,048; x/y -4096..4096, text 256 UTF-8 bytes each/65,536 total, integer size 1..256, opacity 0..1
lines{ x1=0, y1=0, x2=1, y2=1, color="#39FF72", width=2 }Up to 2,048; endpoints 0..1, integer width 1..256, default 1
pathsLogical-pixel rectangle plus fill, stroke, strokeWidth, operationsSame shape and limits as Decoration paths
cells{ column=20, row=10, character="@", foreground="#FFFFFF", background="#202020" }Sparse; up to 8,192 retained cell records (not a grid dimension); unique integer coordinates, column and row each independently 1..4096
buttons{ id="apply", x=12, y=12, width=80, height=28, label="Apply", callback="applyValue", enabled=true }Up to 16; x/y -4096..4096, dimensions 1..4096, IDs unique across buttons and actions

Visual colors use Qt color syntax, including #RRGGBB and alpha-first #AARRGGBB, not TDML’s alpha-last eight-digit form. Visual buttons also accept optional color and labelColor; omitted label color uses automatic contrast. Their native hover/focus/disabled styling remains host-controlled. Positioned text is a UTF-8 string styled by its record fields, not TDML. Within the visual surface, layers are background, cells, lines, paths, text items, then buttons; ordinary text/inputs/actions are a separate layer above it. There is no per-primitive z-order or pointer-hit-test API.

Cell Space accepts exactly one printable Basic Latin character (U+0020..U+007E) or Halfwidth Forms character (U+FF61..U+FF9F) per record, not arbitrary Unicode, emoji, or combining/wide characters. Off-grid cells are clipped and may become visible when resized. Cell mutations are contiguous arrays of set, clear, or clearAll records. clearAll must be first and has no cell fields; addressed coordinates cannot repeat in a batch. The batch and retained collection are each limited to 8,192 entries. Mutations preserve other Window content, while complete content replacement replaces the cells.

animated = true delivers visible Window frame opportunities to onTick(frameTimeSeconds). onResize(windowId, dimensions) provides positive columns, rows, and surfaceAspect (visual width/height ratio), not pixel size, font metrics, or DPI. Initial dimensions arrive after realization; resize bursts coalesce, and hidden/minimized/preview Windows do not deliver them.

onKey(key, modifiers) receives key presses only for a focused visible Window. Keys are 0-9, A-Z, F1-F12, Escape, Enter, Space, Tab, Backspace, Delete, Insert, Left, Right, Up, Down, Home, End, PageUp, and PageDown. Modifiers are boolean shift, ctrl, alt, and meta. Fullscreen Escape is handled by the host before Lua. The callback does not receive a Window ID, key releases, repeat notifications, or text-composition events.

Window Inputs

Inputs share id, kind, optional label, optional value, and required (default false). An omitted value reads as nil; a supplied empty string or false is a valid value. An invalid edit retains the last valid value but prevents action activation if that input is required. Application policy, such as requiring a future alarm time, belongs in Lua. There is no general input-change callback; read values in an action or another callback using getInput().

kindAccepted/returned valueAdditional fields and behavior
dateTimetime instantLocal-system date/time; optional components from year, month, day, hour, minute, second; hourFormat is "24" (default) or "12"
durationtime durationNon-negative; compare with a duration value, not a bare number
booleanLua booleanCheckbox; omitted required value is invalid even if displayed unchecked
inputboxUTF-8 stringSingle line, up to 65,536 bytes
numberFinite Lua number-1000000000..1000000000; optional minimum/maximum narrow the inclusive range; not an integer-only input
choiceSelected string identifierRequired options array with 1..64 unique { value="fast", label="Fast" } records; value must match an option
editboxUTF-8 string or rich-text valueMultiline; textFormat = "plainText" by default, or "richText"; serialized text up to 65,536 bytes
calendartime instant at local midnightDate only; rejects non-midnight values and does not accept components or hourFormat

For dateTime, omitted components are fixed rather than editable; an omitted second is fixed at zero. If components is absent, all six are available. Twelve-hour display changes only presentation; Lua still receives a normal instant. See Time for arithmetic and persistent millisecond conversion.

Rich-text editboxes require ui.createRichText(html), not a Lua string containing HTML. The returned value has :toHtml() and :toPlainText(). Persist the HTML string, then call createRichText when restoring; neither storage nor JSON accepts the rich-text value itself. This fragment installs a restored document in an existing Window:

local html = storage.getOrDefault("documentHtml", "<p>Initial <b>notes</b></p>")
local notes, richError = ui.createRichText(html)
if not notes then
	log.error(richError.message)
	return
end

function saveNotes()
	local value, inputError = window:getInput("notes")
	if not value then
		if inputError then log.error(inputError.message) end
		return
	end
	local accepted, err = storage.set("documentHtml", value:toHtml())
	if not accepted then log.error(err.message) end
end

local ok, contentError = window:setContent({
	inputs = {
		{ id = "notes", kind = "editbox", textFormat = "richText", value = notes,
		  toolbar = {
			  { id = "bold", label = "B", command = "bold" },
			  { id = "bullets", label = "Bullets", command = "bulletList" },
		  } },
	},
	actions = { { id = "save", label = "Save", callback = "saveNotes" } },
})
if not ok then log.error(contentError.message) end

The example queues the save; use storage.flush before reporting durable success. HTML is the rich-text serialization format, not Markdown or taskbar TDML, and does not expose a native document object.

The optional formatting toolbar contains { id, label, command } records. Commands are bold, italic, underline, strikeout, textColor, paragraph, heading1, heading2, fontDecrease, fontIncrease, alignLeft, alignCenter, alignRight, bulletList, numberedList, outdent, and indent. They act on the current selection, or subsequent typing for character formatting; textColor opens a color picker. Each toolbar is limited to 16 records and is available only for rich-text editboxes.

topToolbar uses the same record shape for separator, save, cut, copy, paste, undo, redo, and spellCheck. A save record must have a matching normal Window action ID; it invokes that action rather than saving automatically. Spell-check availability depends on the host editor support. These controls do not provide arbitrary widgets, layouts, link dialogs, or QML access. The exported Rich Text Editor.lua demonstrates the complete editor and flush handling.