lights FAQ Forum github.com/luapower/ui
ui

Portable UI
ui WIP
codedit WIP

ui

Extensible UI toolkit in Lua


local ui = require'ui'

Extensible UI toolkit written in Lua featuring layouts, styles and animations.

Status

See issues and milestones.

Features

  • feature-packed editable grid that can scroll millions of rows at 60 fps.
  • tab list with animated, moveable, draggable, dockable tabs.
  • highly hackable code editor written in Lua.
  • consistent Unicode text rendering and editing on all platforms.
  • cascading styles.
  • declarative transition animations.
  • constraint-based, container-based and flow-based layouts.
  • affine transforms.

Example

local ui = require'ui'

local win = ui:window{
   cw = 500, ch = 300,
   title = 'UI Demo',
}

local b = ui:button{
   x = win.cw - ui.button.w - 20,
   y = win.ch - ui.button.h - 20,
   parent = win,
   text = 'Close',
   cancel = true,
}

ui:run()

The ui object

native properties
autoquit, maxfps, app_active,
app_visible, caret_blink_time,
displays, main_display,
active_display, app_id
these map directly to nw app
features, so see nw.
native methods
run, poll, stop, quit, runevery,
runafter, sleep, activate_app,
hide_app, unhide_app, key,
getclipboard, setclipboard,
opendialog, savedialog,
app_already_running,
wakeup_other_app_instances,
check_single_app_instance,
these map directly to nw app
features, so see nw.
font registration
ui:add_font_file(...) see tr:add_font_file(...)
ui:add_mem_font(...) see tr:add_mem_font(...)

Elements

selectors
TODO
stylesheets
TODO
attribute types
TODO
transition animations
TODO
interpolators
TODO
element lists
TODO
tags & styles
elem.stylesheet
elem:settag(tag, on)
elem:settags('+tag1 -tag2 ...')
attribute transitions
elem.transition_duration = 0
elem.transition_ease = 'expo out'
elem.transition_delay = 0
elem.transition_repeat = 1
elem.transition_speed = 1
elem.transition_blend =
'replace_nodelay'
elem:transition(attr, val, dt,
ease, duration, ease, delay,
times, backval, blend)
elem:transitioning(attr) -> t|f

Windows

ui:window{...} -> win
win:free()
parent/child relationship
win.parent
win:to_parent(x, y)
win:from_parent(x, y)
native methods
frame_rect, client_rect,
client_to_frame, frame_to_client,
closing, close, show, hide,
activate, minimize, maximize,
restore, shownormal, raise, lower,
to_screen, from_screen
these map directly to nw window
methods, so see nw.
native properties
x, y, w, h, cx, cy, cw, ch,
min_cw, min_ch, max_cw, max_ch,
autoquit, visible, fullscreen,
enabled, edgesnapping, topmost,
title, dead, closeable,
activable, minimizable, maximizable, resizeable,
fullscreenable, frame,
transparent, corner_radius, sticky, dead, active, isminimized,
ismaximized, display, cursor
these map directly to nw window
methods, so see nw.
element query interface
win:find(sel) -> elem_list
win:each(sel, f)
mouse state
win.mouse_x, win.mouse_y
win:mouse_pos() -> x, y
drawing
win:draw(cr)
win:invalidate()
frameless windows
win.move_layer

Layers

TODO

Box model

  • layers can be nested, which affects their painting order, clipping and positioning relative to each other.
  • layers have a "box" defined by their x, y, w, h, and a "content box" which is the same box adjusted by paddings.
  • layers are positioned and clipped relative to their parent's content box.
  • unlike html, the content box is not affected by borders.
  • borders can be drawn at an offset relative to the layer's box and the border's thickness.
  • a layer's contents and background can be clipped by the padding box of its parent, or by the border inner contour of its parent, or it can be left unclipped.

Mouse interaction

  • layers must be activable in order to receive mouse events.
  • a layer is hot when the mouse is over it or when it's active.
  • a layer must set active on mousedown and must reset it on mouseup in order to have the mouse captured while a mouse button is down; this can be done automatically by statically setting mousedown_activate.
  • while a layer is active, it continues to be hot and receive mousemove events even when the mouse is outside its hit test area or outside the window even (that is, the mouse is captured).
  • a layer must be active in order to receive drag & drop events.

Keyboard interaction

  • layers must be focusable in order to receive keyboard events.
  • keyboard events are only received by the focused layer.
  • return true in a keydown to eat up a key stroke so that it isn't used by other actions: this is how key conflicts are solved.

Widgets

input
ui:editbox(...) create an editbox
ui:dropdown(...) create a drop-down
ui:slider(...) create a slider
ui:checkbox(...) create a check box
ui:radiobutton(...) create a radio button
ui:choicebutton(...) create a multi-choice button
ui:colorpicker(...) create a calendar
ui:calendar(...)
output
ui:image(...) create an image
ui:progressbar(...) create a progress bar
input/output
ui:grid(...) create a grid
action
ui:button(...) create a button
ui:menu(...) create a menu
containers
ui:scrollbar(...) create a scroll bar
ui:scrollbox(...) create a scroll box
ui:popup(...) create a pop-up window
ui:tablist(...) create a tab list

TIP: Widgets are implemented in separate modules. Run each module standalone to see a demo of the widgets implemented in the module.

Editboxes

TODO
TODO

Sliders

TODO

Check boxes

TODO

Radio buttons

TODO

Multi-choice buttons

TODO

Calendars

TODO

Images

TODO

Progress bars

TODO

Editable grids

TODO

Buttons

TODO
TODO

Scroll bars

TODO

Scroll boxes

TODO

Pop-up windows

TODO

Tab lists

TODO

Creating new widgets

The API for creating and extending widgets is far larger and more complex than the API for instantiating and using existing widgets. This is normal, since widgets are supposed to encapsulate complex user interaction patterns as well as provide customizable presentation and behavior. This API is also less stable than the user API and not formally documented (that's not to say that it's not stable at all, and it is well documented in the code IMHO).

That being said, there are many programming features which combined enable short, clean, extensible implementations that don't degenerate into spagetti-code past a certain level of complexity.

These are the main programming features that need to be understood for hacking widgets:

The object system provides subclassing and instantiation (of course) but also virtual properties and method overriding hooks which are the bread and butter of extensible widget programming.

The ui layer class (the base class from which all widgets are derived) contains many abstractions that widgets can be built upon like relative positioning, hit testing and tab-based navigation.

The drag & drop API is nothing special except that it's a litte more complex so I mention it because it needs a little extra effort to understand. OTOH, ignoring it and reinventing it in your widgets or apps could be worse, since it's hard to get it right.


Last updated: 15 hours ago | Edit on GitHub

Pkg type:Lua+ffi
Version: dev-183-g5e76538
Last commit:
License: PD
Requires: amoeba  bitmap  box2d  boxblur  cairo  codedit  color  easing  freetype  fs  glue  luajit  oo  path2d  time  tuple  path 
Required by: none

Top