diff --git a/.gitignore b/.gitignore index 387c892..0368e87 100644 --- a/.gitignore +++ b/.gitignore @@ -40,9 +40,11 @@ luac.out *.x86_64 *.hex +# VS Code cruft +.vscode/ +# crush output directory +lib/ # ldoc output directory doc/ -# crush library directory -lib/ diff --git a/button.lua b/button.lua index 7161838..6a64cbb 100644 --- a/button.lua +++ b/button.lua @@ -1,3 +1,13 @@ +--- Implements a clickable button widget +-- +-- @classmod yui.Button +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +-- +--- Button widget receives the following callbacks: @{yui.Widget.WidgetCallbacks|onEnter}(), @{yui.Widget.WidgetCallbacks|onHit}(), @{yui.Widget.WidgetCallbacks|onLeave}(). + + local BASE = (...):gsub('button$', '') local Widget = require(BASE..'widget') @@ -9,7 +19,20 @@ local T = require('lib.moonspeak').translate local Button = setmetatable({}, Widget) Button.__index = Button +--- Attributes accepted by the @{Button} widget beyond the standard @{yui.Widget.WidgetAttributes|attributes} +-- and @{yui.Widget.WidgetCallbacks|callbacks}. +-- +-- and @{yui.Widget.WidgetCallbacks|callbacks}. +-- @field text (string) text displayed inside the button +-- @field[opt='center'] valign (string) vertical alignment 'top', 'bottom', 'center' +-- @field[opt='center'] align (string) horizontal alignment, 'left', 'center', 'right' +-- @field cornerRadius (number) radius for rounded corners +-- @field notranslate (boolean) don't translate text +-- @table ButtonAttributes + +--- Button constructor +-- @param args (@{ButtonAttributes}) widget attributes function Button.new(args) local self = setmetatable(args, Button) diff --git a/checkbox.lua b/checkbox.lua index 07bc228..1d1b513 100644 --- a/checkbox.lua +++ b/checkbox.lua @@ -1,3 +1,11 @@ +--- Implements a checkbox widget with a binary tick selection +-- +-- @classmod yui.Checkbox +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- Checkbox widget receives the following callbacks: @{yui.Widget.WidgetCallbacks|onEnter}(), @{yui.Widget.WidgetCallbacks|onChange}(), @{yui.Widget.WidgetCallbacks|onLeave}(). + local BASE = (...):gsub('checkbox$', '') local Widget = require(BASE..'widget') @@ -10,6 +18,20 @@ local Checkbox = setmetatable({}, Widget) Checkbox.__index = Checkbox +--- Attributes accepted by the @{Checkbox} widget beyond the standard @{yui.Widget.WidgetAttributes|attributes} +-- and @{yui.Widget.WidgetCallbacks|callbacks}. +-- +-- @field checked (boolean) to set it checked by default +-- @field text (string) text displayed inside the Checkbox +-- @field[opt='center'] valign (string) vertical alignment 'top', 'bottom', 'center' +-- @field[opt='center'] align (string) horizontal alignment, 'left', 'center', 'right' +-- @field cornerRadius (number) radius for rounded corners +-- @field notranslate (boolean) don't translate text +-- @table CheckboxAttributes + + +--- Checkbox constructor +-- @param args (@{CheckboxAttributes}) widget attributes function Checkbox.new(args) local self = setmetatable(args, Checkbox) diff --git a/choice.lua b/choice.lua index a8848c2..9806fbe 100644 --- a/choice.lua +++ b/choice.lua @@ -1,3 +1,11 @@ +--- Implements a multi-choice widget +-- +-- @classmod yui.Choice +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- Multi-choice widget receives the following callbacks: @{yui.Widget.WidgetCallbacks|onEnter}(), @{yui.Widget.WidgetCallbacks|onChange}(), @{yui.Widget.WidgetCallbacks|onLeave}(). + local BASE = (...):gsub('choice$', '') local Widget = require(BASE..'widget') @@ -11,7 +19,20 @@ local Choice = setmetatable({ }, Widget) Choice.__index = Choice +--- Attributes accepted by the @{Choice} widget beyond the standard @{yui.Widget.WidgetAttributes|attributes} +-- and @{yui.Widget.WidgetCallbacks|callbacks}. +-- +-- @field choices (table) available choices list +-- @field nowrap (boolean) disable choices wrapping +-- @field[opt='center'] valign (string) vertical alignment 'top', 'bottom', 'center' +-- @field[opt='center'] align (string) horizontal alignment, 'left', 'center', 'right' +-- @field cornerRadius (number) radius for rounded corners +-- @field notranslate (boolean) don't translate text +-- @table ChoiceAttributes + +--- Choice constructor +-- @param args (@{ChoiceAttributes}) widget attributes function Choice.new(args) local self = setmetatable(args, Choice) diff --git a/columns.lua b/columns.lua index e2ba5bc..25115a4 100644 --- a/columns.lua +++ b/columns.lua @@ -1,9 +1,17 @@ +--- Columns layout for widgets +-- +-- @classmod yui.Columns +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- A widget container, lays down its child widgets into multiple columns. + local BASE = (...):gsub('columns$', '') local Layout = require(BASE..'layout') --- Advance position to next column, --- given current position, widget dimensions and padding. +-- Advance position to next column +-- given current position, widget dimensions and padding local function columnadvance(x,y, ww,wh, padding) return x + ww + padding, y end diff --git a/config.ld b/config.ld new file mode 100644 index 0000000..9702056 --- /dev/null +++ b/config.ld @@ -0,0 +1,35 @@ +project = 'Yui' +title = 'Yui docs' +description = 'Yui is Yet another User Interface library.' +format = 'markdown' +full_description = [[ +The Yui library assists in designing menu screens, pause menus, HUDs, and such. + +Source code: @{https://git.doublefourteen.io/lua/yui} + +Examples: @{https://git.doublefourteen.io/lua/yui-examples} + +Pictures: @{https://git.doublefourteen.io/lua/yui-examples/src/branch/master/pics} + + +The main features: grid layout, widget navigation with keyboard/joystick buttons, support for managing custom +input devices (keyboard, mouse, touch, gamepad), and an easily extensible widget collection. The user interface is +described with a declarative approach: the layout is defined once, and events are handled in the callbacks. + +Integrated support for localization was achieved through the use of another library: moonspeak. +(@{https://git.doublefourteen.io/lua/moonspeak}) + +Most of the widget and theme rendering code are re-used from Matthias Richter's SUIT library. +(@{https://github.com/vrld/suit}) + +]] +file = {'', exclude = {'crush.lua'}} + + + +custom_see_handler('^https://(.+)$', function(root) + local url ='https://'..root + + return url, + url + end) diff --git a/crush.lua b/crush.lua index 5777248..22b3ee1 100644 --- a/crush.lua +++ b/crush.lua @@ -1,12 +1,13 @@ ---- crush - The uncomplicated dependency system for LÖVE. +--- Crush +-- +-- The uncomplicated dependency system for LÖVE. +-- +-- @module crush +-- @copyright 2022 The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti +-- @author Andrea Pasquini +-- -- --- Author: Lorenzo Cogotti --- Copyright: 2022 The DoubleFourteen Code Forge --- License: MIT (see LICENSE file for details) - -local io = require 'io' -local os = require 'os' - -- System specific functions -- -- Portions of this code are based on work from the LuaRocks project. @@ -15,6 +16,11 @@ local os = require 'os' -- LuaRocks website: https://luarocks.org -- LuaRocks sources: https://github.com/luarocks/luarocks +local io = require 'io' +local os = require 'os' + + + local is_windows = package.config:sub(1,1) == "\\" local is_directory diff --git a/input.lua b/input.lua index 053fcaf..b72768b 100644 --- a/input.lua +++ b/input.lua @@ -1,3 +1,12 @@ +--- Implements a text input field widget (textfield) +-- +-- @classmod yui.Input +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- Input widget receives the following callbacks: @{yui.Widget.WidgetCallbacks|onEnter}(), @{yui.Widget.WidgetCallbacks|onChange}(), @{yui.Widget.WidgetCallbacks|onLeave}(). + + local BASE = (...):gsub('input$', '') local Widget = require(BASE..'widget') @@ -18,6 +27,16 @@ local function split(str, pos) return str:sub(1, ofs-1), str:sub(ofs) end +--- Attributes accepted by the @{Input} widget beyond the standard @{yui.Widget.WidgetAttributes|attributes} +-- and @{yui.Widget.WidgetCallbacks|callbacks}. +-- +-- @field text (string) text displayed inside the Input +-- @field cornerRadius (number) radius for rounded corners +-- @table InputAttributes + + +--- Input constructor +-- @param args (@{InputAttributes}) widget attributes function Input.new(args) local self = setmetatable(args, Input) diff --git a/label.lua b/label.lua index 425b038..6f185e3 100644 --- a/label.lua +++ b/label.lua @@ -1,3 +1,10 @@ +--- Implements a static label widget +-- +-- @classmod yui.Label +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- + local BASE = (...):gsub('label$', '') local Widget = require(BASE..'widget') @@ -13,7 +20,16 @@ local Label = setmetatable({ }, Widget) Label.__index = Label +--- Attributes accepted by the @{Label} widget in addition to the standard @{yui.Widget.WidgetAttributes|attributes}. +-- +-- @field text (string) text displayed inside the Label +-- @field[opt='center'] valign (string) vertical alignment 'top', 'bottom', 'center' +-- @field[opt='center'] align (string) horizontal alignment, 'left', 'center', 'right' +-- @field notranslate (boolean) don't translate text +-- @table LabelAttributes +--- Label constructor +-- @param args (@{LabelAttributes}) widget attributes function Label.new(args) local self = setmetatable(args, Label) diff --git a/layout.lua b/layout.lua index 66959e2..102f8c8 100644 --- a/layout.lua +++ b/layout.lua @@ -1,3 +1,15 @@ +--- Layout container widget +-- +-- Implements a layout widget +-- +-- @classmod yui.Layout +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- @{Layout} is an internal class, serving as a container of widgets and helping to define their organization and display order. +-- It is useful for arrangement customization. + + local BASE = (...):gsub('layout$', '') local Widget = require(BASE..'widget') @@ -147,6 +159,14 @@ local function scanbackwards(layout, from) end end +--- Attributes accepted by the Layout widget +-- +-- @field padding (number) number of pixels between two elements +-- @table LayoutAttributes + + +--- Layout constructor +-- @param args (@{LayoutAttributes}) widget attributes function Layout.new(args) local self = setmetatable(args, Layout) @@ -165,17 +185,17 @@ function Layout.new(args) return self end ---- Find first widget in layout accepting focus. +--- Find the first widget in the layout accepting focus. function Layout:first() return scanforward(self) end ---- Find last widget in layout accepting focus. +--- Find the last widget in the layout accepting focus. function Layout:last() return scanbackwards(self) end ---- Find next focusable widget after the provided one. +--- Find the next focusable widget after the provided one. function Layout:after(widget) widget = childof(self, widget) @@ -187,7 +207,7 @@ function Layout:after(widget) end end ---- Find previous focusable widget before the provided one. +--- Find the previous focusable widget before the provided one. function Layout:before(widget) widget = childof(self, widget) diff --git a/rows.lua b/rows.lua index b1f3e3e..b6de635 100644 --- a/rows.lua +++ b/rows.lua @@ -1,3 +1,11 @@ +--- Row layout for widgets +-- +-- @classmod yui.Rows +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- A widget container, lays down its child widgets into multiple rows. + local BASE = (...):gsub('rows$', '') local Layout = require(BASE..'layout') diff --git a/slider.lua b/slider.lua index 32a0d46..bd37f6d 100644 --- a/slider.lua +++ b/slider.lua @@ -1,3 +1,11 @@ +--- Implements a scrollable slider widget +-- +-- @classmod yui.Slider +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- Slider widget receives the following callbacks: @{yui.Widget.WidgetCallbacks|onEnter}(), @{yui.Widget.WidgetCallbacks|onChange}(), @{yui.Widget.WidgetCallbacks|onLeave}(). + local BASE = (...):gsub('slider$', '') local Widget = require(BASE..'widget') @@ -6,7 +14,20 @@ local core = require(BASE..'core') local Slider = setmetatable({}, Widget) Slider.__index = Slider +--- Attributes accepted by the @{Slider} widget beyond the standard @{yui.Widget.WidgetAttributes|attributes} +-- and @{yui.Widget.WidgetCallbacks|callbacks}. +-- +-- @field min (number) min value of the slider +-- @field max (number) max value of the slider +-- @field vertical (boolean) true for vertical slider, false or nil for horizontal slider +-- @field value (number) default value +-- @field step (number) number of slider's steps +-- @field cornerRadius (number) radius for rounded corners +-- @table SliderAttributes + +--- Slider constructor +-- @param args (@{SliderAttributes}) widget attributes function Slider.new(args) local self = setmetatable(args, Slider) diff --git a/spacer.lua b/spacer.lua index bc1cae2..d7f2985 100644 --- a/spacer.lua +++ b/spacer.lua @@ -1,3 +1,11 @@ +--- Implements a spacer widget +-- +-- @classmod yui.Spacer +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- +--- Spacer widget insert a space between two widget. + local BASE = (...):gsub('spacer$', '') local Widget = require(BASE..'widget') @@ -10,6 +18,9 @@ local Spacer = setmetatable({ Spacer.__index = Spacer +--- Attributes accepted by the @{Spacer} widget @{yui.Widget.WidgetAttributes|attributes}. +-- +-- @param args @{yui.Widget.WidgetAttributes|Widgetattributes} widget attributes function Spacer.new(args) return setmetatable(args, Spacer) end return Spacer diff --git a/theme.lua b/theme.lua index 9d17b00..6bda54e 100644 --- a/theme.lua +++ b/theme.lua @@ -1,3 +1,27 @@ +--- Global visual theme settings +-- +-- @module yui.theme +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini + +--- Defines common visual attributes and colors applied to every @{yui.Widget|Widget}. +-- +-- @field cornerRadius (number) radius for rounded corners +-- @field color (@{ColorPalette}) default @{yui.Widget|Widget} color theme +-- @table theme + +--- Defines which color corresponds to each @{yui.Widget|Widget} state. +-- +-- @field hovered (@{Color}) color applied to hovered widgets +-- @field normal (@{Color}) color applied to widgets in their default state +-- @field active (@{Color}) color applied to active widgets +-- @table ColorPalette + +--- A pair defining background and foreground colors. +-- +-- @field bg (table) background color +-- @field fg (table) foreground color (typically used for text) +-- @table Color local theme = { cornerRadius = 4, diff --git a/ui.lua b/ui.lua index 892a60f..d063f65 100644 --- a/ui.lua +++ b/ui.lua @@ -1,3 +1,13 @@ +--- User interface manager +-- +-- @classmod yui.Ui +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini +-- + +--- An Ui manages a hierarchy of Widgets. +-- The @{Ui} draws its widgets according to their layout and position, manages input focus, and +-- dispatches events to the appropriate widgets depending on their class and activity status. local BASE = (...):gsub('ui$', '') local Widget = require(BASE..'widget') @@ -52,6 +62,15 @@ local function resolveautofocus(widget) return firstfocus, cancelfocus end +--- Attributes accepted by the Ui widget +-- +-- @field x (number) x position of the Ui +-- @field y (number) y position of the Ui +-- @table UiAttributes + + +--- Ui constructor +-- @param args (@{UiAttributes}) widget attributes function Ui.new(args) local self = setmetatable(args, Ui) assert(#self == 1, "Ui.new() must have exactly one root widget.") @@ -219,8 +238,7 @@ end --- Move focus to the given direction. -- --- @param where (string) Direction to move to, --- one of: 'up', 'down', 'left', 'right', 'cancel'. +-- @param where (string) Direction to move to, one of: 'up', 'down', 'left', 'right', 'cancel'. function Ui:navigate(where) local nextfocus = nil diff --git a/widget.lua b/widget.lua index 1bc85b2..c8769da 100644 --- a/widget.lua +++ b/widget.lua @@ -1,3 +1,20 @@ +--- A user interface element +-- @classmod yui.Widget +-- @copyright 2022, The DoubleFourteen Code Forge +-- @author Lorenzo Cogotti, Andrea Pasquini + +--- Functions accepted by all the Widget classes +-- @field onEnter function is called when the widget gets entered (e.g. hovered by pointer/mouse cursor) +-- @field onHit function is called when the widget is hit (e.g. clicked) +-- @field onChange function is called when the widget value is changed (e.g. checkbox is ticked) +-- @field onLeave function is called when the widget is left (e.g. another widget acquires focus, mouse leaves the widget area) +-- @table WidgetCallbacks + +--- Attributes accepted by all the Widget classes +-- @field w (number) widget width +-- @field h (number) widget height +-- @field color (@{yui.theme.ColorPalette|ColorPalette}) widget color +-- @table WidgetAttributes local rectunion = require('lib.gear.rect').union local Widget = { @@ -104,6 +121,7 @@ function Widget:loseFocus() end function Widget:gainFocus() end -- NOP event handlers, publicly overridable + function Widget:onHit() end function Widget:onEnter() end function Widget:onLeave() end