Merge branch 'main' into main
This commit is contained in:
10065
BasaltLS.lua
10065
BasaltLS.lua
File diff suppressed because it is too large
Load Diff
850
config.lua
850
config.lua
@@ -1,509 +1,517 @@
|
|||||||
return {
|
return {
|
||||||
["categories"] = {
|
["categories"] = {
|
||||||
["core"] = {
|
["libraries"] = {
|
||||||
["description"] = "Core Files",
|
|
||||||
["files"] = {
|
["files"] = {
|
||||||
["main"] = {
|
["collectionentry"] = {
|
||||||
["size"] = 19883,
|
["description"] = "",
|
||||||
["path"] = "main.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
["default"] = true,
|
||||||
|
["path"] = "libraries/collectionentry.lua",
|
||||||
|
["size"] = 3551,
|
||||||
},
|
},
|
||||||
["errorManager"] = {
|
["utils"] = {
|
||||||
["size"] = 3789,
|
["description"] = "",
|
||||||
["path"] = "errorManager.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
["default"] = true,
|
||||||
|
["path"] = "libraries/utils.lua",
|
||||||
|
["size"] = 2661,
|
||||||
},
|
},
|
||||||
["elementManager"] = {
|
["expect"] = {
|
||||||
["size"] = 15411,
|
["description"] = "",
|
||||||
["path"] = "elementManager.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
["default"] = true,
|
||||||
|
["path"] = "libraries/expect.lua",
|
||||||
|
["size"] = 846,
|
||||||
},
|
},
|
||||||
["render"] = {
|
["colorHex"] = {
|
||||||
["size"] = 12422,
|
["description"] = "",
|
||||||
["path"] = "render.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["propertySystem"] = {
|
|
||||||
["size"] = 18186,
|
|
||||||
["path"] = "propertySystem.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["layoutManager"] = {
|
|
||||||
["size"] = 3634,
|
|
||||||
["path"] = "layoutManager.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["init"] = {
|
|
||||||
["size"] = 622,
|
|
||||||
["path"] = "init.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["log"] = {
|
|
||||||
["size"] = 3142,
|
|
||||||
["path"] = "log.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
["default"] = true,
|
||||||
|
["path"] = "libraries/colorHex.lua",
|
||||||
|
["size"] = 132,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
["description"] = "Libraries",
|
||||||
|
},
|
||||||
|
["core"] = {
|
||||||
|
["files"] = {
|
||||||
|
["render"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "render.lua",
|
||||||
|
["size"] = 12422,
|
||||||
|
},
|
||||||
|
["errorManager"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "errorManager.lua",
|
||||||
|
["size"] = 3789,
|
||||||
|
},
|
||||||
|
["main"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "main.lua",
|
||||||
|
["size"] = 19883,
|
||||||
|
},
|
||||||
|
["init"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "init.lua",
|
||||||
|
["size"] = 622,
|
||||||
|
},
|
||||||
|
["log"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "log.lua",
|
||||||
|
["size"] = 3142,
|
||||||
|
},
|
||||||
|
["layoutManager"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "layoutManager.lua",
|
||||||
|
["size"] = 3634,
|
||||||
|
},
|
||||||
|
["elementManager"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elementManager.lua",
|
||||||
|
["size"] = 15411,
|
||||||
|
},
|
||||||
|
["propertySystem"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "propertySystem.lua",
|
||||||
|
["size"] = 18307,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["description"] = "Core Files",
|
||||||
|
},
|
||||||
|
["plugins"] = {
|
||||||
|
["files"] = {
|
||||||
|
["xml"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/xml.lua",
|
||||||
|
["size"] = 14068,
|
||||||
|
},
|
||||||
|
["canvas"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/canvas.lua",
|
||||||
|
["size"] = 7897,
|
||||||
|
},
|
||||||
|
["debug"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/debug.lua",
|
||||||
|
["size"] = 6274,
|
||||||
|
},
|
||||||
|
["reactive"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/reactive.lua",
|
||||||
|
["size"] = 11893,
|
||||||
|
},
|
||||||
|
["responsive"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/responsive.lua",
|
||||||
|
["size"] = 5529,
|
||||||
|
},
|
||||||
|
["theme"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/theme.lua",
|
||||||
|
["size"] = 6801,
|
||||||
|
},
|
||||||
|
["animation"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/animation.lua",
|
||||||
|
["size"] = 18446,
|
||||||
|
},
|
||||||
|
["benchmark"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "plugins/benchmark.lua",
|
||||||
|
["size"] = 12604,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
["description"] = "Plugins",
|
||||||
},
|
},
|
||||||
["elements"] = {
|
["elements"] = {
|
||||||
["description"] = "UI Elements",
|
|
||||||
["files"] = {
|
["files"] = {
|
||||||
["Program"] = {
|
|
||||||
["size"] = 12753,
|
|
||||||
["path"] = "elements/Program.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["LineChart"] = {
|
|
||||||
["size"] = 3172,
|
|
||||||
["path"] = "elements/LineChart.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["BarChart"] = {
|
|
||||||
["size"] = 3507,
|
|
||||||
["path"] = "elements/BarChart.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Timer"] = {
|
|
||||||
["size"] = 2938,
|
|
||||||
["path"] = "elements/Timer.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "BaseElement",
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["List"] = {
|
|
||||||
["size"] = 15474,
|
|
||||||
["path"] = "elements/List.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Collection",
|
|
||||||
},
|
|
||||||
["description"] = "A scrollable list of selectable items",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Image"] = {
|
|
||||||
["size"] = 15076,
|
|
||||||
["path"] = "elements/Image.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Input"] = {
|
|
||||||
["size"] = 9200,
|
|
||||||
["path"] = "elements/Input.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "A text input field with various features",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Collection"] = {
|
|
||||||
["size"] = 7778,
|
|
||||||
["path"] = "elements/Collection.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "A collection of items",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["SideNav"] = {
|
|
||||||
["size"] = 22159,
|
|
||||||
["path"] = "elements/SideNav.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Container",
|
|
||||||
},
|
|
||||||
["description"] = "A SideNav element that provides sidebar navigation with multiple content areas.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["ProgressBar"] = {
|
|
||||||
["size"] = 3398,
|
|
||||||
["path"] = "elements/ProgressBar.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Label"] = {
|
|
||||||
["size"] = 3088,
|
|
||||||
["path"] = "elements/Label.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "A simple text display element that automatically resizes its width based on the text content.",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["TextBox"] = {
|
|
||||||
["size"] = 43530,
|
|
||||||
["path"] = "elements/TextBox.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "A multi-line text editor component with cursor support and text manipulation features",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["Display"] = {
|
["Display"] = {
|
||||||
["size"] = 4493,
|
|
||||||
["path"] = "elements/Display.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "The Display is a special element which uses the CC Window API which you can use.",
|
["description"] = "The Display is a special element which uses the CC Window API which you can use.",
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["Graph"] = {
|
|
||||||
["size"] = 6933,
|
|
||||||
["path"] = "elements/Graph.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "A point based graph element",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["BaseElement"] = {
|
|
||||||
["size"] = 13870,
|
|
||||||
["path"] = "elements/BaseElement.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "The base class for all UI elements in Basalt.",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Accordion"] = {
|
|
||||||
["size"] = 14937,
|
|
||||||
["path"] = "elements/Accordion.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Container",
|
|
||||||
},
|
|
||||||
["description"] = "An Accordion element that provides collapsible panels with headers.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["ContextMenu"] = {
|
|
||||||
["size"] = 10660,
|
|
||||||
["path"] = "elements/ContextMenu.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Container",
|
|
||||||
},
|
|
||||||
["description"] = "A ContextMenu element that displays a menu with items and submenus.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["CheckBox"] = {
|
|
||||||
["size"] = 3700,
|
|
||||||
["path"] = "elements/CheckBox.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "This is a checkbox. It is a visual element that can be checked.",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Button"] = {
|
|
||||||
["size"] = 2437,
|
|
||||||
["path"] = "elements/Button.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "VisualElement",
|
[1] = "VisualElement",
|
||||||
},
|
},
|
||||||
["description"] = "The Button is a standard button element with click handling and state management.",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["Breadcrumb"] = {
|
|
||||||
["size"] = 4381,
|
|
||||||
["path"] = "elements/Breadcrumb.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "A breadcrumb navigation element that displays the current path.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["Table"] = {
|
|
||||||
["size"] = 25512,
|
|
||||||
["path"] = "elements/Table.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Collection",
|
|
||||||
},
|
|
||||||
["description"] = "The Table is a sortable data grid with customizable columns, row selection, and scrolling capabilities.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["ComboBox"] = {
|
|
||||||
["size"] = 14751,
|
|
||||||
["path"] = "elements/ComboBox.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "DropDown",
|
|
||||||
},
|
|
||||||
["description"] = "A ComboBox that combines dropdown selection with editable text input",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["ScrollBar"] = {
|
|
||||||
["size"] = 9689,
|
|
||||||
["path"] = "elements/ScrollBar.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "A ScrollBar element that can be attached to other elements to control their scroll properties.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["BigFont"] = {
|
|
||||||
["size"] = 21551,
|
|
||||||
["path"] = "elements/BigFont.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["Menu"] = {
|
|
||||||
["size"] = 8582,
|
|
||||||
["path"] = "elements/Menu.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "List",
|
|
||||||
},
|
|
||||||
["description"] = "A horizontal menu bar with selectable items.",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["TabControl"] = {
|
|
||||||
["size"] = 20900,
|
|
||||||
["path"] = "elements/TabControl.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Container",
|
|
||||||
},
|
|
||||||
["description"] = "A TabControl element that provides tabbed interface with multiple content areas.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["ScrollFrame"] = {
|
|
||||||
["size"] = 17463,
|
|
||||||
["path"] = "elements/ScrollFrame.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Container",
|
|
||||||
},
|
|
||||||
["description"] = "A scrollable container that automatically displays scrollbars when content overflows.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["Slider"] = {
|
|
||||||
["size"] = 5043,
|
|
||||||
["path"] = "elements/Slider.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "A slider control element for selecting a value within a range.",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/Display.lua",
|
||||||
|
["size"] = 4549,
|
||||||
},
|
},
|
||||||
["DropDown"] = {
|
["DropDown"] = {
|
||||||
["size"] = 7886,
|
["description"] = "A DropDown menu that shows a list of selectable items",
|
||||||
["path"] = "elements/DropDown.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "List",
|
[1] = "List",
|
||||||
},
|
},
|
||||||
["description"] = "A DropDown menu that shows a list of selectable items",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/DropDown.lua",
|
||||||
|
["size"] = 7988,
|
||||||
},
|
},
|
||||||
["Container"] = {
|
["Switch"] = {
|
||||||
["size"] = 27475,
|
["description"] = "The Switch is a standard Switch element with click handling and state management.",
|
||||||
["path"] = "elements/Container.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "VisualElement",
|
[1] = "VisualElement",
|
||||||
},
|
},
|
||||||
["description"] = "The container class. It is a visual element that can contain other elements. It is the base class for all containers",
|
["default"] = false,
|
||||||
|
["path"] = "elements/Switch.lua",
|
||||||
|
["size"] = 3375,
|
||||||
|
},
|
||||||
|
["BaseFrame"] = {
|
||||||
|
["description"] = "This is the base frame class. It is the root element of all elements and the only element without a parent.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "Container",
|
||||||
|
},
|
||||||
["default"] = true,
|
["default"] = true,
|
||||||
|
["path"] = "elements/BaseFrame.lua",
|
||||||
|
["size"] = 8972,
|
||||||
},
|
},
|
||||||
["Tree"] = {
|
["Table"] = {
|
||||||
["size"] = 22168,
|
["description"] = "The Table is a sortable data grid with customizable columns, row selection, and scrolling capabilities.",
|
||||||
["path"] = "elements/Tree.lua",
|
["requires"] = {
|
||||||
|
[1] = "Collection",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/Table.lua",
|
||||||
|
["size"] = 25766,
|
||||||
|
},
|
||||||
|
["Slider"] = {
|
||||||
|
["description"] = "A slider control element for selecting a value within a range.",
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "VisualElement",
|
[1] = "VisualElement",
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/Slider.lua",
|
||||||
|
["size"] = 5211,
|
||||||
|
},
|
||||||
|
["Input"] = {
|
||||||
|
["description"] = "A text input field with various features",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Input.lua",
|
||||||
|
["size"] = 9456,
|
||||||
|
},
|
||||||
|
["Collection"] = {
|
||||||
|
["description"] = "A collection of items",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Collection.lua",
|
||||||
|
["size"] = 7874,
|
||||||
|
},
|
||||||
|
["TextBox"] = {
|
||||||
|
["description"] = "A multi-line text editor component with cursor support and text manipulation features",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/TextBox.lua",
|
||||||
|
["size"] = 44462,
|
||||||
|
},
|
||||||
|
["BarChart"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/BarChart.lua",
|
||||||
|
["size"] = 3547,
|
||||||
|
},
|
||||||
|
["Accordion"] = {
|
||||||
|
["description"] = "An Accordion element that provides collapsible panels with headers.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "Container",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/Accordion.lua",
|
||||||
|
["size"] = 15169,
|
||||||
},
|
},
|
||||||
["Dialog"] = {
|
["Dialog"] = {
|
||||||
["size"] = 8901,
|
["description"] = "A dialog overlay system with common presets (alert, confirm, prompt).",
|
||||||
["path"] = "elements/Dialog.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "Frame",
|
[1] = "Frame",
|
||||||
},
|
},
|
||||||
["description"] = "A dialog overlay system with common presets (alert, confirm, prompt).",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
},
|
["path"] = "elements/Dialog.lua",
|
||||||
["Switch"] = {
|
["size"] = 9125,
|
||||||
["size"] = 3293,
|
|
||||||
["path"] = "elements/Switch.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "VisualElement",
|
|
||||||
},
|
|
||||||
["description"] = "The Switch is a standard Switch element with click handling and state management.",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["Frame"] = {
|
|
||||||
["size"] = 6646,
|
|
||||||
["path"] = "elements/Frame.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Container",
|
|
||||||
},
|
|
||||||
["description"] = "A frame element that serves as a grouping container for other elements.",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["BaseFrame"] = {
|
|
||||||
["size"] = 8972,
|
|
||||||
["path"] = "elements/BaseFrame.lua",
|
|
||||||
["requires"] = {
|
|
||||||
[1] = "Container",
|
|
||||||
},
|
|
||||||
["description"] = "This is the base frame class. It is the root element of all elements and the only element without a parent.",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
},
|
||||||
["Toast"] = {
|
["Toast"] = {
|
||||||
["size"] = 7897,
|
["description"] = "A toast notification element that displays temporary messages.",
|
||||||
["path"] = "elements/Toast.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "VisualElement",
|
[1] = "VisualElement",
|
||||||
},
|
},
|
||||||
["description"] = "A toast notification element that displays temporary messages.",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/Toast.lua",
|
||||||
|
["size"] = 7945,
|
||||||
|
},
|
||||||
|
["BigFont"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/BigFont.lua",
|
||||||
|
["size"] = 21675,
|
||||||
|
},
|
||||||
|
["TabControl"] = {
|
||||||
|
["description"] = "A TabControl element that provides tabbed interface with multiple content areas.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "Container",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/TabControl.lua",
|
||||||
|
["size"] = 21136,
|
||||||
|
},
|
||||||
|
["SideNav"] = {
|
||||||
|
["description"] = "A SideNav element that provides sidebar navigation with multiple content areas.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "Container",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/SideNav.lua",
|
||||||
|
["size"] = 22429,
|
||||||
|
},
|
||||||
|
["CheckBox"] = {
|
||||||
|
["description"] = "This is a checkbox. It is a visual element that can be checked.",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/CheckBox.lua",
|
||||||
|
["size"] = 3748,
|
||||||
|
},
|
||||||
|
["Image"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Image.lua",
|
||||||
|
["size"] = 15372,
|
||||||
|
},
|
||||||
|
["Menu"] = {
|
||||||
|
["description"] = "A horizontal menu bar with selectable items.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "List",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Menu.lua",
|
||||||
|
["size"] = 8758,
|
||||||
|
},
|
||||||
|
["Frame"] = {
|
||||||
|
["description"] = "A frame element that serves as a grouping container for other elements.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "Container",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Frame.lua",
|
||||||
|
["size"] = 6742,
|
||||||
|
},
|
||||||
|
["ContextMenu"] = {
|
||||||
|
["description"] = "A ContextMenu element that displays a menu with items and submenus.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "Container",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/ContextMenu.lua",
|
||||||
|
["size"] = 10836,
|
||||||
|
},
|
||||||
|
["List"] = {
|
||||||
|
["description"] = "A scrollable list of selectable items",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "Collection",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/List.lua",
|
||||||
|
["size"] = 15754,
|
||||||
|
},
|
||||||
|
["BaseElement"] = {
|
||||||
|
["description"] = "The base class for all UI elements in Basalt.",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/BaseElement.lua",
|
||||||
|
["size"] = 18468,
|
||||||
|
},
|
||||||
|
["Program"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/Program.lua",
|
||||||
|
["size"] = 12833,
|
||||||
|
},
|
||||||
|
["ProgressBar"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/ProgressBar.lua",
|
||||||
|
["size"] = 3440,
|
||||||
|
},
|
||||||
|
["Label"] = {
|
||||||
|
["description"] = "A simple text display element that automatically resizes its width based on the text content.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Label.lua",
|
||||||
|
["size"] = 3184,
|
||||||
|
},
|
||||||
|
["LineChart"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/LineChart.lua",
|
||||||
|
["size"] = 3228,
|
||||||
|
},
|
||||||
|
["ScrollBar"] = {
|
||||||
|
["description"] = "A ScrollBar element that can be attached to other elements to control their scroll properties.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/ScrollBar.lua",
|
||||||
|
["size"] = 9941,
|
||||||
|
},
|
||||||
|
["Button"] = {
|
||||||
|
["description"] = "The Button is a standard button element with click handling and state management.",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Button.lua",
|
||||||
|
["size"] = 2461,
|
||||||
|
},
|
||||||
|
["Tree"] = {
|
||||||
|
["description"] = "",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/Tree.lua",
|
||||||
|
["size"] = 22552,
|
||||||
|
},
|
||||||
|
["Container"] = {
|
||||||
|
["description"] = "The container class. It is a visual element that can contain other elements. It is the base class for all containers",
|
||||||
|
["requires"] = {
|
||||||
|
[1] = "VisualElement",
|
||||||
|
},
|
||||||
|
["default"] = true,
|
||||||
|
["path"] = "elements/Container.lua",
|
||||||
|
["size"] = 27731,
|
||||||
},
|
},
|
||||||
["VisualElement"] = {
|
["VisualElement"] = {
|
||||||
["size"] = 45082,
|
["description"] = "The Visual Element class which is the base class for all visual UI elements",
|
||||||
["path"] = "elements/VisualElement.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "BaseElement",
|
[1] = "BaseElement",
|
||||||
},
|
},
|
||||||
["description"] = "The Visual Element class which is the base class for all visual UI elements",
|
|
||||||
["default"] = true,
|
["default"] = true,
|
||||||
|
["path"] = "elements/VisualElement.lua",
|
||||||
|
["size"] = 45338,
|
||||||
},
|
},
|
||||||
},
|
["ScrollFrame"] = {
|
||||||
},
|
["description"] = "A scrollable container that automatically displays scrollbars when content overflows.",
|
||||||
["plugins"] = {
|
|
||||||
["description"] = "Plugins",
|
|
||||||
["files"] = {
|
|
||||||
["xml"] = {
|
|
||||||
["size"] = 14068,
|
|
||||||
["path"] = "plugins/xml.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
|
[1] = "Container",
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/ScrollFrame.lua",
|
||||||
|
["size"] = 17831,
|
||||||
},
|
},
|
||||||
["theme"] = {
|
["Timer"] = {
|
||||||
["size"] = 6801,
|
["description"] = "",
|
||||||
["path"] = "plugins/theme.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
|
[1] = "BaseElement",
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/Timer.lua",
|
||||||
|
["size"] = 2962,
|
||||||
},
|
},
|
||||||
["animation"] = {
|
["Breadcrumb"] = {
|
||||||
["size"] = 18446,
|
["description"] = "A breadcrumb navigation element that displays the current path.",
|
||||||
["path"] = "plugins/animation.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["debug"] = {
|
|
||||||
["size"] = 6274,
|
|
||||||
["path"] = "plugins/debug.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["reactive"] = {
|
|
||||||
["size"] = 11869,
|
|
||||||
["path"] = "plugins/reactive.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
|
||||||
},
|
|
||||||
["benchmark"] = {
|
|
||||||
["size"] = 12604,
|
|
||||||
["path"] = "plugins/benchmark.lua",
|
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
[1] = "VisualElement",
|
[1] = "VisualElement",
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/Breadcrumb.lua",
|
||||||
|
["size"] = 4461,
|
||||||
},
|
},
|
||||||
["canvas"] = {
|
["ComboBox"] = {
|
||||||
["size"] = 7897,
|
["description"] = "A ComboBox that combines dropdown selection with editable text input",
|
||||||
["path"] = "plugins/canvas.lua",
|
["requires"] = {
|
||||||
|
[1] = "DropDown",
|
||||||
|
},
|
||||||
|
["default"] = false,
|
||||||
|
["path"] = "elements/ComboBox.lua",
|
||||||
|
["size"] = 15143,
|
||||||
|
},
|
||||||
|
["Graph"] = {
|
||||||
|
["description"] = "A point based graph element",
|
||||||
["requires"] = {
|
["requires"] = {
|
||||||
},
|
},
|
||||||
["description"] = "",
|
|
||||||
["default"] = false,
|
["default"] = false,
|
||||||
|
["path"] = "elements/Graph.lua",
|
||||||
|
["size"] = 7045,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
["description"] = "UI Elements",
|
||||||
["libraries"] = {
|
|
||||||
["description"] = "Libraries",
|
|
||||||
["files"] = {
|
|
||||||
["utils"] = {
|
|
||||||
["size"] = 2661,
|
|
||||||
["path"] = "libraries/utils.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["colorHex"] = {
|
|
||||||
["size"] = 132,
|
|
||||||
["path"] = "libraries/colorHex.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["expect"] = {
|
|
||||||
["size"] = 846,
|
|
||||||
["path"] = "libraries/expect.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
["collectionentry"] = {
|
|
||||||
["size"] = 3551,
|
|
||||||
["path"] = "libraries/collectionentry.lua",
|
|
||||||
["requires"] = {
|
|
||||||
},
|
|
||||||
["description"] = "",
|
|
||||||
["default"] = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
["metadata"] = {
|
["metadata"] = {
|
||||||
|
["generated"] = "Wed Nov 5 00:37:16 2025",
|
||||||
["version"] = "2.0",
|
["version"] = "2.0",
|
||||||
["generated"] = "Tue Nov 4 09:01:43 2025",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -174,14 +174,14 @@ end
|
|||||||
--- @param expanded boolean Whether the panel starts expanded (default: false)
|
--- @param expanded boolean Whether the panel starts expanded (default: false)
|
||||||
--- @return table panelContainer The container for this panel
|
--- @return table panelContainer The container for this panel
|
||||||
function Accordion:newPanel(title, expanded)
|
function Accordion:newPanel(title, expanded)
|
||||||
local panels = self.get("panels") or {}
|
local panels = self.getResolved("panels") or {}
|
||||||
local panelId = #panels + 1
|
local panelId = #panels + 1
|
||||||
|
|
||||||
local panelContainer = self:addContainer()
|
local panelContainer = self:addContainer()
|
||||||
panelContainer.set("x", 1)
|
panelContainer.set("x", 1)
|
||||||
panelContainer.set("y", 1)
|
panelContainer.set("y", 1)
|
||||||
panelContainer.set("width", self.get("width"))
|
panelContainer.set("width", self.getResolved("width"))
|
||||||
panelContainer.set("height", self.get("height"))
|
panelContainer.set("height", self.getResolved("height"))
|
||||||
panelContainer.set("visible", expanded or false)
|
panelContainer.set("visible", expanded or false)
|
||||||
panelContainer.set("ignoreOffset", true)
|
panelContainer.set("ignoreOffset", true)
|
||||||
|
|
||||||
@@ -202,11 +202,11 @@ Accordion.addPanel = Accordion.newPanel
|
|||||||
--- @shortDescription Updates the layout of all panels (positions and visibility)
|
--- @shortDescription Updates the layout of all panels (positions and visibility)
|
||||||
--- @private
|
--- @private
|
||||||
function Accordion:updatePanelLayout()
|
function Accordion:updatePanelLayout()
|
||||||
local panels = self.get("panels") or {}
|
local panels = self.getResolved("panels") or {}
|
||||||
local headerHeight = self.get("panelHeaderHeight") or 1
|
local headerHeight = self.getResolved("panelHeaderHeight") or 1
|
||||||
local currentY = 1
|
local currentY = 1
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local accordionHeight = self.get("height")
|
local accordionHeight = self.getResolved("height")
|
||||||
|
|
||||||
for _, panel in ipairs(panels) do
|
for _, panel in ipairs(panels) do
|
||||||
local contentY = currentY + headerHeight
|
local contentY = currentY + headerHeight
|
||||||
@@ -238,7 +238,7 @@ function Accordion:updatePanelLayout()
|
|||||||
|
|
||||||
local totalHeight = currentY - 1
|
local totalHeight = currentY - 1
|
||||||
local maxOffset = math.max(0, totalHeight - accordionHeight)
|
local maxOffset = math.max(0, totalHeight - accordionHeight)
|
||||||
local currentOffset = self.get("offsetY")
|
local currentOffset = self.getResolved("offsetY")
|
||||||
|
|
||||||
if currentOffset > maxOffset then
|
if currentOffset > maxOffset then
|
||||||
self.set("offsetY", maxOffset)
|
self.set("offsetY", maxOffset)
|
||||||
@@ -251,8 +251,8 @@ end
|
|||||||
--- @param panelId number The ID of the panel to toggle
|
--- @param panelId number The ID of the panel to toggle
|
||||||
--- @return Accordion self For method chaining
|
--- @return Accordion self For method chaining
|
||||||
function Accordion:togglePanel(panelId)
|
function Accordion:togglePanel(panelId)
|
||||||
local panels = self.get("panels") or {}
|
local panels = self.getResolved("panels") or {}
|
||||||
local allowMultiple = self.get("allowMultiple")
|
local allowMultiple = self.getResolved("allowMultiple")
|
||||||
|
|
||||||
for i, panel in ipairs(panels) do
|
for i, panel in ipairs(panels) do
|
||||||
if panel.id == panelId then
|
if panel.id == panelId then
|
||||||
@@ -279,8 +279,8 @@ end
|
|||||||
--- @param panelId number The ID of the panel to expand
|
--- @param panelId number The ID of the panel to expand
|
||||||
--- @return Accordion self For method chaining
|
--- @return Accordion self For method chaining
|
||||||
function Accordion:expandPanel(panelId)
|
function Accordion:expandPanel(panelId)
|
||||||
local panels = self.get("panels") or {}
|
local panels = self.getResolved("panels") or {}
|
||||||
local allowMultiple = self.get("allowMultiple")
|
local allowMultiple = self.getResolved("allowMultiple")
|
||||||
|
|
||||||
for i, panel in ipairs(panels) do
|
for i, panel in ipairs(panels) do
|
||||||
if panel.id == panelId then
|
if panel.id == panelId then
|
||||||
@@ -309,7 +309,7 @@ end
|
|||||||
--- @param panelId number The ID of the panel to collapse
|
--- @param panelId number The ID of the panel to collapse
|
||||||
--- @return Accordion self For method chaining
|
--- @return Accordion self For method chaining
|
||||||
function Accordion:collapsePanel(panelId)
|
function Accordion:collapsePanel(panelId)
|
||||||
local panels = self.get("panels") or {}
|
local panels = self.getResolved("panels") or {}
|
||||||
|
|
||||||
for _, panel in ipairs(panels) do
|
for _, panel in ipairs(panels) do
|
||||||
if panel.id == panelId then
|
if panel.id == panelId then
|
||||||
@@ -329,7 +329,7 @@ end
|
|||||||
--- @param panelId number The ID of the panel
|
--- @param panelId number The ID of the panel
|
||||||
--- @return table? container The panel's container or nil
|
--- @return table? container The panel's container or nil
|
||||||
function Accordion:getPanel(panelId)
|
function Accordion:getPanel(panelId)
|
||||||
local panels = self.get("panels") or {}
|
local panels = self.getResolved("panels") or {}
|
||||||
for _, panel in ipairs(panels) do
|
for _, panel in ipairs(panels) do
|
||||||
if panel.id == panelId then
|
if panel.id == panelId then
|
||||||
return panel.container
|
return panel.container
|
||||||
@@ -342,8 +342,8 @@ end
|
|||||||
--- @return table metrics Panel layout information
|
--- @return table metrics Panel layout information
|
||||||
--- @private
|
--- @private
|
||||||
function Accordion:_getPanelMetrics()
|
function Accordion:_getPanelMetrics()
|
||||||
local panels = self.get("panels") or {}
|
local panels = self.getResolved("panels") or {}
|
||||||
local headerHeight = self.get("panelHeaderHeight") or 1
|
local headerHeight = self.getResolved("panelHeaderHeight") or 1
|
||||||
|
|
||||||
local positions = {}
|
local positions = {}
|
||||||
local currentY = 1
|
local currentY = 1
|
||||||
@@ -381,7 +381,7 @@ function Accordion:mouse_click(button, x, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local relX, relY = VisualElement.getRelativePosition(self, x, y)
|
local relX, relY = VisualElement.getRelativePosition(self, x, y)
|
||||||
local offsetY = self.get("offsetY")
|
local offsetY = self.getResolved("offsetY")
|
||||||
local adjustedY = relY + offsetY
|
local adjustedY = relY + offsetY
|
||||||
local metrics = self:_getPanelMetrics()
|
local metrics = self:_getPanelMetrics()
|
||||||
|
|
||||||
@@ -400,12 +400,12 @@ end
|
|||||||
function Accordion:mouse_scroll(direction, x, y)
|
function Accordion:mouse_scroll(direction, x, y)
|
||||||
if VisualElement.mouse_scroll(self, direction, x, y) then
|
if VisualElement.mouse_scroll(self, direction, x, y) then
|
||||||
local metrics = self:_getPanelMetrics()
|
local metrics = self:_getPanelMetrics()
|
||||||
local accordionHeight = self.get("height")
|
local accordionHeight = self.getResolved("height")
|
||||||
local totalHeight = metrics.totalHeight
|
local totalHeight = metrics.totalHeight
|
||||||
local maxOffset = math.max(0, totalHeight - accordionHeight)
|
local maxOffset = math.max(0, totalHeight - accordionHeight)
|
||||||
|
|
||||||
if maxOffset > 0 then
|
if maxOffset > 0 then
|
||||||
local currentOffset = self.get("offsetY")
|
local currentOffset = self.getResolved("offsetY")
|
||||||
local newOffset = currentOffset + direction
|
local newOffset = currentOffset + direction
|
||||||
newOffset = math.max(0, math.min(maxOffset, newOffset))
|
newOffset = math.max(0, math.min(maxOffset, newOffset))
|
||||||
self.set("offsetY", newOffset)
|
self.set("offsetY", newOffset)
|
||||||
@@ -422,17 +422,17 @@ end
|
|||||||
function Accordion:render()
|
function Accordion:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local offsetY = self.get("offsetY")
|
local offsetY = self.getResolved("offsetY")
|
||||||
local metrics = self:_getPanelMetrics()
|
local metrics = self:_getPanelMetrics()
|
||||||
|
|
||||||
for _, panelInfo in ipairs(metrics.positions) do
|
for _, panelInfo in ipairs(metrics.positions) do
|
||||||
local bgColor = panelInfo.expanded and self.get("expandedHeaderBackground") or self.get("headerBackground")
|
local bgColor = panelInfo.expanded and self.getResolved("expandedHeaderBackground") or self.getResolved("headerBackground")
|
||||||
local fgColor = panelInfo.expanded and self.get("expandedHeaderTextColor") or self.get("headerTextColor")
|
local fgColor = panelInfo.expanded and self.getResolved("expandedHeaderTextColor") or self.getResolved("headerTextColor")
|
||||||
|
|
||||||
local headerY = panelInfo.headerY - offsetY
|
local headerY = panelInfo.headerY - offsetY
|
||||||
|
|
||||||
if headerY >= 1 and headerY <= self.get("height") then
|
if headerY >= 1 and headerY <= self.getResolved("height") then
|
||||||
VisualElement.multiBlit(
|
VisualElement.multiBlit(
|
||||||
self,
|
self,
|
||||||
1,
|
1,
|
||||||
@@ -450,16 +450,16 @@ function Accordion:render()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("childrenSorted") then
|
if not self.getResolved("childrenSorted") then
|
||||||
self:sortChildren()
|
self:sortChildren()
|
||||||
end
|
end
|
||||||
if not self.get("childrenEventsSorted") then
|
if not self.getResolved("childrenEventsSorted") then
|
||||||
for eventName in pairs(self._values.childrenEvents or {}) do
|
for eventName in pairs(self._values.childrenEvents or {}) do
|
||||||
self:sortChildrenEvents(eventName)
|
self:sortChildrenEvents(eventName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, child in ipairs(self.get("visibleChildren") or {}) do
|
for _, child in ipairs(self.getResolved("visibleChildren") or {}) do
|
||||||
if child == self then
|
if child == self then
|
||||||
error("CIRCULAR REFERENCE DETECTED!")
|
error("CIRCULAR REFERENCE DETECTED!")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ end
|
|||||||
function BarChart:render()
|
function BarChart:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local minVal = self.get("minValue")
|
local minVal = self.getResolved("minValue")
|
||||||
local maxVal = self.get("maxValue")
|
local maxVal = self.getResolved("maxValue")
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
|
|
||||||
local activeSeriesCount = 0
|
local activeSeriesCount = 0
|
||||||
local seriesList = {}
|
local seriesList = {}
|
||||||
|
|||||||
@@ -225,13 +225,14 @@ end
|
|||||||
--- @param priority? number Optional priority override
|
--- @param priority? number Optional priority override
|
||||||
--- @return BaseElement self
|
--- @return BaseElement self
|
||||||
function BaseElement:setState(stateName, priority)
|
function BaseElement:setState(stateName, priority)
|
||||||
local states = self.get("states")
|
local states = self.getResolved("states")
|
||||||
|
|
||||||
if not priority and self._registeredStates[stateName] then
|
if not priority and self._registeredStates[stateName] then
|
||||||
priority = self._registeredStates[stateName].priority
|
priority = self._registeredStates[stateName].priority
|
||||||
end
|
end
|
||||||
|
|
||||||
states[stateName] = priority or 0
|
states[stateName] = priority or 0
|
||||||
|
|
||||||
self.set("states", states)
|
self.set("states", states)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -299,7 +300,9 @@ end
|
|||||||
function BaseElement:updateConditionalStates()
|
function BaseElement:updateConditionalStates()
|
||||||
for stateName, stateInfo in pairs(self._registeredStates) do
|
for stateName, stateInfo in pairs(self._registeredStates) do
|
||||||
if stateInfo.condition then
|
if stateInfo.condition then
|
||||||
if stateInfo.condition(self) then
|
local result = stateInfo.condition(self)
|
||||||
|
|
||||||
|
if result then
|
||||||
self:setState(stateName, stateInfo.priority)
|
self:setState(stateName, stateInfo.priority)
|
||||||
else
|
else
|
||||||
self:unsetState(stateName)
|
self:unsetState(stateName)
|
||||||
@@ -309,6 +312,145 @@ function BaseElement:updateConditionalStates()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Registers a responsive state that reacts to parent size changes
|
||||||
|
--- @shortDescription Registers a state that responds to parent dimensions
|
||||||
|
--- @param stateName string The name of the state
|
||||||
|
--- @param condition string|function Condition as string expression or function: function(element) return boolean end
|
||||||
|
--- @param options? table|number Options table with 'priority' and 'observe', or just priority number
|
||||||
|
--- @return BaseElement self
|
||||||
|
function BaseElement:registerResponsiveState(stateName, condition, options)
|
||||||
|
local priority = 100
|
||||||
|
local observeList = {}
|
||||||
|
if type(options) == "number" then
|
||||||
|
priority = options
|
||||||
|
elseif type(options) == "table" then
|
||||||
|
priority = options.priority or 100
|
||||||
|
observeList = options.observe or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local conditionFunc
|
||||||
|
local isStringExpr = type(condition) == "string"
|
||||||
|
|
||||||
|
if isStringExpr then
|
||||||
|
conditionFunc = self:_parseResponsiveExpression(condition)
|
||||||
|
|
||||||
|
local autoDeps = self:_detectDependencies(condition)
|
||||||
|
for _, dep in ipairs(autoDeps) do
|
||||||
|
table.insert(observeList, dep)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
conditionFunc = condition
|
||||||
|
end
|
||||||
|
self:registerState(stateName, conditionFunc, priority)
|
||||||
|
|
||||||
|
for _, observeInfo in ipairs(observeList) do
|
||||||
|
local element = observeInfo.element or observeInfo[1]
|
||||||
|
local property = observeInfo.property or observeInfo[2]
|
||||||
|
if element and property then
|
||||||
|
element:observe(property, function()
|
||||||
|
self:updateConditionalStates()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:updateConditionalStates()
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Parses a responsive expression string into a function
|
||||||
|
--- @private
|
||||||
|
--- @param expr string The expression to parse
|
||||||
|
--- @return function conditionFunc The parsed condition function
|
||||||
|
function BaseElement:_parseResponsiveExpression(expr)
|
||||||
|
local protectedNames = {
|
||||||
|
colors = true,
|
||||||
|
math = true,
|
||||||
|
clamp = true,
|
||||||
|
round = true
|
||||||
|
}
|
||||||
|
|
||||||
|
local mathEnv = {
|
||||||
|
clamp = function(val, min, max)
|
||||||
|
return math.min(math.max(val, min), max)
|
||||||
|
end,
|
||||||
|
round = function(val)
|
||||||
|
return math.floor(val + 0.5)
|
||||||
|
end,
|
||||||
|
floor = math.floor,
|
||||||
|
ceil = math.ceil,
|
||||||
|
abs = math.abs
|
||||||
|
}
|
||||||
|
|
||||||
|
expr = expr:gsub("([%w_]+)%.([%w_]+)", function(obj, prop)
|
||||||
|
if protectedNames[obj] or tonumber(obj) then
|
||||||
|
return obj.."."..prop
|
||||||
|
end
|
||||||
|
return string.format('__getProperty("%s", "%s")', obj, prop)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local element = self
|
||||||
|
local env = setmetatable({
|
||||||
|
colors = colors,
|
||||||
|
math = math,
|
||||||
|
tostring = tostring,
|
||||||
|
tonumber = tonumber,
|
||||||
|
__getProperty = function(objName, propName)
|
||||||
|
if objName == "self" then
|
||||||
|
if element._properties[propName] then
|
||||||
|
return element.get(propName)
|
||||||
|
end
|
||||||
|
elseif objName == "parent" then
|
||||||
|
if element.parent and element.parent._properties[propName] then
|
||||||
|
return element.parent.get(propName)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local target = element:getBaseFrame():getChild(objName)
|
||||||
|
if target and target._properties[propName] then
|
||||||
|
return target.get(propName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
}, { __index = mathEnv })
|
||||||
|
|
||||||
|
local func, err = load("return "..expr, "responsive", "t", env)
|
||||||
|
if not func then
|
||||||
|
error("Invalid responsive expression: " .. err)
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(self)
|
||||||
|
local ok, result = pcall(func)
|
||||||
|
return ok and result or false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Detects dependencies in a responsive expression
|
||||||
|
--- @private
|
||||||
|
--- @param expr string The expression to analyze
|
||||||
|
--- @return table dependencies List of {element, property} pairs
|
||||||
|
function BaseElement:_detectDependencies(expr)
|
||||||
|
local deps = {}
|
||||||
|
local protectedNames = {colors = true, math = true, clamp = true, round = true}
|
||||||
|
|
||||||
|
for ref, prop in expr:gmatch("([%w_]+)%.([%w_]+)") do
|
||||||
|
if not protectedNames[ref] and not tonumber(ref) then
|
||||||
|
local element
|
||||||
|
if ref == "self" then
|
||||||
|
element = self
|
||||||
|
elseif ref == "parent" then
|
||||||
|
element = self.parent
|
||||||
|
else
|
||||||
|
element = self:getBaseFrame():getChild(ref)
|
||||||
|
end
|
||||||
|
|
||||||
|
if element then
|
||||||
|
table.insert(deps, {element = element, property = prop})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return deps
|
||||||
|
end
|
||||||
|
|
||||||
--- Removes a state from the registry
|
--- Removes a state from the registry
|
||||||
--- @shortDescription Removes state definition
|
--- @shortDescription Removes state definition
|
||||||
--- @param stateName string The state to remove
|
--- @param stateName string The state to remove
|
||||||
@@ -325,9 +467,9 @@ end
|
|||||||
--- @param ... any Additional arguments to pass to the callbacks
|
--- @param ... any Additional arguments to pass to the callbacks
|
||||||
--- @return table self The BaseElement instance
|
--- @return table self The BaseElement instance
|
||||||
function BaseElement:fireEvent(event, ...)
|
function BaseElement:fireEvent(event, ...)
|
||||||
if self.get("eventCallbacks")[event] then
|
if self.getResolved("eventCallbacks")[event] then
|
||||||
local lastResult
|
local lastResult
|
||||||
for _, callback in ipairs(self.get("eventCallbacks")[event]) do
|
for _, callback in ipairs(self.getResolved("eventCallbacks")[event]) do
|
||||||
lastResult = callback(self, ...)
|
lastResult = callback(self, ...)
|
||||||
end
|
end
|
||||||
return lastResult
|
return lastResult
|
||||||
@@ -341,7 +483,7 @@ end
|
|||||||
--- @return boolean? handled Whether the event was handled
|
--- @return boolean? handled Whether the event was handled
|
||||||
--- @protected
|
--- @protected
|
||||||
function BaseElement:dispatchEvent(event, ...)
|
function BaseElement:dispatchEvent(event, ...)
|
||||||
if self.get("enabled") == false then
|
if self.getResolved("enabled") == false then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if self[event] then
|
if self[event] then
|
||||||
|
|||||||
@@ -171,12 +171,12 @@ BigFont.__index = BigFont
|
|||||||
|
|
||||||
---@property text string BigFont The text string to display in enlarged format
|
---@property text string BigFont The text string to display in enlarged format
|
||||||
BigFont.defineProperty(BigFont, "text", {default = "BigFont", type = "string", canTriggerRender = true, setter=function(self, value)
|
BigFont.defineProperty(BigFont, "text", {default = "BigFont", type = "string", canTriggerRender = true, setter=function(self, value)
|
||||||
self.bigfontText = makeText(self.get("fontSize"), value, self.get("foreground"), self.get("background"))
|
self.bigfontText = makeText(self.getResolved("fontSize"), value, self.getResolved("foreground"), self.getResolved("background"))
|
||||||
return value
|
return value
|
||||||
end})
|
end})
|
||||||
---@property fontSize number 1 Scale factor for text size (1-3, where 1 is 3x3 pixels per character)
|
---@property fontSize number 1 Scale factor for text size (1-3, where 1 is 3x3 pixels per character)
|
||||||
BigFont.defineProperty(BigFont, "fontSize", {default = 1, type = "number", canTriggerRender = true, setter=function(self, value)
|
BigFont.defineProperty(BigFont, "fontSize", {default = 1, type = "number", canTriggerRender = true, setter=function(self, value)
|
||||||
self.bigfontText = makeText(value, self.get("text"), self.get("foreground"), self.get("background"))
|
self.bigfontText = makeText(value, self.getResolved("text"), self.getResolved("foreground"), self.getResolved("background"))
|
||||||
return value
|
return value
|
||||||
end})
|
end})
|
||||||
|
|
||||||
@@ -200,10 +200,10 @@ function BigFont:init(props, basalt)
|
|||||||
VisualElement.init(self, props, basalt)
|
VisualElement.init(self, props, basalt)
|
||||||
self.set("type", "BigFont")
|
self.set("type", "BigFont")
|
||||||
self:observe("background", function(self, value)
|
self:observe("background", function(self, value)
|
||||||
self.bigfontText = makeText(self.get("fontSize"), self.get("text"), self.get("foreground"), value)
|
self.bigfontText = makeText(self.getResolved("fontSize"), self.getResolved("text"), self.getResolved("foreground"), value)
|
||||||
end)
|
end)
|
||||||
self:observe("foreground", function(self, value)
|
self:observe("foreground", function(self, value)
|
||||||
self.bigfontText = makeText(self.get("fontSize"), self.get("text"), value, self.get("background"))
|
self.bigfontText = makeText(self.getResolved("fontSize"), self.getResolved("text"), value, self.getResolved("background"))
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -212,11 +212,12 @@ end
|
|||||||
function BigFont:render()
|
function BigFont:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
if(self.bigfontText)then
|
if(self.bigfontText)then
|
||||||
local x, y = self.get("x"), self.get("y")
|
local x, y = self.getResolved("x"), self.getResolved("y")
|
||||||
|
local width = self.getResolved("width")
|
||||||
for i = 1, #self.bigfontText[1] do
|
for i = 1, #self.bigfontText[1] do
|
||||||
local text = self.bigfontText[1][i]:sub(1, self.get("width"))
|
local text = self.bigfontText[1][i]:sub(1, width)
|
||||||
local fg = self.bigfontText[2][i]:sub(1, self.get("width"))
|
local fg = self.bigfontText[2][i]:sub(1, width)
|
||||||
local bg = self.bigfontText[3][i]:sub(1, self.get("width"))
|
local bg = self.bigfontText[3][i]:sub(1, width)
|
||||||
self:blit(x, y + i - 1, text, fg, bg)
|
self:blit(x, y + i - 1, text, fg, bg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ end
|
|||||||
--- @param y number
|
--- @param y number
|
||||||
--- @return boolean handled
|
--- @return boolean handled
|
||||||
function Breadcrumb:mouse_click(button, x, y)
|
function Breadcrumb:mouse_click(button, x, y)
|
||||||
if not self.get("clickable") then return false end
|
if not self.getResolved("clickable") then return false end
|
||||||
if VisualElement.mouse_click(self, button, x, y) then
|
if VisualElement.mouse_click(self, button, x, y) then
|
||||||
local path = self.get("path")
|
local path = self.getResolved("path")
|
||||||
local separator = self.get("separator")
|
local separator = self.getResolved("separator")
|
||||||
|
|
||||||
local cursorX = 1
|
local cursorX = 1
|
||||||
for i, segment in ipairs(path) do
|
for i, segment in ipairs(path) do
|
||||||
@@ -81,11 +81,11 @@ end
|
|||||||
--- @shortDescription Renders the breadcrumb trail
|
--- @shortDescription Renders the breadcrumb trail
|
||||||
--- @protected
|
--- @protected
|
||||||
function Breadcrumb:render()
|
function Breadcrumb:render()
|
||||||
local path = self.get("path")
|
local path = self.getResolved("path")
|
||||||
local separator = self.get("separator")
|
local separator = self.getResolved("separator")
|
||||||
local fg = self.get("foreground")
|
local fg = self.getResolved("foreground")
|
||||||
local clickable = self.get("clickable")
|
local clickable = self.getResolved("clickable")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
|
|
||||||
local fullText = ""
|
local fullText = ""
|
||||||
for i, segment in ipairs(path) do
|
for i, segment in ipairs(path) do
|
||||||
@@ -95,8 +95,8 @@ function Breadcrumb:render()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.get("autoSize") then
|
if self.getResolved("autoSize") then
|
||||||
self.set("width", #fullText)
|
self.getResolved("width", #fullText)
|
||||||
else
|
else
|
||||||
if #fullText > width then
|
if #fullText > width then
|
||||||
local ellipsis = "... > "
|
local ellipsis = "... > "
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ end
|
|||||||
function Button:render()
|
function Button:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local text = self.getResolved("text")
|
local text = self.getResolved("text")
|
||||||
text = text:sub(1, self.get("width"))
|
text = text:sub(1, self.getResolved("width"))
|
||||||
local xO, yO = getCenteredPosition(text, self.get("width"), self.get("height"))
|
local xO, yO = getCenteredPosition(text, self.getResolved("width"), self.getResolved("height"))
|
||||||
self:textFg(xO, yO, text, self.getResolved("foreground"))
|
self:textFg(xO, yO, text, self.getResolved("foreground"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -24,18 +24,18 @@ CheckBox.__index = CheckBox
|
|||||||
CheckBox.defineProperty(CheckBox, "checked", {default = false, type = "boolean", canTriggerRender = true})
|
CheckBox.defineProperty(CheckBox, "checked", {default = false, type = "boolean", canTriggerRender = true})
|
||||||
---@property text string empty Text shown when the checkbox is unchecked
|
---@property text string empty Text shown when the checkbox is unchecked
|
||||||
CheckBox.defineProperty(CheckBox, "text", {default = " ", type = "string", canTriggerRender = true, setter=function(self, value)
|
CheckBox.defineProperty(CheckBox, "text", {default = " ", type = "string", canTriggerRender = true, setter=function(self, value)
|
||||||
local checkedText = self.get("checkedText")
|
local checkedText = self.getResolved("checkedText")
|
||||||
local width = math.max(#value, #checkedText)
|
local width = math.max(#value, #checkedText)
|
||||||
if(self.get("autoSize"))then
|
if(self.getResolved("autoSize"))then
|
||||||
self.set("width", width)
|
self.set("width", width)
|
||||||
end
|
end
|
||||||
return value
|
return value
|
||||||
end})
|
end})
|
||||||
---@property checkedText string x Text shown when the checkbox is checked
|
---@property checkedText string x Text shown when the checkbox is checked
|
||||||
CheckBox.defineProperty(CheckBox, "checkedText", {default = "x", type = "string", canTriggerRender = true, setter=function(self, value)
|
CheckBox.defineProperty(CheckBox, "checkedText", {default = "x", type = "string", canTriggerRender = true, setter=function(self, value)
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local width = math.max(#value, #text)
|
local width = math.max(#value, #text)
|
||||||
if(self.get("autoSize"))then
|
if(self.getResolved("autoSize"))then
|
||||||
self.set("width", width)
|
self.set("width", width)
|
||||||
end
|
end
|
||||||
return value
|
return value
|
||||||
@@ -74,7 +74,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function CheckBox:mouse_click(button, x, y)
|
function CheckBox:mouse_click(button, x, y)
|
||||||
if VisualElement.mouse_click(self, button, x, y) then
|
if VisualElement.mouse_click(self, button, x, y) then
|
||||||
self.set("checked", not self.get("checked"))
|
self.set("checked", not self.getResolved("checked"))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
@@ -88,7 +88,7 @@ function CheckBox:render()
|
|||||||
local checked = self.getResolved("checked")
|
local checked = self.getResolved("checked")
|
||||||
local defaultText = self.getResolved("text")
|
local defaultText = self.getResolved("text")
|
||||||
local checkedText = self.getResolved("checkedText")
|
local checkedText = self.getResolved("checkedText")
|
||||||
local text = string.sub(checked and checkedText or defaultText, 1, self.get("width"))
|
local text = string.sub(checked and checkedText or defaultText, 1, self.getResolved("width"))
|
||||||
|
|
||||||
self:textFg(1, 1, text, self.getResolved("foreground"))
|
self:textFg(1, 1, text, self.getResolved("foreground"))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ function Collection:addItem(itemData)
|
|||||||
end
|
end
|
||||||
local entry = CollectionEntry.new(self, itemData, self._entrySchema)
|
local entry = CollectionEntry.new(self, itemData, self._entrySchema)
|
||||||
|
|
||||||
table.insert(self.get("items"), entry)
|
table.insert(self.getResolved("items"), entry)
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
return entry
|
return entry
|
||||||
end
|
end
|
||||||
@@ -67,7 +67,7 @@ end
|
|||||||
--- @return Collection self The Collection instance
|
--- @return Collection self The Collection instance
|
||||||
--- @usage Collection:removeItem(1)
|
--- @usage Collection:removeItem(1)
|
||||||
function Collection:removeItem(index)
|
function Collection:removeItem(index)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
if type(index) == "number" then
|
if type(index) == "number" then
|
||||||
table.remove(items, index)
|
table.remove(items, index)
|
||||||
else
|
else
|
||||||
@@ -98,7 +98,7 @@ end
|
|||||||
--- @usage local selected = Collection:getSelectedItems()
|
--- @usage local selected = Collection:getSelectedItems()
|
||||||
function Collection:getSelectedItems()
|
function Collection:getSelectedItems()
|
||||||
local selected = {}
|
local selected = {}
|
||||||
for i, item in ipairs(self.get("items")) do
|
for i, item in ipairs(self.getResolved("items")) do
|
||||||
if type(item) == "table" and item.selected then
|
if type(item) == "table" and item.selected then
|
||||||
local selectedItem = item
|
local selectedItem = item
|
||||||
selectedItem.index = i
|
selectedItem.index = i
|
||||||
@@ -112,7 +112,7 @@ end
|
|||||||
--- @shortDescription Gets first selected item
|
--- @shortDescription Gets first selected item
|
||||||
--- @return table? selected The first item
|
--- @return table? selected The first item
|
||||||
function Collection:getSelectedItem()
|
function Collection:getSelectedItem()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
for i, item in ipairs(items) do
|
for i, item in ipairs(items) do
|
||||||
if type(item) == "table" and item.selected then
|
if type(item) == "table" and item.selected then
|
||||||
return item
|
return item
|
||||||
@@ -122,7 +122,7 @@ function Collection:getSelectedItem()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Collection:selectItem(index)
|
function Collection:selectItem(index)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
if type(index) == "number" then
|
if type(index) == "number" then
|
||||||
if items[index] and type(items[index]) == "table" then
|
if items[index] and type(items[index]) == "table" then
|
||||||
items[index].selected = true
|
items[index].selected = true
|
||||||
@@ -142,7 +142,7 @@ function Collection:selectItem(index)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Collection:unselectItem(index)
|
function Collection:unselectItem(index)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
if type(index) == "number" then
|
if type(index) == "number" then
|
||||||
if items[index] and type(items[index]) == "table" then
|
if items[index] and type(items[index]) == "table" then
|
||||||
items[index].selected = false
|
items[index].selected = false
|
||||||
@@ -162,7 +162,7 @@ function Collection:unselectItem(index)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Collection:clearItemSelection()
|
function Collection:clearItemSelection()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
for i, item in ipairs(items) do
|
for i, item in ipairs(items) do
|
||||||
item.selected = false
|
item.selected = false
|
||||||
end
|
end
|
||||||
@@ -175,7 +175,7 @@ end
|
|||||||
--- @return number? index The index of the first selected item, or nil if none selected
|
--- @return number? index The index of the first selected item, or nil if none selected
|
||||||
--- @usage local index = Collection:getSelectedIndex()
|
--- @usage local index = Collection:getSelectedIndex()
|
||||||
function Collection:getSelectedIndex()
|
function Collection:getSelectedIndex()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
for i, item in ipairs(items) do
|
for i, item in ipairs(items) do
|
||||||
if type(item) == "table" and item.selected then
|
if type(item) == "table" and item.selected then
|
||||||
return i
|
return i
|
||||||
@@ -188,7 +188,7 @@ end
|
|||||||
--- @shortDescription Selects the next item
|
--- @shortDescription Selects the next item
|
||||||
--- @return Collection self The Collection instance
|
--- @return Collection self The Collection instance
|
||||||
function Collection:selectNext()
|
function Collection:selectNext()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local currentIndex = self:getSelectedIndex()
|
local currentIndex = self:getSelectedIndex()
|
||||||
|
|
||||||
if not currentIndex then
|
if not currentIndex then
|
||||||
@@ -196,7 +196,7 @@ function Collection:selectNext()
|
|||||||
self:selectItem(1)
|
self:selectItem(1)
|
||||||
end
|
end
|
||||||
elseif currentIndex < #items then
|
elseif currentIndex < #items then
|
||||||
if not self.get("multiSelection") then
|
if not self.getResolved("multiSelection") then
|
||||||
self:clearItemSelection()
|
self:clearItemSelection()
|
||||||
end
|
end
|
||||||
self:selectItem(currentIndex + 1)
|
self:selectItem(currentIndex + 1)
|
||||||
@@ -210,7 +210,7 @@ end
|
|||||||
--- @shortDescription Selects the previous item
|
--- @shortDescription Selects the previous item
|
||||||
--- @return Collection self The Collection instance
|
--- @return Collection self The Collection instance
|
||||||
function Collection:selectPrevious()
|
function Collection:selectPrevious()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local currentIndex = self:getSelectedIndex()
|
local currentIndex = self:getSelectedIndex()
|
||||||
|
|
||||||
if not currentIndex then
|
if not currentIndex then
|
||||||
@@ -218,7 +218,7 @@ function Collection:selectPrevious()
|
|||||||
self:selectItem(#items)
|
self:selectItem(#items)
|
||||||
end
|
end
|
||||||
elseif currentIndex > 1 then
|
elseif currentIndex > 1 then
|
||||||
if not self.get("multiSelection") then
|
if not self.getResolved("multiSelection") then
|
||||||
self:clearItemSelection()
|
self:clearItemSelection()
|
||||||
end
|
end
|
||||||
self:selectItem(currentIndex - 1)
|
self:selectItem(currentIndex - 1)
|
||||||
|
|||||||
@@ -78,10 +78,10 @@ end
|
|||||||
--- @shortDescription Filters items for auto-complete
|
--- @shortDescription Filters items for auto-complete
|
||||||
--- @private
|
--- @private
|
||||||
function ComboBox:getFilteredItems()
|
function ComboBox:getFilteredItems()
|
||||||
local allItems = self.get("items") or {}
|
local allItems = self.getResolved("items") or {}
|
||||||
local currentText = self.get("text"):lower()
|
local currentText = self.getResolved("text"):lower()
|
||||||
|
|
||||||
if not self.get("autoComplete") or #currentText == 0 then
|
if not self.getResolved("autoComplete") or #currentText == 0 then
|
||||||
return allItems
|
return allItems
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -106,15 +106,15 @@ end
|
|||||||
--- @shortDescription Updates dropdown with filtered items
|
--- @shortDescription Updates dropdown with filtered items
|
||||||
--- @private
|
--- @private
|
||||||
function ComboBox:updateFilteredDropdown()
|
function ComboBox:updateFilteredDropdown()
|
||||||
if not self.get("autoComplete") then return end
|
if not self.getResolved("autoComplete") then return end
|
||||||
|
|
||||||
local filteredItems = self:getFilteredItems()
|
local filteredItems = self:getFilteredItems()
|
||||||
local shouldOpen = #filteredItems > 0 and #self.get("text") > 0
|
local shouldOpen = #filteredItems > 0 and #self.getResolved("text") > 0
|
||||||
|
|
||||||
if shouldOpen then
|
if shouldOpen then
|
||||||
self:setState("opened")
|
self:setState("opened")
|
||||||
self.set("manuallyOpened", false)
|
self.set("manuallyOpened", false)
|
||||||
local dropdownHeight = self.get("dropdownHeight") or 5
|
local dropdownHeight = self.getResolved("dropdownHeight") or 5
|
||||||
local actualHeight = math.min(dropdownHeight, #filteredItems)
|
local actualHeight = math.min(dropdownHeight, #filteredItems)
|
||||||
self.set("height", 1 + actualHeight)
|
self.set("height", 1 + actualHeight)
|
||||||
else
|
else
|
||||||
@@ -128,15 +128,15 @@ end
|
|||||||
--- @shortDescription Updates the viewport
|
--- @shortDescription Updates the viewport
|
||||||
--- @private
|
--- @private
|
||||||
function ComboBox:updateViewport()
|
function ComboBox:updateViewport()
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local cursorPos = self.get("cursorPos")
|
local cursorPos = self.getResolved("cursorPos")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local dropSymbol = self.get("dropSymbol")
|
local dropSymbol = self.getResolved("dropSymbol")
|
||||||
|
|
||||||
local textWidth = width - #dropSymbol
|
local textWidth = width - #dropSymbol
|
||||||
if textWidth < 1 then textWidth = 1 end
|
if textWidth < 1 then textWidth = 1 end
|
||||||
|
|
||||||
local viewOffset = self.get("viewOffset")
|
local viewOffset = self.getResolved("viewOffset")
|
||||||
|
|
||||||
if cursorPos - viewOffset > textWidth then
|
if cursorPos - viewOffset > textWidth then
|
||||||
viewOffset = cursorPos - textWidth
|
viewOffset = cursorPos - textWidth
|
||||||
@@ -151,18 +151,18 @@ end
|
|||||||
--- @shortDescription Handles character input
|
--- @shortDescription Handles character input
|
||||||
--- @param char string The character that was typed
|
--- @param char string The character that was typed
|
||||||
function ComboBox:char(char)
|
function ComboBox:char(char)
|
||||||
if not self.get("editable") then return end
|
if not self.getResolved("editable") then return end
|
||||||
if not self:hasState("focused") then return end
|
if not self:hasState("focused") then return end
|
||||||
|
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local cursorPos = self.get("cursorPos")
|
local cursorPos = self.getResolved("cursorPos")
|
||||||
|
|
||||||
local newText = text:sub(1, cursorPos - 1) .. char .. text:sub(cursorPos)
|
local newText = text:sub(1, cursorPos - 1) .. char .. text:sub(cursorPos)
|
||||||
self.set("text", newText)
|
self.set("text", newText)
|
||||||
self.set("cursorPos", cursorPos + 1)
|
self.set("cursorPos", cursorPos + 1)
|
||||||
self:updateViewport()
|
self:updateViewport()
|
||||||
|
|
||||||
if self.get("autoComplete") then
|
if self.getResolved("autoComplete") then
|
||||||
self:updateFilteredDropdown()
|
self:updateFilteredDropdown()
|
||||||
else
|
else
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
@@ -174,11 +174,11 @@ end
|
|||||||
--- @param key number The key code that was pressed
|
--- @param key number The key code that was pressed
|
||||||
--- @param held boolean Whether the key is being held
|
--- @param held boolean Whether the key is being held
|
||||||
function ComboBox:key(key, held)
|
function ComboBox:key(key, held)
|
||||||
if not self.get("editable") then return end
|
if not self.getResolved("editable") then return end
|
||||||
if not self:hasState("focused") then return end
|
if not self:hasState("focused") then return end
|
||||||
|
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local cursorPos = self.get("cursorPos")
|
local cursorPos = self.getResolved("cursorPos")
|
||||||
|
|
||||||
if key == keys.left then
|
if key == keys.left then
|
||||||
self.set("cursorPos", math.max(1, cursorPos - 1))
|
self.set("cursorPos", math.max(1, cursorPos - 1))
|
||||||
@@ -193,7 +193,7 @@ function ComboBox:key(key, held)
|
|||||||
self.set("cursorPos", cursorPos - 1)
|
self.set("cursorPos", cursorPos - 1)
|
||||||
self:updateViewport()
|
self:updateViewport()
|
||||||
|
|
||||||
if self.get("autoComplete") then
|
if self.getResolved("autoComplete") then
|
||||||
self:updateFilteredDropdown()
|
self:updateFilteredDropdown()
|
||||||
else
|
else
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
@@ -205,7 +205,7 @@ function ComboBox:key(key, held)
|
|||||||
self.set("text", newText)
|
self.set("text", newText)
|
||||||
self:updateViewport()
|
self:updateViewport()
|
||||||
|
|
||||||
if self.get("autoComplete") then
|
if self.getResolved("autoComplete") then
|
||||||
self:updateFilteredDropdown()
|
self:updateFilteredDropdown()
|
||||||
else
|
else
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
@@ -238,8 +238,8 @@ function ComboBox:mouse_click(button, x, y)
|
|||||||
if not VisualElement.mouse_click(self, button, x, y) then return false end
|
if not VisualElement.mouse_click(self, button, x, y) then return false end
|
||||||
|
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local dropSymbol = self.get("dropSymbol")
|
local dropSymbol = self.getResolved("dropSymbol")
|
||||||
local isOpen = self:hasState("opened")
|
local isOpen = self:hasState("opened")
|
||||||
|
|
||||||
if relY == 1 then
|
if relY == 1 then
|
||||||
@@ -250,8 +250,8 @@ function ComboBox:mouse_click(button, x, y)
|
|||||||
self.set("manuallyOpened", false)
|
self.set("manuallyOpened", false)
|
||||||
else
|
else
|
||||||
self:setState("opened")
|
self:setState("opened")
|
||||||
local allItems = self.get("items") or {}
|
local allItems = self.getResolved("items") or {}
|
||||||
local dropdownHeight = self.get("dropdownHeight") or 5
|
local dropdownHeight = self.getResolved("dropdownHeight") or 5
|
||||||
local actualHeight = math.min(dropdownHeight, #allItems)
|
local actualHeight = math.min(dropdownHeight, #allItems)
|
||||||
self.set("height", 1 + actualHeight)
|
self.set("height", 1 + actualHeight)
|
||||||
self.set("manuallyOpened", true)
|
self.set("manuallyOpened", true)
|
||||||
@@ -260,17 +260,17 @@ function ComboBox:mouse_click(button, x, y)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if relX <= width - #dropSymbol and self.get("editable") then
|
if relX <= width - #dropSymbol and self.getResolved("editable") then
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local viewOffset = self.get("viewOffset")
|
local viewOffset = self.getResolved("viewOffset")
|
||||||
local maxPos = #text + 1
|
local maxPos = #text + 1
|
||||||
local targetPos = math.min(maxPos, viewOffset + relX)
|
local targetPos = math.min(maxPos, viewOffset + relX)
|
||||||
|
|
||||||
self.set("cursorPos", targetPos)
|
self.set("cursorPos", targetPos)
|
||||||
if not isOpen then
|
if not isOpen then
|
||||||
self:setState("opened")
|
self:setState("opened")
|
||||||
local allItems = self.get("items") or {}
|
local allItems = self.getResolved("items") or {}
|
||||||
local dropdownHeight = self.get("dropdownHeight") or 5
|
local dropdownHeight = self.getResolved("dropdownHeight") or 5
|
||||||
local actualHeight = math.min(dropdownHeight, #allItems)
|
local actualHeight = math.min(dropdownHeight, #allItems)
|
||||||
self.set("height", 1 + actualHeight)
|
self.set("height", 1 + actualHeight)
|
||||||
self.set("manuallyOpened", true)
|
self.set("manuallyOpened", true)
|
||||||
@@ -299,14 +299,14 @@ function ComboBox:mouse_up(button, x, y)
|
|||||||
if self:hasState("opened") then
|
if self:hasState("opened") then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
|
|
||||||
if relY > 1 and self.get("selectable") and not self._scrollBarDragging then
|
if relY > 1 and self.getResolved("selectable") and not self._scrollBarDragging then
|
||||||
local itemIndex = (relY - 1) + self.get("offset")
|
local itemIndex = (relY - 1) + self.getResolved("offset")
|
||||||
|
|
||||||
local items
|
local items
|
||||||
if self.get("autoComplete") and not self.get("manuallyOpened") then
|
if self.getResolved("autoComplete") and not self.getResolved("manuallyOpened") then
|
||||||
items = self:getFilteredItems()
|
items = self:getFilteredItems()
|
||||||
else
|
else
|
||||||
items = self.get("items")
|
items = self.getResolved("items")
|
||||||
end
|
end
|
||||||
|
|
||||||
if itemIndex <= #items then
|
if itemIndex <= #items then
|
||||||
@@ -316,8 +316,8 @@ function ComboBox:mouse_up(button, x, y)
|
|||||||
items[itemIndex] = item
|
items[itemIndex] = item
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("multiSelection") then
|
if not self.getResolved("multiSelection") then
|
||||||
for _, otherItem in ipairs(self.get("items")) do
|
for _, otherItem in ipairs(self.getResolved("items")) do
|
||||||
if type(otherItem) == "table" then
|
if type(otherItem) == "table" then
|
||||||
otherItem.selected = false
|
otherItem.selected = false
|
||||||
end
|
end
|
||||||
@@ -357,12 +357,12 @@ end
|
|||||||
function ComboBox:render()
|
function ComboBox:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local dropSymbol = self.get("dropSymbol")
|
local dropSymbol = self.getResolved("dropSymbol")
|
||||||
local isFocused = self:hasState("focused")
|
local isFocused = self:hasState("focused")
|
||||||
local isOpen = self:hasState("opened")
|
local isOpen = self:hasState("opened")
|
||||||
local viewOffset = self.get("viewOffset")
|
local viewOffset = self.getResolved("viewOffset")
|
||||||
local selectedText = self.getResolved("selectedText")
|
local selectedText = self.getResolved("selectedText")
|
||||||
local bg = self.getResolved("background")
|
local bg = self.getResolved("background")
|
||||||
local fg = self.getResolved("foreground")
|
local fg = self.getResolved("foreground")
|
||||||
@@ -387,8 +387,8 @@ function ComboBox:render()
|
|||||||
string.rep(tHex[fg], width),
|
string.rep(tHex[fg], width),
|
||||||
string.rep(tHex[bg], width))
|
string.rep(tHex[bg], width))
|
||||||
|
|
||||||
if isFocused and self.get("editable") then
|
if isFocused and self.getResolved("editable") then
|
||||||
local cursorPos = self.get("cursorPos")
|
local cursorPos = self.getResolved("cursorPos")
|
||||||
local cursorX = cursorPos - viewOffset
|
local cursorX = cursorPos - viewOffset
|
||||||
if cursorX >= 1 and cursorX <= textWidth then
|
if cursorX >= 1 and cursorX <= textWidth then
|
||||||
self:setCursor(cursorX, 1, true, fg)
|
self:setCursor(cursorX, 1, true, fg)
|
||||||
@@ -396,14 +396,14 @@ function ComboBox:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if isOpen then
|
if isOpen then
|
||||||
local actualHeight = self.get("height")
|
local actualHeight = self.getResolved("height")
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
|
|
||||||
if self.get("autoComplete") and not self.get("manuallyOpened") then
|
if self.getResolved("autoComplete") and not self.getResolved("manuallyOpened") then
|
||||||
items = self:getFilteredItems()
|
items = self:getFilteredItems()
|
||||||
end
|
end
|
||||||
|
|
||||||
local dropdownHeight = math.min(self.get("dropdownHeight"), #items)
|
local dropdownHeight = math.min(self.getResolved("dropdownHeight"), #items)
|
||||||
|
|
||||||
local originalItems = self._values.items
|
local originalItems = self._values.items
|
||||||
self._values.items = items
|
self._values.items = items
|
||||||
@@ -418,8 +418,8 @@ function ComboBox:render()
|
|||||||
string.rep(tHex[fg], width),
|
string.rep(tHex[fg], width),
|
||||||
string.rep(tHex[bg], width))
|
string.rep(tHex[bg], width))
|
||||||
|
|
||||||
if isFocused and self.get("editable") then
|
if isFocused and self.getResolved("editable") then
|
||||||
local cursorPos = self.get("cursorPos")
|
local cursorPos = self.getResolved("cursorPos")
|
||||||
local cursorX = cursorPos - viewOffset
|
local cursorX = cursorPos - viewOffset
|
||||||
if cursorX >= 1 and cursorX <= textWidth then
|
if cursorX >= 1 and cursorX <= textWidth then
|
||||||
self:setCursor(cursorX, 1, true, fg)
|
self:setCursor(cursorX, 1, true, fg)
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ function Container:isChildVisible(child)
|
|||||||
if not child:isType("VisualElement") then return false end
|
if not child:isType("VisualElement") then return false end
|
||||||
if(child.get("visible") == false)then return false end
|
if(child.get("visible") == false)then return false end
|
||||||
if(child._destroyed)then return false end
|
if(child._destroyed)then return false end
|
||||||
local containerW, containerH = self.get("width"), self.get("height")
|
local containerW, containerH = self.getResolved("width"), self.getResolved("height")
|
||||||
local offsetX, offsetY = self.get("offsetX"), self.get("offsetY")
|
local offsetX, offsetY = self.getResolved("offsetX"), self.getResolved("offsetY")
|
||||||
|
|
||||||
local childX, childY = child.get("x"), child.get("y")
|
local childX, childY = child.get("x"), child.get("y")
|
||||||
local childW, childH = child.get("width"), child.get("height")
|
local childW, childH = child.get("width"), child.get("height")
|
||||||
@@ -353,7 +353,7 @@ local function convertMousePosition(self, event, ...)
|
|||||||
local args = {...}
|
local args = {...}
|
||||||
if event and event:find("mouse_") then
|
if event and event:find("mouse_") then
|
||||||
local button, absX, absY = ...
|
local button, absX, absY = ...
|
||||||
local xOffset, yOffset = self.get("offsetX"), self.get("offsetY")
|
local xOffset, yOffset = self.getResolved("offsetX"), self.getResolved("offsetY")
|
||||||
local relX, relY = self:getRelativePosition(absX + xOffset, absY + yOffset)
|
local relX, relY = self:getRelativePosition(absX + xOffset, absY + yOffset)
|
||||||
args = {button, relX, relY}
|
args = {button, relX, relY}
|
||||||
end
|
end
|
||||||
@@ -368,13 +368,13 @@ end
|
|||||||
--- @return boolean handled Whether the event was handled
|
--- @return boolean handled Whether the event was handled
|
||||||
--- @return table? child The child that handled the event
|
--- @return table? child The child that handled the event
|
||||||
function Container:callChildrenEvent(visibleOnly, event, ...)
|
function Container:callChildrenEvent(visibleOnly, event, ...)
|
||||||
if visibleOnly and not self.get("childrenEventsSorted") then
|
if visibleOnly and not self.getResolved("childrenEventsSorted") then
|
||||||
for evt in pairs(self._values.childrenEvents) do
|
for evt in pairs(self._values.childrenEvents) do
|
||||||
self:sortChildrenEvents(evt)
|
self:sortChildrenEvents(evt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local children = visibleOnly and self.get("visibleChildrenEvents") or self.get("childrenEvents")
|
local children = visibleOnly and self.getResolved("visibleChildrenEvents") or self.getResolved("childrenEvents")
|
||||||
if children[event] then
|
if children[event] then
|
||||||
local events = children[event]
|
local events = children[event]
|
||||||
for i = #events, 1, -1 do
|
for i = #events, 1, -1 do
|
||||||
@@ -510,8 +510,8 @@ end
|
|||||||
--- @return boolean handled Whether the event was handled
|
--- @return boolean handled Whether the event was handled
|
||||||
--- @protected
|
--- @protected
|
||||||
function Container:key(key)
|
function Container:key(key)
|
||||||
if self.get("focusedChild") then
|
if self.getResolved("focusedChild") then
|
||||||
return self.get("focusedChild"):dispatchEvent("key", key)
|
return self.getResolved("focusedChild"):dispatchEvent("key", key)
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -521,8 +521,8 @@ end
|
|||||||
--- @return boolean handled Whether the event was handled
|
--- @return boolean handled Whether the event was handled
|
||||||
--- @protected
|
--- @protected
|
||||||
function Container:char(char)
|
function Container:char(char)
|
||||||
if self.get("focusedChild") then
|
if self.getResolved("focusedChild") then
|
||||||
return self.get("focusedChild"):dispatchEvent("char", char)
|
return self.getResolved("focusedChild"):dispatchEvent("char", char)
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -532,8 +532,8 @@ end
|
|||||||
--- @return boolean handled Whether the event was handled
|
--- @return boolean handled Whether the event was handled
|
||||||
--- @protected
|
--- @protected
|
||||||
function Container:key_up(key)
|
function Container:key_up(key)
|
||||||
if self.get("focusedChild") then
|
if self.getResolved("focusedChild") then
|
||||||
return self.get("focusedChild"):dispatchEvent("key_up", key)
|
return self.getResolved("focusedChild"):dispatchEvent("key_up", key)
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -549,7 +549,7 @@ end
|
|||||||
--- @return Container self The container instance
|
--- @return Container self The container instance
|
||||||
--- @protected
|
--- @protected
|
||||||
function Container:multiBlit(x, y, width, height, text, fg, bg)
|
function Container:multiBlit(x, y, width, height, text, fg, bg)
|
||||||
local w, h = self.get("width"), self.get("height")
|
local w, h = self.getResolved("width"), self.getResolved("height")
|
||||||
|
|
||||||
width = x < 1 and math.min(width + x - 1, w) or math.min(width, math.max(0, w - x + 1))
|
width = x < 1 and math.min(width + x - 1, w) or math.min(width, math.max(0, w - x + 1))
|
||||||
height = y < 1 and math.min(height + y - 1, h) or math.min(height, math.max(0, h - y + 1))
|
height = y < 1 and math.min(height + y - 1, h) or math.min(height, math.max(0, h - y + 1))
|
||||||
@@ -568,7 +568,7 @@ end
|
|||||||
--- @return Container self The container instance
|
--- @return Container self The container instance
|
||||||
--- @protected
|
--- @protected
|
||||||
function Container:textFg(x, y, text, fg)
|
function Container:textFg(x, y, text, fg)
|
||||||
local w, h = self.get("width"), self.get("height")
|
local w, h = self.getResolved("width"), self.getResolved("height")
|
||||||
|
|
||||||
if y < 1 or y > h then return self end
|
if y < 1 or y > h then return self end
|
||||||
|
|
||||||
@@ -589,7 +589,7 @@ end
|
|||||||
--- @return Container self The container instance
|
--- @return Container self The container instance
|
||||||
--- @protected
|
--- @protected
|
||||||
function Container:textBg(x, y, text, bg)
|
function Container:textBg(x, y, text, bg)
|
||||||
local w, h = self.get("width"), self.get("height")
|
local w, h = self.getResolved("width"), self.getResolved("height")
|
||||||
|
|
||||||
if y < 1 or y > h then return self end
|
if y < 1 or y > h then return self end
|
||||||
|
|
||||||
@@ -603,7 +603,7 @@ function Container:textBg(x, y, text, bg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Container:drawText(x, y, text)
|
function Container:drawText(x, y, text)
|
||||||
local w, h = self.get("width"), self.get("height")
|
local w, h = self.getResolved("width"), self.getResolved("height")
|
||||||
|
|
||||||
if y < 1 or y > h then return self end
|
if y < 1 or y > h then return self end
|
||||||
|
|
||||||
@@ -617,7 +617,7 @@ function Container:drawText(x, y, text)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Container:drawFg(x, y, fg)
|
function Container:drawFg(x, y, fg)
|
||||||
local w, h = self.get("width"), self.get("height")
|
local w, h = self.getResolved("width"), self.getResolved("height")
|
||||||
|
|
||||||
if y < 1 or y > h then return self end
|
if y < 1 or y > h then return self end
|
||||||
|
|
||||||
@@ -630,7 +630,7 @@ function Container:drawFg(x, y, fg)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Container:drawBg(x, y, bg)
|
function Container:drawBg(x, y, bg)
|
||||||
local w, h = self.get("width"), self.get("height")
|
local w, h = self.getResolved("width"), self.getResolved("height")
|
||||||
|
|
||||||
if y < 1 or y > h then return self end
|
if y < 1 or y > h then return self end
|
||||||
|
|
||||||
@@ -651,7 +651,7 @@ end
|
|||||||
--- @return Container self The container instance
|
--- @return Container self The container instance
|
||||||
--- @protected
|
--- @protected
|
||||||
function Container:blit(x, y, text, fg, bg)
|
function Container:blit(x, y, text, fg, bg)
|
||||||
local w, h = self.get("width"), self.get("height")
|
local w, h = self.getResolved("width"), self.getResolved("height")
|
||||||
|
|
||||||
if y < 1 or y > h then return self end
|
if y < 1 or y > h then return self end
|
||||||
|
|
||||||
@@ -674,15 +674,15 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Container:render()
|
function Container:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
if not self.get("childrenSorted")then
|
if not self.getResolved("childrenSorted")then
|
||||||
self:sortChildren()
|
self:sortChildren()
|
||||||
end
|
end
|
||||||
if not self.get("childrenEventsSorted")then
|
if not self.getResolved("childrenEventsSorted")then
|
||||||
for event in pairs(self._values.childrenEvents) do
|
for event in pairs(self._values.childrenEvents) do
|
||||||
self:sortChildrenEvents(event)
|
self:sortChildrenEvents(event)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for _, child in ipairs(self.get("visibleChildren")) do
|
for _, child in ipairs(self.getResolved("visibleChildren")) do
|
||||||
if child == self then
|
if child == self then
|
||||||
errorManager.error("CIRCULAR REFERENCE DETECTED!")
|
errorManager.error("CIRCULAR REFERENCE DETECTED!")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ end
|
|||||||
--- @shortDescription Calculates menu size based on items
|
--- @shortDescription Calculates menu size based on items
|
||||||
--- @private
|
--- @private
|
||||||
function ContextMenu:calculateSize()
|
function ContextMenu:calculateSize()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local itemHeight = self.get("itemHeight")
|
local itemHeight = self.getResolved("itemHeight")
|
||||||
|
|
||||||
if #items == 0 then
|
if #items == 0 then
|
||||||
self.set("width", 10)
|
self.set("width", 10)
|
||||||
@@ -195,7 +195,7 @@ function ContextMenu:close()
|
|||||||
self.set("isOpen", false)
|
self.set("isOpen", false)
|
||||||
self.set("visible", false)
|
self.set("visible", false)
|
||||||
|
|
||||||
local openSubmenu = self.get("openSubmenu")
|
local openSubmenu = self.getResolved("openSubmenu")
|
||||||
if openSubmenu and openSubmenu.menu then
|
if openSubmenu and openSubmenu.menu then
|
||||||
openSubmenu.menu:close()
|
openSubmenu.menu:close()
|
||||||
end
|
end
|
||||||
@@ -225,8 +225,8 @@ end
|
|||||||
--- @return table? item Item data or nil
|
--- @return table? item Item data or nil
|
||||||
--- @private
|
--- @private
|
||||||
function ContextMenu:getItemAt(y)
|
function ContextMenu:getItemAt(y)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local itemHeight = self.get("itemHeight")
|
local itemHeight = self.getResolved("itemHeight")
|
||||||
|
|
||||||
local index = math.floor((y - 1) / itemHeight) + 1
|
local index = math.floor((y - 1) / itemHeight) + 1
|
||||||
|
|
||||||
@@ -243,20 +243,20 @@ function ContextMenu:createSubmenu(submenuItems, parentItem)
|
|||||||
local submenu = self.parent:addContextMenu()
|
local submenu = self.parent:addContextMenu()
|
||||||
submenu:setItems(submenuItems)
|
submenu:setItems(submenuItems)
|
||||||
|
|
||||||
submenu.set("background", self.get("background"))
|
submenu.set("background", self.getResolved("background"))
|
||||||
submenu.set("foreground", self.get("foreground"))
|
submenu.set("foreground", self.getResolved("foreground"))
|
||||||
|
|
||||||
submenu.parentMenu = self
|
submenu.parentMenu = self
|
||||||
|
|
||||||
local parentX = self.get("x")
|
local parentX = self.getResolved("x")
|
||||||
local parentY = self.get("y")
|
local parentY = self.getResolved("y")
|
||||||
local parentWidth = self.get("width")
|
local parentWidth = self.getResolved("width")
|
||||||
local itemHeight = self.get("itemHeight")
|
local itemHeight = self.getResolved("itemHeight")
|
||||||
local itemIndex = parentItem._index or 1
|
local itemIndex = parentItem._index or 1
|
||||||
|
|
||||||
submenu.set("x", parentX + parentWidth)
|
submenu.set("x", parentX + parentWidth)
|
||||||
submenu.set("y", parentY + (itemIndex - 1) * itemHeight)
|
submenu.set("y", parentY + (itemIndex - 1) * itemHeight)
|
||||||
submenu.set("z", self.get("z") + 1)
|
submenu.set("z", self.getResolved("z") + 1)
|
||||||
|
|
||||||
return submenu
|
return submenu
|
||||||
end
|
end
|
||||||
@@ -278,7 +278,7 @@ function ContextMenu:mouse_click(button, x, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if item.submenu then
|
if item.submenu then
|
||||||
local openSubmenu = self.get("openSubmenu")
|
local openSubmenu = self.getResolved("openSubmenu")
|
||||||
if openSubmenu and openSubmenu.index == index then
|
if openSubmenu and openSubmenu.index == index then
|
||||||
openSubmenu.menu:close()
|
openSubmenu.menu:close()
|
||||||
self.set("openSubmenu", nil)
|
self.set("openSubmenu", nil)
|
||||||
@@ -312,12 +312,12 @@ end
|
|||||||
--- @shortDescription Renders the ContextMenu
|
--- @shortDescription Renders the ContextMenu
|
||||||
--- @protected
|
--- @protected
|
||||||
function ContextMenu:render()
|
function ContextMenu:render()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local itemHeight = self.get("itemHeight")
|
local itemHeight = self.getResolved("itemHeight")
|
||||||
local menuBg = self.get("background")
|
local menuBg = self.getResolved("background")
|
||||||
local menuFg = self.get("foreground")
|
local menuFg = self.getResolved("foreground")
|
||||||
|
|
||||||
for i, item in ipairs(items) do
|
for i, item in ipairs(items) do
|
||||||
local y = (i - 1) * itemHeight + 1
|
local y = (i - 1) * itemHeight + 1
|
||||||
@@ -342,16 +342,16 @@ function ContextMenu:render()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("childrenSorted") then
|
if not self.getResolved("childrenSorted") then
|
||||||
self:sortChildren()
|
self:sortChildren()
|
||||||
end
|
end
|
||||||
if not self.get("childrenEventsSorted") then
|
if not self.getResolved("childrenEventsSorted") then
|
||||||
for eventName in pairs(self._values.childrenEvents or {}) do
|
for eventName in pairs(self._values.childrenEvents or {}) do
|
||||||
self:sortChildrenEvents(eventName)
|
self:sortChildrenEvents(eventName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, child in ipairs(self.get("visibleChildren") or {}) do
|
for _, child in ipairs(self.getResolved("visibleChildren") or {}) do
|
||||||
if child == self then
|
if child == self then
|
||||||
error("CIRCULAR REFERENCE DETECTED!")
|
error("CIRCULAR REFERENCE DETECTED!")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ function Dialog:show()
|
|||||||
self:center()
|
self:center()
|
||||||
self.set("visible", true)
|
self.set("visible", true)
|
||||||
-- Auto-focus when modal
|
-- Auto-focus when modal
|
||||||
if self.get("modal") then
|
if self.getResolved("modal") then
|
||||||
self:setFocused(true)
|
self:setFocused(true)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -91,22 +91,22 @@ function Dialog:alert(title, message, callback)
|
|||||||
self:addLabel({
|
self:addLabel({
|
||||||
text = message,
|
text = message,
|
||||||
x = 2, y = 3,
|
x = 2, y = 3,
|
||||||
width = self.get("width") - 3,
|
width = self.getResolved("width") - 3,
|
||||||
height = 3,
|
height = 3,
|
||||||
foreground = colors.white
|
foreground = colors.white
|
||||||
})
|
})
|
||||||
|
|
||||||
local btnWidth = 10
|
local btnWidth = 10
|
||||||
local btnX = math.floor((self.get("width") - btnWidth) / 2) + 1
|
local btnX = math.floor((self.getResolved("width") - btnWidth) / 2) + 1
|
||||||
|
|
||||||
self:addButton({
|
self:addButton({
|
||||||
text = "OK",
|
text = "OK",
|
||||||
x = btnX,
|
x = btnX,
|
||||||
y = self.get("height") - 2,
|
y = self.getResolved("height") - 2,
|
||||||
width = btnWidth,
|
width = btnWidth,
|
||||||
height = 1,
|
height = 1,
|
||||||
background = self.get("primaryColor"),
|
background = self.getResolved("primaryColor"),
|
||||||
foreground = self.get("buttonForeground")
|
foreground = self.getResolved("buttonForeground")
|
||||||
}):onClick(function()
|
}):onClick(function()
|
||||||
if callback then callback() end
|
if callback then callback() end
|
||||||
self:close()
|
self:close()
|
||||||
@@ -129,7 +129,7 @@ function Dialog:confirm(title, message, callback)
|
|||||||
self:addLabel({
|
self:addLabel({
|
||||||
text = message,
|
text = message,
|
||||||
x = 2, y = 3,
|
x = 2, y = 3,
|
||||||
width = self.get("width") - 3,
|
width = self.getResolved("width") - 3,
|
||||||
height = 3,
|
height = 3,
|
||||||
foreground = colors.white
|
foreground = colors.white
|
||||||
})
|
})
|
||||||
@@ -137,16 +137,16 @@ function Dialog:confirm(title, message, callback)
|
|||||||
local btnWidth = 10
|
local btnWidth = 10
|
||||||
local spacing = 2
|
local spacing = 2
|
||||||
local totalWidth = btnWidth * 2 + spacing
|
local totalWidth = btnWidth * 2 + spacing
|
||||||
local startX = math.floor((self.get("width") - totalWidth) / 2) + 1
|
local startX = math.floor((self.getResolved("width") - totalWidth) / 2) + 1
|
||||||
|
|
||||||
self:addButton({
|
self:addButton({
|
||||||
text = "Cancel",
|
text = "Cancel",
|
||||||
x = startX,
|
x = startX,
|
||||||
y = self.get("height") - 2,
|
y = self.getResolved("height") - 2,
|
||||||
width = btnWidth,
|
width = btnWidth,
|
||||||
height = 1,
|
height = 1,
|
||||||
background = self.get("secondaryColor"),
|
background = self.getResolved("secondaryColor"),
|
||||||
foreground = self.get("buttonForeground")
|
foreground = self.getResolved("buttonForeground")
|
||||||
}):onClick(function()
|
}):onClick(function()
|
||||||
if callback then callback(false) end
|
if callback then callback(false) end
|
||||||
self:close()
|
self:close()
|
||||||
@@ -155,11 +155,11 @@ function Dialog:confirm(title, message, callback)
|
|||||||
self:addButton({
|
self:addButton({
|
||||||
text = "OK",
|
text = "OK",
|
||||||
x = startX + btnWidth + spacing,
|
x = startX + btnWidth + spacing,
|
||||||
y = self.get("height") - 2,
|
y = self.getResolved("height") - 2,
|
||||||
width = btnWidth,
|
width = btnWidth,
|
||||||
height = 1,
|
height = 1,
|
||||||
background = self.get("primaryColor"),
|
background = self.getResolved("primaryColor"),
|
||||||
foreground = self.get("buttonForeground")
|
foreground = self.getResolved("buttonForeground")
|
||||||
}):onClick(function()
|
}):onClick(function()
|
||||||
if callback then callback(true) end
|
if callback then callback(true) end
|
||||||
self:close()
|
self:close()
|
||||||
@@ -188,7 +188,7 @@ function Dialog:prompt(title, message, default, callback)
|
|||||||
|
|
||||||
local input = self:addInput({
|
local input = self:addInput({
|
||||||
x = 2, y = 5,
|
x = 2, y = 5,
|
||||||
width = self.get("width") - 3,
|
width = self.getResolved("width") - 3,
|
||||||
height = 1,
|
height = 1,
|
||||||
defaultText = default or "",
|
defaultText = default or "",
|
||||||
background = colors.white,
|
background = colors.white,
|
||||||
@@ -198,16 +198,16 @@ function Dialog:prompt(title, message, default, callback)
|
|||||||
local btnWidth = 10
|
local btnWidth = 10
|
||||||
local spacing = 2
|
local spacing = 2
|
||||||
local totalWidth = btnWidth * 2 + spacing
|
local totalWidth = btnWidth * 2 + spacing
|
||||||
local startX = math.floor((self.get("width") - totalWidth) / 2) + 1
|
local startX = math.floor((self.getResolved("width") - totalWidth) / 2) + 1
|
||||||
|
|
||||||
self:addButton({
|
self:addButton({
|
||||||
text = "Cancel",
|
text = "Cancel",
|
||||||
x = startX,
|
x = startX,
|
||||||
y = self.get("height") - 2,
|
y = self.getResolved("height") - 2,
|
||||||
width = btnWidth,
|
width = btnWidth,
|
||||||
height = 1,
|
height = 1,
|
||||||
background = self.get("secondaryColor"),
|
background = self.getResolved("secondaryColor"),
|
||||||
foreground = self.get("buttonForeground")
|
foreground = self.getResolved("buttonForeground")
|
||||||
}):onClick(function()
|
}):onClick(function()
|
||||||
if callback then callback(nil) end
|
if callback then callback(nil) end
|
||||||
self:close()
|
self:close()
|
||||||
@@ -216,11 +216,11 @@ function Dialog:prompt(title, message, default, callback)
|
|||||||
self:addButton({
|
self:addButton({
|
||||||
text = "OK",
|
text = "OK",
|
||||||
x = startX + btnWidth + spacing,
|
x = startX + btnWidth + spacing,
|
||||||
y = self.get("height") - 2,
|
y = self.getResolved("height") - 2,
|
||||||
width = btnWidth,
|
width = btnWidth,
|
||||||
height = 1,
|
height = 1,
|
||||||
background = self.get("primaryColor"),
|
background = self.getResolved("primaryColor"),
|
||||||
foreground = self.get("buttonForeground")
|
foreground = self.getResolved("buttonForeground")
|
||||||
}):onClick(function()
|
}):onClick(function()
|
||||||
if callback then callback(input.get("text") or "") end
|
if callback then callback(input.get("text") or "") end
|
||||||
self:close()
|
self:close()
|
||||||
@@ -235,9 +235,9 @@ end
|
|||||||
function Dialog:render()
|
function Dialog:render()
|
||||||
Frame.render(self)
|
Frame.render(self)
|
||||||
|
|
||||||
local title = self.get("title")
|
local title = self.getResolved("title")
|
||||||
if title ~= "" then
|
if title ~= "" then
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local titleText = title:sub(1, width - 4)
|
local titleText = title:sub(1, width - 4)
|
||||||
self:textFg(2, 2, titleText, colors.white)
|
self:textFg(2, 2, titleText, colors.white)
|
||||||
end
|
end
|
||||||
@@ -247,7 +247,7 @@ end
|
|||||||
--- @shortDescription Handles mouse click events
|
--- @shortDescription Handles mouse click events
|
||||||
--- @protected
|
--- @protected
|
||||||
function Dialog:mouse_click(button, x, y)
|
function Dialog:mouse_click(button, x, y)
|
||||||
if self.get("modal") then
|
if self.getResolved("modal") then
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
return Frame.mouse_click(self, button, x, y)
|
return Frame.mouse_click(self, button, x, y)
|
||||||
end
|
end
|
||||||
@@ -260,7 +260,7 @@ end
|
|||||||
--- @shortDescription Handles mouse drag events
|
--- @shortDescription Handles mouse drag events
|
||||||
--- @protected
|
--- @protected
|
||||||
function Dialog:mouse_drag(button, x, y)
|
function Dialog:mouse_drag(button, x, y)
|
||||||
if self.get("modal") then
|
if self.getResolved("modal") then
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
return Frame.mouse_drag and Frame.mouse_drag(self, button, x, y) or false
|
return Frame.mouse_drag and Frame.mouse_drag(self, button, x, y) or false
|
||||||
end
|
end
|
||||||
@@ -273,7 +273,7 @@ end
|
|||||||
--- @shortDescription Handles mouse up events
|
--- @shortDescription Handles mouse up events
|
||||||
--- @protected
|
--- @protected
|
||||||
function Dialog:mouse_up(button, x, y)
|
function Dialog:mouse_up(button, x, y)
|
||||||
if self.get("modal") then
|
if self.getResolved("modal") then
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
return Frame.mouse_up and Frame.mouse_up(self, button, x, y) or false
|
return Frame.mouse_up and Frame.mouse_up(self, button, x, y) or false
|
||||||
end
|
end
|
||||||
@@ -286,7 +286,7 @@ end
|
|||||||
--- @shortDescription Handles mouse scroll events
|
--- @shortDescription Handles mouse scroll events
|
||||||
--- @protected
|
--- @protected
|
||||||
function Dialog:mouse_scroll(direction, x, y)
|
function Dialog:mouse_scroll(direction, x, y)
|
||||||
if self.get("modal") then
|
if self.getResolved("modal") then
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
return Frame.mouse_scroll and Frame.mouse_scroll(self, direction, x, y) or false
|
return Frame.mouse_scroll and Frame.mouse_scroll(self, direction, x, y) or false
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ end
|
|||||||
function Display:init(props, basalt)
|
function Display:init(props, basalt)
|
||||||
VisualElement.init(self, props, basalt)
|
VisualElement.init(self, props, basalt)
|
||||||
self.set("type", "Display")
|
self.set("type", "Display")
|
||||||
self._window = window.create(basalt.getActiveFrame():getTerm(), 1, 1, self.get("width"), self.get("height"), false)
|
self._window = window.create(basalt.getActiveFrame():getTerm(), 1, 1, self.getResolved("width"), self.getResolved("height"), false)
|
||||||
local reposition = self._window.reposition
|
local reposition = self._window.reposition
|
||||||
local blit = self._window.blit
|
local blit = self._window.blit
|
||||||
local write = self._window.write
|
local write = self._window.write
|
||||||
@@ -63,7 +63,7 @@ function Display:init(props, basalt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
self._window.getPosition = function(self)
|
self._window.getPosition = function(self)
|
||||||
return self.get("x"), self.get("y")
|
return self.getResolved("x"), self.getResolved("y")
|
||||||
end
|
end
|
||||||
|
|
||||||
self._window.setVisible = function(visible)
|
self._window.setVisible = function(visible)
|
||||||
@@ -71,7 +71,7 @@ function Display:init(props, basalt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
self._window.isVisible = function(self)
|
self._window.isVisible = function(self)
|
||||||
return self.get("visible")
|
return self.getResolved("visible")
|
||||||
end
|
end
|
||||||
self._window.blit = function(x, y, text, fg, bg)
|
self._window.blit = function(x, y, text, fg, bg)
|
||||||
blit(x, y, text, fg, bg)
|
blit(x, y, text, fg, bg)
|
||||||
@@ -85,13 +85,13 @@ function Display:init(props, basalt)
|
|||||||
self:observe("width", function(self, width)
|
self:observe("width", function(self, width)
|
||||||
local window = self._window
|
local window = self._window
|
||||||
if window then
|
if window then
|
||||||
window.reposition(1, 1, width, self.get("height"))
|
window.reposition(1, 1, width, self.getResolved("height"))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
self:observe("height", function(self, height)
|
self:observe("height", function(self, height)
|
||||||
local window = self._window
|
local window = self._window
|
||||||
if window then
|
if window then
|
||||||
window.reposition(1, 1, self.get("width"), height)
|
window.reposition(1, 1, self.getResolved("width"), height)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ function DropDown:mouse_click(button, x, y)
|
|||||||
self.set("height", 1)
|
self.set("height", 1)
|
||||||
self:unsetState("opened")
|
self:unsetState("opened")
|
||||||
else
|
else
|
||||||
self.set("height", 1 + math.min(self.get("dropdownHeight"), #self.get("items")))
|
self.set("height", 1 + math.min(self.getResolved("dropdownHeight"), #self.getResolved("items")))
|
||||||
self:setState("opened")
|
self:setState("opened")
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
@@ -140,9 +140,9 @@ function DropDown:mouse_up(button, x, y)
|
|||||||
if self:hasState("opened") then
|
if self:hasState("opened") then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
|
|
||||||
if relY > 1 and self.get("selectable") and not self._scrollBarDragging then
|
if relY > 1 and self.getResolved("selectable") and not self._scrollBarDragging then
|
||||||
local itemIndex = (relY - 1) + self.get("offset")
|
local itemIndex = (relY - 1) + self.getResolved("offset")
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
|
|
||||||
if itemIndex <= #items then
|
if itemIndex <= #items then
|
||||||
local item = items[itemIndex]
|
local item = items[itemIndex]
|
||||||
@@ -151,7 +151,7 @@ function DropDown:mouse_up(button, x, y)
|
|||||||
items[itemIndex] = item
|
items[itemIndex] = item
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("multiSelection") then
|
if not self.getResolved("multiSelection") then
|
||||||
for _, otherItem in ipairs(items) do
|
for _, otherItem in ipairs(items) do
|
||||||
if type(otherItem) == "table" then
|
if type(otherItem) == "table" then
|
||||||
otherItem.selected = false
|
otherItem.selected = false
|
||||||
@@ -187,26 +187,28 @@ end
|
|||||||
function DropDown:render()
|
function DropDown:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local text = self.get("selectedText")
|
local width = self.getResolved("width")
|
||||||
|
local height = self.getResolved("height")
|
||||||
|
local text = self.getResolved("selectedText")
|
||||||
local isOpen = self:hasState("opened")
|
local isOpen = self:hasState("opened")
|
||||||
local selectedItems = self:getSelectedItems()
|
local selectedItems = self:getSelectedItems()
|
||||||
if #selectedItems > 0 then
|
if #selectedItems > 0 then
|
||||||
local selectedItem = selectedItems[1]
|
local selectedItem = selectedItems[1]
|
||||||
text = selectedItem.text or ""
|
text = selectedItem.text or ""
|
||||||
text = text:sub(1, self.get("width") - 2)
|
text = text:sub(1, width - 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
if isOpen then
|
if isOpen then
|
||||||
local actualHeight = self.get("height")
|
local actualHeight = height
|
||||||
local dropdownHeight = math.min(self.get("dropdownHeight"), #self.get("items"))
|
local dropdownHeight = math.min(self.getResolved("dropdownHeight"), #self.getResolved("items"))
|
||||||
self.set("height", dropdownHeight)
|
self.set("height", dropdownHeight)
|
||||||
List.render(self, 1)
|
List.render(self, 1)
|
||||||
self.set("height", actualHeight)
|
self.set("height", actualHeight)
|
||||||
end
|
end
|
||||||
|
|
||||||
self:blit(1, 1, text .. string.rep(" ", self.get("width") - #text - 1) .. (isOpen and self.dropSymbol or self.undropSymbol),
|
self:blit(1, 1, text .. string.rep(" ", width - #text - 1) .. (isOpen and self.getResolved("dropSymbol") or self.getResolved("undropSymbol")),
|
||||||
string.rep(tHex[self.getResolved("foreground")], self.get("width")),
|
string.rep(tHex[self.getResolved("foreground")], width),
|
||||||
string.rep(tHex[self.getResolved("background")], self.get("width")))
|
string.rep(tHex[self.getResolved("background")], width))
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Called when the DropDown gains focus
|
--- Called when the DropDown gains focus
|
||||||
|
|||||||
@@ -53,21 +53,21 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Frame:mouse_click(button, x, y)
|
function Frame:mouse_click(button, x, y)
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
if self.get("draggable") then
|
if self.getResolved("draggable") then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local draggingMap = self.get("draggingMap")
|
local draggingMap = self.getResolved("draggingMap")
|
||||||
|
|
||||||
for _, map in ipairs(draggingMap) do
|
for _, map in ipairs(draggingMap) do
|
||||||
local width = map.width or 1
|
local width = map.width or 1
|
||||||
local height = map.height or 1
|
local height = map.height or 1
|
||||||
|
|
||||||
if type(width) == "string" and width == "width" then
|
if type(width) == "string" and width == "width" then
|
||||||
width = self.get("width")
|
width = self.getResolved("width")
|
||||||
elseif type(width) == "function" then
|
elseif type(width) == "function" then
|
||||||
width = width(self)
|
width = width(self)
|
||||||
end
|
end
|
||||||
if type(height) == "string" and height == "height" then
|
if type(height) == "string" and height == "height" then
|
||||||
height = self.get("height")
|
height = self.getResolved("height")
|
||||||
elseif type(height) == "function" then
|
elseif type(height) == "function" then
|
||||||
height = height(self)
|
height = height(self)
|
||||||
end
|
end
|
||||||
@@ -75,8 +75,8 @@ function Frame:mouse_click(button, x, y)
|
|||||||
local mapY = map.y or 1
|
local mapY = map.y or 1
|
||||||
if relX >= map.x and relX <= map.x + width - 1 and
|
if relX >= map.x and relX <= map.x + width - 1 and
|
||||||
relY >= mapY and relY <= mapY + height - 1 then
|
relY >= mapY and relY <= mapY + height - 1 then
|
||||||
self.dragStartX = x - self.get("x")
|
self.dragStartX = x - self.getResolved("x")
|
||||||
self.dragStartY = y - self.get("y")
|
self.dragStartY = y - self.getResolved("y")
|
||||||
self.dragging = true
|
self.dragging = true
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -126,7 +126,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Frame:getChildrenHeight()
|
function Frame:getChildrenHeight()
|
||||||
local maxHeight = 0
|
local maxHeight = 0
|
||||||
local children = self.get("children")
|
local children = self.getResolved("children")
|
||||||
|
|
||||||
for _, child in ipairs(children) do
|
for _, child in ipairs(children) do
|
||||||
if child.get("visible") then
|
if child.get("visible") then
|
||||||
@@ -147,7 +147,7 @@ local function convertMousePosition(self, event, ...)
|
|||||||
local args = {...}
|
local args = {...}
|
||||||
if event and event:find("mouse_") then
|
if event and event:find("mouse_") then
|
||||||
local button, absX, absY = ...
|
local button, absX, absY = ...
|
||||||
local xOffset, yOffset = self.get("offsetX"), self.get("offsetY")
|
local xOffset, yOffset = self.getResolved("offsetX"), self.getResolved("offsetY")
|
||||||
local relX, relY = self:getRelativePosition(absX + xOffset, absY + yOffset)
|
local relX, relY = self:getRelativePosition(absX + xOffset, absY + yOffset)
|
||||||
args = {button, relX, relY}
|
args = {button, relX, relY}
|
||||||
end
|
end
|
||||||
@@ -167,11 +167,11 @@ function Frame:mouse_scroll(direction, x, y)
|
|||||||
if success then
|
if success then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if self.get("scrollable") then
|
if self.getResolved("scrollable") then
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
|
|
||||||
local childrenHeight = self:getChildrenHeight()
|
local childrenHeight = self:getChildrenHeight()
|
||||||
local currentOffset = self.get("offsetY")
|
local currentOffset = self.getResolved("offsetY")
|
||||||
local maxScroll = math.max(0, childrenHeight - height)
|
local maxScroll = math.max(0, childrenHeight - height)
|
||||||
|
|
||||||
local newOffset = currentOffset + direction
|
local newOffset = currentOffset + direction
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ end
|
|||||||
--- @param pointCount number The number of points in the series
|
--- @param pointCount number The number of points in the series
|
||||||
--- @return Graph self The graph instance
|
--- @return Graph self The graph instance
|
||||||
function Graph:addSeries(name, symbol, bgCol, fgCol, pointCount)
|
function Graph:addSeries(name, symbol, bgCol, fgCol, pointCount)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
table.insert(series, {
|
table.insert(series, {
|
||||||
name = name,
|
name = name,
|
||||||
symbol = symbol or " ",
|
symbol = symbol or " ",
|
||||||
bgColor = bgCol or colors.white,
|
bgColor = bgCol or colors.white,
|
||||||
fgColor = fgCol or colors.black,
|
fgColor = fgCol or colors.black,
|
||||||
pointCount = pointCount or self.get("width"),
|
pointCount = pointCount or self.getResolved("width"),
|
||||||
data = {},
|
data = {},
|
||||||
visible = true
|
visible = true
|
||||||
})
|
})
|
||||||
@@ -78,7 +78,7 @@ end
|
|||||||
--- @param name string The name of the series
|
--- @param name string The name of the series
|
||||||
--- @return Graph self The graph instance
|
--- @return Graph self The graph instance
|
||||||
function Graph:removeSeries(name)
|
function Graph:removeSeries(name)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
for i, s in ipairs(series) do
|
for i, s in ipairs(series) do
|
||||||
if s.name == name then
|
if s.name == name then
|
||||||
table.remove(series, i)
|
table.remove(series, i)
|
||||||
@@ -93,7 +93,7 @@ end
|
|||||||
--- @param name string The name of the series
|
--- @param name string The name of the series
|
||||||
--- @return table? series The series
|
--- @return table? series The series
|
||||||
function Graph:getSeries(name)
|
function Graph:getSeries(name)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
for _, s in ipairs(series) do
|
for _, s in ipairs(series) do
|
||||||
if s.name == name then
|
if s.name == name then
|
||||||
return s
|
return s
|
||||||
@@ -107,7 +107,7 @@ end
|
|||||||
--- @param visible boolean Whether the series should be visible
|
--- @param visible boolean Whether the series should be visible
|
||||||
--- @return Graph self The graph instance
|
--- @return Graph self The graph instance
|
||||||
function Graph:changeSeriesVisibility(name, visible)
|
function Graph:changeSeriesVisibility(name, visible)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
for _, s in ipairs(series) do
|
for _, s in ipairs(series) do
|
||||||
if s.name == name then
|
if s.name == name then
|
||||||
s.visible = visible
|
s.visible = visible
|
||||||
@@ -123,7 +123,7 @@ end
|
|||||||
--- @param value number The value of the point
|
--- @param value number The value of the point
|
||||||
--- @return Graph self The graph instance
|
--- @return Graph self The graph instance
|
||||||
function Graph:addPoint(name, value)
|
function Graph:addPoint(name, value)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
|
|
||||||
for _, s in ipairs(series) do
|
for _, s in ipairs(series) do
|
||||||
if s.name == name then
|
if s.name == name then
|
||||||
@@ -142,7 +142,7 @@ end
|
|||||||
--- @param name string The name of the series
|
--- @param name string The name of the series
|
||||||
--- @return Graph self The graph instance
|
--- @return Graph self The graph instance
|
||||||
function Graph:focusSeries(name)
|
function Graph:focusSeries(name)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
for index, s in ipairs(series) do
|
for index, s in ipairs(series) do
|
||||||
if s.name == name then
|
if s.name == name then
|
||||||
table.remove(series, index)
|
table.remove(series, index)
|
||||||
@@ -159,7 +159,7 @@ end
|
|||||||
--- @param count number The number of points in the series
|
--- @param count number The number of points in the series
|
||||||
--- @return Graph self The graph instance
|
--- @return Graph self The graph instance
|
||||||
function Graph:setSeriesPointCount(name, count)
|
function Graph:setSeriesPointCount(name, count)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
for _, s in ipairs(series) do
|
for _, s in ipairs(series) do
|
||||||
if s.name == name then
|
if s.name == name then
|
||||||
s.pointCount = count
|
s.pointCount = count
|
||||||
@@ -178,7 +178,7 @@ end
|
|||||||
--- @param name? string The name of the series
|
--- @param name? string The name of the series
|
||||||
--- @return Graph self The graph instance
|
--- @return Graph self The graph instance
|
||||||
function Graph:clear(seriesName)
|
function Graph:clear(seriesName)
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
if seriesName then
|
if seriesName then
|
||||||
for _, s in ipairs(series) do
|
for _, s in ipairs(series) do
|
||||||
if s.name == seriesName then
|
if s.name == seriesName then
|
||||||
@@ -199,11 +199,11 @@ end
|
|||||||
function Graph:render()
|
function Graph:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local minVal = self.get("minValue")
|
local minVal = self.getResolved("minValue")
|
||||||
local maxVal = self.get("maxValue")
|
local maxVal = self.getResolved("maxValue")
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
|
|
||||||
for _, s in pairs(series) do
|
for _, s in pairs(series) do
|
||||||
if(s.visible)then
|
if(s.visible)then
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ end
|
|||||||
--- @param height number The new height of the image
|
--- @param height number The new height of the image
|
||||||
--- @return Image self The Image instance
|
--- @return Image self The Image instance
|
||||||
function Image:resizeImage(width, height)
|
function Image:resizeImage(width, height)
|
||||||
local frames = self.get("bimg")
|
local frames = self.getResolved("bimg")
|
||||||
|
|
||||||
for frameIndex, frame in ipairs(frames) do
|
for frameIndex, frame in ipairs(frames) do
|
||||||
local newFrame = {}
|
local newFrame = {}
|
||||||
@@ -86,7 +86,7 @@ end
|
|||||||
--- @return number width The width of the image
|
--- @return number width The width of the image
|
||||||
--- @return number height The height of the image
|
--- @return number height The height of the image
|
||||||
function Image:getImageSize()
|
function Image:getImageSize()
|
||||||
local bimg = self.get("bimg")
|
local bimg = self.getResolved("bimg")
|
||||||
if not bimg[1] or not bimg[1][1] then return 0, 0 end
|
if not bimg[1] or not bimg[1][1] then return 0, 0 end
|
||||||
return #bimg[1][1][1], #bimg[1]
|
return #bimg[1][1][1], #bimg[1]
|
||||||
end
|
end
|
||||||
@@ -99,7 +99,7 @@ end
|
|||||||
--- @return number? bg Background color
|
--- @return number? bg Background color
|
||||||
--- @return string? char Character at position
|
--- @return string? char Character at position
|
||||||
function Image:getPixelData(x, y)
|
function Image:getPixelData(x, y)
|
||||||
local frame = self.get("bimg")[self.get("currentFrame")]
|
local frame = self.getResolved("bimg")[self.getResolved("currentFrame")]
|
||||||
if not frame or not frame[y] then return end
|
if not frame or not frame[y] then return end
|
||||||
|
|
||||||
local text = frame[y][1]
|
local text = frame[y][1]
|
||||||
@@ -116,10 +116,10 @@ function Image:getPixelData(x, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function ensureFrame(self, y)
|
local function ensureFrame(self, y)
|
||||||
local frame = self.get("bimg")[self.get("currentFrame")]
|
local frame = self.getResolved("bimg")[self.getResolved("currentFrame")]
|
||||||
if not frame then
|
if not frame then
|
||||||
frame = {}
|
frame = {}
|
||||||
self.get("bimg")[self.get("currentFrame")] = frame
|
self.getResolved("bimg")[self.getResolved("currentFrame")] = frame
|
||||||
end
|
end
|
||||||
if not frame[y] then
|
if not frame[y] then
|
||||||
frame[y] = {"", "", ""}
|
frame[y] = {"", "", ""}
|
||||||
@@ -128,9 +128,9 @@ local function ensureFrame(self, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function updateFrameSize(self, neededWidth, neededHeight)
|
local function updateFrameSize(self, neededWidth, neededHeight)
|
||||||
if not self.get("autoResize") then return end
|
if not self.getResolved("autoResize") then return end
|
||||||
|
|
||||||
local frames = self.get("bimg")
|
local frames = self.getResolved("bimg")
|
||||||
|
|
||||||
local maxWidth = neededWidth
|
local maxWidth = neededWidth
|
||||||
local maxHeight = neededHeight
|
local maxHeight = neededHeight
|
||||||
@@ -164,13 +164,13 @@ end
|
|||||||
--- @return Image self The Image instance
|
--- @return Image self The Image instance
|
||||||
function Image:setText(x, y, text)
|
function Image:setText(x, y, text)
|
||||||
if type(text) ~= "string" or #text < 1 or x < 1 or y < 1 then return self end
|
if type(text) ~= "string" or #text < 1 or x < 1 or y < 1 then return self end
|
||||||
if not self.get("autoResize")then
|
if not self.getResolved("autoResize")then
|
||||||
local imgWidth, imgHeight = self:getImageSize()
|
local imgWidth, imgHeight = self:getImageSize()
|
||||||
if y > imgHeight then return self end
|
if y > imgHeight then return self end
|
||||||
end
|
end
|
||||||
local frame = ensureFrame(self, y)
|
local frame = ensureFrame(self, y)
|
||||||
|
|
||||||
if self.get("autoResize") then
|
if self.getResolved("autoResize") then
|
||||||
updateFrameSize(self, x + #text - 1, y)
|
updateFrameSize(self, x + #text - 1, y)
|
||||||
else
|
else
|
||||||
local maxLen = #frame[y][1]
|
local maxLen = #frame[y][1]
|
||||||
@@ -193,7 +193,7 @@ end
|
|||||||
--- @return string text The text at the specified position
|
--- @return string text The text at the specified position
|
||||||
function Image:getText(x, y, length)
|
function Image:getText(x, y, length)
|
||||||
if not x or not y then return "" end
|
if not x or not y then return "" end
|
||||||
local frame = self.get("bimg")[self.get("currentFrame")]
|
local frame = self.getResolved("bimg")[self.getResolved("currentFrame")]
|
||||||
if not frame or not frame[y] then return "" end
|
if not frame or not frame[y] then return "" end
|
||||||
|
|
||||||
local text = frame[y][1]
|
local text = frame[y][1]
|
||||||
@@ -214,13 +214,13 @@ end
|
|||||||
--- @return Image self The Image instance
|
--- @return Image self The Image instance
|
||||||
function Image:setFg(x, y, pattern)
|
function Image:setFg(x, y, pattern)
|
||||||
if type(pattern) ~= "string" or #pattern < 1 or x < 1 or y < 1 then return self end
|
if type(pattern) ~= "string" or #pattern < 1 or x < 1 or y < 1 then return self end
|
||||||
if not self.get("autoResize")then
|
if not self.getResolved("autoResize")then
|
||||||
local imgWidth, imgHeight = self:getImageSize()
|
local imgWidth, imgHeight = self:getImageSize()
|
||||||
if y > imgHeight then return self end
|
if y > imgHeight then return self end
|
||||||
end
|
end
|
||||||
local frame = ensureFrame(self, y)
|
local frame = ensureFrame(self, y)
|
||||||
|
|
||||||
if self.get("autoResize") then
|
if self.getResolved("autoResize") then
|
||||||
updateFrameSize(self, x + #pattern - 1, y)
|
updateFrameSize(self, x + #pattern - 1, y)
|
||||||
else
|
else
|
||||||
local maxLen = #frame[y][2]
|
local maxLen = #frame[y][2]
|
||||||
@@ -243,7 +243,7 @@ end
|
|||||||
--- @return string fg The foreground color pattern
|
--- @return string fg The foreground color pattern
|
||||||
function Image:getFg(x, y, length)
|
function Image:getFg(x, y, length)
|
||||||
if not x or not y then return "" end
|
if not x or not y then return "" end
|
||||||
local frame = self.get("bimg")[self.get("currentFrame")]
|
local frame = self.getResolved("bimg")[self.getResolved("currentFrame")]
|
||||||
if not frame or not frame[y] then return "" end
|
if not frame or not frame[y] then return "" end
|
||||||
|
|
||||||
local fg = frame[y][2]
|
local fg = frame[y][2]
|
||||||
@@ -264,13 +264,13 @@ end
|
|||||||
--- @return Image self The Image instance
|
--- @return Image self The Image instance
|
||||||
function Image:setBg(x, y, pattern)
|
function Image:setBg(x, y, pattern)
|
||||||
if type(pattern) ~= "string" or #pattern < 1 or x < 1 or y < 1 then return self end
|
if type(pattern) ~= "string" or #pattern < 1 or x < 1 or y < 1 then return self end
|
||||||
if not self.get("autoResize")then
|
if not self.getResolved("autoResize")then
|
||||||
local imgWidth, imgHeight = self:getImageSize()
|
local imgWidth, imgHeight = self:getImageSize()
|
||||||
if y > imgHeight then return self end
|
if y > imgHeight then return self end
|
||||||
end
|
end
|
||||||
local frame = ensureFrame(self, y)
|
local frame = ensureFrame(self, y)
|
||||||
|
|
||||||
if self.get("autoResize") then
|
if self.getResolved("autoResize") then
|
||||||
updateFrameSize(self, x + #pattern - 1, y)
|
updateFrameSize(self, x + #pattern - 1, y)
|
||||||
else
|
else
|
||||||
local maxLen = #frame[y][3]
|
local maxLen = #frame[y][3]
|
||||||
@@ -293,7 +293,7 @@ end
|
|||||||
--- @return string bg The background color pattern
|
--- @return string bg The background color pattern
|
||||||
function Image:getBg(x, y, length)
|
function Image:getBg(x, y, length)
|
||||||
if not x or not y then return "" end
|
if not x or not y then return "" end
|
||||||
local frame = self.get("bimg")[self.get("currentFrame")]
|
local frame = self.getResolved("bimg")[self.getResolved("currentFrame")]
|
||||||
if not frame or not frame[y] then return "" end
|
if not frame or not frame[y] then return "" end
|
||||||
|
|
||||||
local bg = frame[y][3]
|
local bg = frame[y][3]
|
||||||
@@ -325,10 +325,10 @@ end
|
|||||||
--- @shortDescription Advances to the next frame in the animation
|
--- @shortDescription Advances to the next frame in the animation
|
||||||
--- @return Image self The Image instance
|
--- @return Image self The Image instance
|
||||||
function Image:nextFrame()
|
function Image:nextFrame()
|
||||||
if not self.get("bimg").animation then return self end
|
if not self.getResolved("bimg").animation then return self end
|
||||||
|
|
||||||
local frames = self.get("bimg")
|
local frames = self.getResolved("bimg")
|
||||||
local current = self.get("currentFrame")
|
local current = self.getResolved("currentFrame")
|
||||||
local next = current + 1
|
local next = current + 1
|
||||||
if next > #frames then next = 1 end
|
if next > #frames then next = 1 end
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ end
|
|||||||
--- @shortDescription Adds a new frame to the image
|
--- @shortDescription Adds a new frame to the image
|
||||||
--- @return Image self The Image instance
|
--- @return Image self The Image instance
|
||||||
function Image:addFrame()
|
function Image:addFrame()
|
||||||
local frames = self.get("bimg")
|
local frames = self.getResolved("bimg")
|
||||||
local width = frames.width or #frames[1][1][1]
|
local width = frames.width or #frames[1][1][1]
|
||||||
local height = frames.height or #frames[1]
|
local height = frames.height or #frames[1]
|
||||||
local frame = {}
|
local frame = {}
|
||||||
@@ -360,7 +360,7 @@ end
|
|||||||
--- @param frame table The new frame data
|
--- @param frame table The new frame data
|
||||||
--- @return Image self The Image instance
|
--- @return Image self The Image instance
|
||||||
function Image:updateFrame(frameIndex, frame)
|
function Image:updateFrame(frameIndex, frame)
|
||||||
local frames = self.get("bimg")
|
local frames = self.getResolved("bimg")
|
||||||
frames[frameIndex] = frame
|
frames[frameIndex] = frame
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
return self
|
return self
|
||||||
@@ -371,8 +371,8 @@ end
|
|||||||
--- @param frameIndex number The index of the frame to get
|
--- @param frameIndex number The index of the frame to get
|
||||||
--- @return table frame The frame data
|
--- @return table frame The frame data
|
||||||
function Image:getFrame(frameIndex)
|
function Image:getFrame(frameIndex)
|
||||||
local frames = self.get("bimg")
|
local frames = self.getResolved("bimg")
|
||||||
return frames[frameIndex or self.get("currentFrame")]
|
return frames[frameIndex or self.getResolved("currentFrame")]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the metadata of the image
|
--- Gets the metadata of the image
|
||||||
@@ -380,7 +380,7 @@ end
|
|||||||
--- @return table metadata The metadata of the image
|
--- @return table metadata The metadata of the image
|
||||||
function Image:getMetadata()
|
function Image:getMetadata()
|
||||||
local metadata = {}
|
local metadata = {}
|
||||||
local bimg = self.get("bimg")
|
local bimg = self.getResolved("bimg")
|
||||||
for k,v in pairs(bimg)do
|
for k,v in pairs(bimg)do
|
||||||
if(type(v)=="string")then
|
if(type(v)=="string")then
|
||||||
metadata[k] = v
|
metadata[k] = v
|
||||||
@@ -401,7 +401,7 @@ function Image:setMetadata(key, value)
|
|||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
local bimg = self.get("bimg")
|
local bimg = self.getResolved("bimg")
|
||||||
if(type(value)=="string")then
|
if(type(value)=="string")then
|
||||||
bimg[key] = value
|
bimg[key] = value
|
||||||
end
|
end
|
||||||
@@ -413,13 +413,13 @@ end
|
|||||||
function Image:render()
|
function Image:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local frame = self.get("bimg")[self.get("currentFrame")]
|
local frame = self.getResolved("bimg")[self.getResolved("currentFrame")]
|
||||||
if not frame then return end
|
if not frame then return end
|
||||||
|
|
||||||
local offsetX = self.get("offsetX")
|
local offsetX = self.getResolved("offsetX")
|
||||||
local offsetY = self.get("offsetY")
|
local offsetY = self.getResolved("offsetY")
|
||||||
local elementWidth = self.get("width")
|
local elementWidth = self.getResolved("width")
|
||||||
local elementHeight = self.get("height")
|
local elementHeight = self.getResolved("height")
|
||||||
|
|
||||||
for y = 1, elementHeight do
|
for y = 1, elementHeight do
|
||||||
local frameY = y + offsetY
|
local frameY = y + offsetY
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ end
|
|||||||
--- @param blink boolean Whether the cursor should blink
|
--- @param blink boolean Whether the cursor should blink
|
||||||
--- @param color number The color of the cursor
|
--- @param color number The color of the cursor
|
||||||
function Input:setCursor(x, y, blink, color)
|
function Input:setCursor(x, y, blink, color)
|
||||||
x = math.min(self.get("width"), math.max(1, x))
|
x = math.min(self.getResolved("width"), math.max(1, x))
|
||||||
return VisualElement.setCursor(self, x, y, blink, color)
|
return VisualElement.setCursor(self, x, y, blink, color)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -72,10 +72,10 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Input:char(char)
|
function Input:char(char)
|
||||||
if not self:hasState("focused") then return false end
|
if not self:hasState("focused") then return false end
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local pos = self.get("cursorPos")
|
local pos = self.getResolved("cursorPos")
|
||||||
local maxLength = self.get("maxLength")
|
local maxLength = self.getResolved("maxLength")
|
||||||
local pattern = self.get("pattern")
|
local pattern = self.getResolved("pattern")
|
||||||
|
|
||||||
if maxLength and #text >= maxLength then return false end
|
if maxLength and #text >= maxLength then return false end
|
||||||
if pattern and not char:match(pattern) then return false end
|
if pattern and not char:match(pattern) then return false end
|
||||||
@@ -84,8 +84,8 @@ function Input:char(char)
|
|||||||
self.set("cursorPos", pos + 1)
|
self.set("cursorPos", pos + 1)
|
||||||
self:updateViewport()
|
self:updateViewport()
|
||||||
|
|
||||||
local relPos = self.get("cursorPos") - self.get("viewOffset")
|
local relPos = self.getResolved("cursorPos") - self.getResolved("viewOffset")
|
||||||
self:setCursor(relPos, 1, true, self.get("cursorColor") or self.get("foreground"))
|
self:setCursor(relPos, 1, true, self.getResolved("cursorColor") or self.getResolved("foreground"))
|
||||||
VisualElement.char(self, char)
|
VisualElement.char(self, char)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -96,10 +96,10 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Input:key(key, held)
|
function Input:key(key, held)
|
||||||
if not self:hasState("focused") then return false end
|
if not self:hasState("focused") then return false end
|
||||||
local pos = self.get("cursorPos")
|
local pos = self.getResolved("cursorPos")
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local viewOffset = self.get("viewOffset")
|
local viewOffset = self.getResolved("viewOffset")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
|
|
||||||
if key == keys.left then
|
if key == keys.left then
|
||||||
if pos > 1 then
|
if pos > 1 then
|
||||||
@@ -124,7 +124,7 @@ function Input:key(key, held)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local relativePos = self.get("cursorPos") - self.get("viewOffset")
|
local relativePos = self.getResolved("cursorPos") - self.getResolved("viewOffset")
|
||||||
self:setCursor(relativePos, 1, true, self.getResolved("cursorColor") or self.getResolved("foreground"))
|
self:setCursor(relativePos, 1, true, self.getResolved("cursorColor") or self.getResolved("foreground"))
|
||||||
VisualElement.key(self, key, held)
|
VisualElement.key(self, key, held)
|
||||||
return true
|
return true
|
||||||
@@ -139,8 +139,8 @@ end
|
|||||||
function Input:mouse_click(button, x, y)
|
function Input:mouse_click(button, x, y)
|
||||||
if VisualElement.mouse_click(self, button, x, y) then
|
if VisualElement.mouse_click(self, button, x, y) then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local viewOffset = self.get("viewOffset")
|
local viewOffset = self.getResolved("viewOffset")
|
||||||
|
|
||||||
local maxPos = #text + 1
|
local maxPos = #text + 1
|
||||||
local targetPos = math.min(maxPos, viewOffset + relX)
|
local targetPos = math.min(maxPos, viewOffset + relX)
|
||||||
@@ -158,10 +158,10 @@ end
|
|||||||
--- @shortDescription Updates the input's viewport
|
--- @shortDescription Updates the input's viewport
|
||||||
--- @return Input self The updated instance
|
--- @return Input self The updated instance
|
||||||
function Input:updateViewport()
|
function Input:updateViewport()
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local cursorPos = self.get("cursorPos")
|
local cursorPos = self.getResolved("cursorPos")
|
||||||
local viewOffset = self.get("viewOffset")
|
local viewOffset = self.getResolved("viewOffset")
|
||||||
local textLength = #self.get("text")
|
local textLength = #self.getResolved("text")
|
||||||
|
|
||||||
if cursorPos - viewOffset >= width then
|
if cursorPos - viewOffset >= width then
|
||||||
self.set("viewOffset", cursorPos - width + 1)
|
self.set("viewOffset", cursorPos - width + 1)
|
||||||
@@ -169,7 +169,7 @@ function Input:updateViewport()
|
|||||||
self.set("viewOffset", cursorPos - 1)
|
self.set("viewOffset", cursorPos - 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.set("viewOffset", math.max(0, math.min(self.get("viewOffset"), textLength - width + 1)))
|
self.set("viewOffset", math.max(0, math.min(self.getResolved("viewOffset"), textLength - width + 1)))
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -178,7 +178,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Input:focus()
|
function Input:focus()
|
||||||
VisualElement.focus(self)
|
VisualElement.focus(self)
|
||||||
self:setCursor(self.get("cursorPos") - self.get("viewOffset"), 1, true, self.getResolved("cursorColor") or self.getResolved("foreground"))
|
self:setCursor(self.getResolved("cursorPos") - self.getResolved("viewOffset"), 1, true, self.getResolved("cursorColor") or self.getResolved("foreground"))
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -194,10 +194,10 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Input:paste(content)
|
function Input:paste(content)
|
||||||
if not self:hasState("focused") then return false end
|
if not self:hasState("focused") then return false end
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local pos = self.get("cursorPos")
|
local pos = self.getResolved("cursorPos")
|
||||||
local maxLength = self.get("maxLength")
|
local maxLength = self.getResolved("maxLength")
|
||||||
local pattern = self.get("pattern")
|
local pattern = self.getResolved("pattern")
|
||||||
local newText = text:sub(1, pos - 1) .. content .. text:sub(pos)
|
local newText = text:sub(1, pos - 1) .. content .. text:sub(pos)
|
||||||
if maxLength and #newText > maxLength then
|
if maxLength and #newText > maxLength then
|
||||||
newText = newText:sub(1, maxLength)
|
newText = newText:sub(1, maxLength)
|
||||||
@@ -214,10 +214,10 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Input:render()
|
function Input:render()
|
||||||
local text = self.getResolved("text")
|
local text = self.getResolved("text")
|
||||||
local viewOffset = self.get("viewOffset")
|
local viewOffset = self.getResolved("viewOffset")
|
||||||
local placeholder = self.getResolved("placeholder")
|
local placeholder = self.getResolved("placeholder")
|
||||||
local focused = self:hasState("focused")
|
local focused = self:hasState("focused")
|
||||||
local width, height = self.get("width"), self.get("height")
|
local width, height = self.getResolved("width"), self.getResolved("height")
|
||||||
local replaceChar = self.getResolved("replaceChar")
|
local replaceChar = self.getResolved("replaceChar")
|
||||||
self:multiBlit(1, 1, width, height, " ", tHex[self.getResolved("foreground")], tHex[self.getResolved("background")])
|
self:multiBlit(1, 1, width, height, " ", tHex[self.getResolved("foreground")], tHex[self.getResolved("background")])
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ function Input:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if(focused) then
|
if(focused) then
|
||||||
self:setCursor(self.get("cursorPos") - viewOffset, 1, true, self.getResolved("cursorColor") or self.getResolved("foreground"))
|
self:setCursor(self.getResolved("cursorPos") - viewOffset, 1, true, self.getResolved("cursorColor") or self.getResolved("foreground"))
|
||||||
end
|
end
|
||||||
|
|
||||||
local visibleText = text:sub(viewOffset + 1, viewOffset + width)
|
local visibleText = text:sub(viewOffset + 1, viewOffset + width)
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ Label.__index = Label
|
|||||||
---@property text string Label The text content to display. Can be a string or a function that returns a string
|
---@property text string Label The text content to display. Can be a string or a function that returns a string
|
||||||
Label.defineProperty(Label, "text", {default = "Label", type = "string", canTriggerRender = true, setter = function(self, value)
|
Label.defineProperty(Label, "text", {default = "Label", type = "string", canTriggerRender = true, setter = function(self, value)
|
||||||
if(type(value)=="function")then value = value() end
|
if(type(value)=="function")then value = value() end
|
||||||
if(self.get("autoSize"))then
|
if(self.getResolved("autoSize"))then
|
||||||
self.set("width", #value)
|
self.set("width", #value)
|
||||||
else
|
else
|
||||||
self.set("height", #wrapText(value, self.get("width")))
|
self.set("height", #wrapText(value, self.getResolved("width")))
|
||||||
end
|
end
|
||||||
return value
|
return value
|
||||||
end})
|
end})
|
||||||
@@ -22,9 +22,9 @@ end})
|
|||||||
---@property autoSize boolean true Whether the label should automatically resize its width based on the text content
|
---@property autoSize boolean true Whether the label should automatically resize its width based on the text content
|
||||||
Label.defineProperty(Label, "autoSize", {default = true, type = "boolean", canTriggerRender = true, setter = function(self, value)
|
Label.defineProperty(Label, "autoSize", {default = true, type = "boolean", canTriggerRender = true, setter = function(self, value)
|
||||||
if(value)then
|
if(value)then
|
||||||
self.set("width", #self.get("text"))
|
self.set("width", #self.getResolved("text"))
|
||||||
else
|
else
|
||||||
self.set("height", #wrapText(self.get("text"), self.get("width")))
|
self.set("height", #wrapText(self.getResolved("text"), self.getResolved("width")))
|
||||||
end
|
end
|
||||||
return value
|
return value
|
||||||
end})
|
end})
|
||||||
@@ -61,8 +61,8 @@ end
|
|||||||
--- @shortDescription Gets the wrapped lines of the Label
|
--- @shortDescription Gets the wrapped lines of the Label
|
||||||
--- @return table wrappedText The wrapped lines of the Label
|
--- @return table wrappedText The wrapped lines of the Label
|
||||||
function Label:getWrappedText()
|
function Label:getWrappedText()
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local wrappedText = wrapText(text, self.get("width"))
|
local wrappedText = wrapText(text, self.getResolved("width"))
|
||||||
return wrappedText
|
return wrappedText
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -70,13 +70,13 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Label:render()
|
function Label:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
if(self.get("autoSize"))then
|
if(self.getResolved("autoSize"))then
|
||||||
self:textFg(1, 1, text, self.get("foreground"))
|
self:textFg(1, 1, text, self.getResolved("foreground"))
|
||||||
else
|
else
|
||||||
local wrappedText = wrapText(text, self.get("width"))
|
local wrappedText = wrapText(text, self.getResolved("width"))
|
||||||
for i, line in ipairs(wrappedText) do
|
for i, line in ipairs(wrappedText) do
|
||||||
self:textFg(1, i, line, self.get("foreground"))
|
self:textFg(1, i, line, self.getResolved("foreground"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ local function drawLine(self, x1, y1, x2, y2, symbol, bgColor, fgColor)
|
|||||||
local t = steps == 0 and 0 or i / steps
|
local t = steps == 0 and 0 or i / steps
|
||||||
local x = math.floor(x1 + dx * t)
|
local x = math.floor(x1 + dx * t)
|
||||||
local y = math.floor(y1 + dy * t)
|
local y = math.floor(y1 + dy * t)
|
||||||
if x >= 1 and x <= self.get("width") and y >= 1 and y <= self.get("height") then
|
if x >= 1 and x <= self.getResolved("width") and y >= 1 and y <= self.getResolved("height") then
|
||||||
self:blit(x, y, symbol, tHex[bgColor], tHex[fgColor])
|
self:blit(x, y, symbol, tHex[bgColor], tHex[fgColor])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -64,11 +64,11 @@ end
|
|||||||
function LineChart:render()
|
function LineChart:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local minVal = self.get("minValue")
|
local minVal = self.getResolved("minValue")
|
||||||
local maxVal = self.get("maxValue")
|
local maxVal = self.getResolved("maxValue")
|
||||||
local series = self.get("series")
|
local series = self.getResolved("series")
|
||||||
|
|
||||||
for _, s in pairs(series) do
|
for _, s in pairs(series) do
|
||||||
if(s.visible)then
|
if(s.visible)then
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ List.defineProperty(List, "offset", {
|
|||||||
type = "number",
|
type = "number",
|
||||||
canTriggerRender = true,
|
canTriggerRender = true,
|
||||||
setter = function(self, value)
|
setter = function(self, value)
|
||||||
local maxOffset = math.max(0, #self.get("items") - self.get("height"))
|
local maxOffset = math.max(0, #self.getResolved("items") - self.getResolved("height"))
|
||||||
return math.min(maxOffset, math.max(0, value))
|
return math.min(maxOffset, math.max(0, value))
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
@@ -86,15 +86,15 @@ function List:init(props, basalt)
|
|||||||
self.set("type", "List")
|
self.set("type", "List")
|
||||||
|
|
||||||
self:observe("items", function()
|
self:observe("items", function()
|
||||||
local maxOffset = math.max(0, #self.get("items") - self.get("height"))
|
local maxOffset = math.max(0, #self.getResolved("items") - self.getResolved("height"))
|
||||||
if self.get("offset") > maxOffset then
|
if self.getResolved("offset") > maxOffset then
|
||||||
self.set("offset", maxOffset)
|
self.set("offset", maxOffset)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
self:observe("height", function()
|
self:observe("height", function()
|
||||||
local maxOffset = math.max(0, #self.get("items") - self.get("height"))
|
local maxOffset = math.max(0, #self.getResolved("items") - self.getResolved("height"))
|
||||||
if self.get("offset") > maxOffset then
|
if self.getResolved("offset") > maxOffset then
|
||||||
self.set("offset", maxOffset)
|
self.set("offset", maxOffset)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -111,16 +111,16 @@ end
|
|||||||
function List:mouse_click(button, x, y)
|
function List:mouse_click(button, x, y)
|
||||||
if Collection.mouse_click(self, button, x, y) then
|
if Collection.mouse_click(self, button, x, y) then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
|
|
||||||
if showScrollBar and #items > height and relX == width then
|
if showScrollBar and #items > height and relX == width then
|
||||||
local maxOffset = #items - height
|
local maxOffset = #items - height
|
||||||
local handleSize = math.max(1, math.floor((height / #items) * height))
|
local handleSize = math.max(1, math.floor((height / #items) * height))
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (self.get("offset") / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (self.getResolved("offset") / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (height - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (height - handleSize)) + 1
|
||||||
|
|
||||||
if relY >= handlePos and relY < handlePos + handleSize then
|
if relY >= handlePos and relY < handlePos + handleSize then
|
||||||
@@ -134,12 +134,12 @@ function List:mouse_click(button, x, y)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.get("selectable") then
|
if self.getResolved("selectable") then
|
||||||
local adjustedIndex = relY + self.get("offset")
|
local adjustedIndex = relY + self.getResolved("offset")
|
||||||
|
|
||||||
if adjustedIndex <= #items then
|
if adjustedIndex <= #items then
|
||||||
local item = items[adjustedIndex]
|
local item = items[adjustedIndex]
|
||||||
if not self.get("multiSelection") then
|
if not self.getResolved("multiSelection") then
|
||||||
for _, otherItem in ipairs(items) do
|
for _, otherItem in ipairs(items) do
|
||||||
if type(otherItem) == "table" then
|
if type(otherItem) == "table" then
|
||||||
otherItem.selected = false
|
otherItem.selected = false
|
||||||
@@ -170,8 +170,8 @@ end
|
|||||||
function List:mouse_drag(button, x, y)
|
function List:mouse_drag(button, x, y)
|
||||||
if self._scrollBarDragging then
|
if self._scrollBarDragging then
|
||||||
local _, relY = self:getRelativePosition(x, y)
|
local _, relY = self:getRelativePosition(x, y)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local handleSize = math.max(1, math.floor((height / #items) * height))
|
local handleSize = math.max(1, math.floor((height / #items) * height))
|
||||||
local maxOffset = #items - height
|
local maxOffset = #items - height
|
||||||
relY = math.max(1, math.min(height, relY))
|
relY = math.max(1, math.min(height, relY))
|
||||||
@@ -209,8 +209,8 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function List:mouse_scroll(direction, x, y)
|
function List:mouse_scroll(direction, x, y)
|
||||||
if Collection.mouse_scroll(self, direction, x, y) then
|
if Collection.mouse_scroll(self, direction, x, y) then
|
||||||
local offset = self.get("offset")
|
local offset = self.getResolved("offset")
|
||||||
local maxOffset = math.max(0, #self.get("items") - self.get("height"))
|
local maxOffset = math.max(0, #self.getResolved("items") - self.getResolved("height"))
|
||||||
|
|
||||||
offset = math.min(maxOffset, math.max(0, offset + direction))
|
offset = math.min(maxOffset, math.max(0, offset + direction))
|
||||||
self.set("offset", offset)
|
self.set("offset", offset)
|
||||||
@@ -233,7 +233,7 @@ end
|
|||||||
--- @shortDescription Scrolls the list to the bottom
|
--- @shortDescription Scrolls the list to the bottom
|
||||||
--- @return List self The List instance
|
--- @return List self The List instance
|
||||||
function List:scrollToBottom()
|
function List:scrollToBottom()
|
||||||
local maxOffset = math.max(0, #self.get("items") - self.get("height"))
|
local maxOffset = math.max(0, #self.getResolved("items") - self.getResolved("height"))
|
||||||
self.set("offset", maxOffset)
|
self.set("offset", maxOffset)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -252,8 +252,8 @@ end
|
|||||||
--- @return List self The List instance
|
--- @return List self The List instance
|
||||||
--- @usage list:scrollToItem(5)
|
--- @usage list:scrollToItem(5)
|
||||||
function List:scrollToItem(index)
|
function List:scrollToItem(index)
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local offset = self.get("offset")
|
local offset = self.getResolved("offset")
|
||||||
|
|
||||||
if index < offset + 1 then
|
if index < offset + 1 then
|
||||||
self.set("offset", math.max(0, index - 1))
|
self.set("offset", math.max(0, index - 1))
|
||||||
@@ -270,8 +270,8 @@ end
|
|||||||
--- @return boolean Whether the event was handled
|
--- @return boolean Whether the event was handled
|
||||||
--- @protected
|
--- @protected
|
||||||
function List:key(keyCode)
|
function List:key(keyCode)
|
||||||
if Collection.key(self, keyCode) and self.get("selectable") then
|
if Collection.key(self, keyCode) and self.getResolved("selectable") then
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local currentIndex = self:getSelectedIndex()
|
local currentIndex = self:getSelectedIndex()
|
||||||
|
|
||||||
if keyCode == keys.up then
|
if keyCode == keys.up then
|
||||||
@@ -297,14 +297,14 @@ function List:key(keyCode)
|
|||||||
self:scrollToBottom()
|
self:scrollToBottom()
|
||||||
return true
|
return true
|
||||||
elseif keyCode == keys.pageUp then
|
elseif keyCode == keys.pageUp then
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local newIndex = math.max(1, (currentIndex or 1) - height)
|
local newIndex = math.max(1, (currentIndex or 1) - height)
|
||||||
self:clearItemSelection()
|
self:clearItemSelection()
|
||||||
self:selectItem(newIndex)
|
self:selectItem(newIndex)
|
||||||
self:scrollToItem(newIndex)
|
self:scrollToItem(newIndex)
|
||||||
return true
|
return true
|
||||||
elseif keyCode == keys.pageDown then
|
elseif keyCode == keys.pageDown then
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local newIndex = math.min(#items, (currentIndex or 1) + height)
|
local newIndex = math.min(#items, (currentIndex or 1) + height)
|
||||||
self:clearItemSelection()
|
self:clearItemSelection()
|
||||||
self:selectItem(newIndex)
|
self:selectItem(newIndex)
|
||||||
@@ -321,19 +321,19 @@ function List:render(vOffset)
|
|||||||
vOffset = vOffset or 0
|
vOffset = vOffset or 0
|
||||||
Collection.render(self)
|
Collection.render(self)
|
||||||
|
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local offset = self.get("offset")
|
local offset = self.getResolved("offset")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local listBg = self.getResolved("background")
|
local listBg = self.getResolved("background")
|
||||||
local listFg = self.getResolved("foreground")
|
local listFg = self.getResolved("foreground")
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
|
|
||||||
local needsScrollBar = showScrollBar and #items > height
|
local needsScrollBar = showScrollBar and #items > height
|
||||||
local contentWidth = needsScrollBar and width - 1 or width
|
local contentWidth = needsScrollBar and width - 1 or width
|
||||||
|
|
||||||
if #items == 0 then
|
if #items == 0 then
|
||||||
local emptyText = self.get("emptyText")
|
local emptyText = self.getResolved("emptyText")
|
||||||
local y = math.floor(height / 2) + vOffset
|
local y = math.floor(height / 2) + vOffset
|
||||||
local x = math.max(1, math.floor((width - #emptyText) / 2) + 1)
|
local x = math.max(1, math.floor((width - #emptyText) / 2) + 1)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Menu.defineProperty(Menu, "horizontalOffset", {
|
|||||||
type = "number",
|
type = "number",
|
||||||
canTriggerRender = true,
|
canTriggerRender = true,
|
||||||
setter = function(self, value)
|
setter = function(self, value)
|
||||||
local maxOffset = math.max(0, self:getTotalWidth() - self.get("width"))
|
local maxOffset = math.max(0, self:getTotalWidth() - self.getResolved("width"))
|
||||||
return math.min(maxOffset, math.max(0, value))
|
return math.min(maxOffset, math.max(0, value))
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
@@ -59,7 +59,7 @@ function Menu:init(props, basalt)
|
|||||||
self.set("type", "Menu")
|
self.set("type", "Menu")
|
||||||
|
|
||||||
self:observe("items", function()
|
self:observe("items", function()
|
||||||
local maxWidth = self.get("maxWidth")
|
local maxWidth = self.getResolved("maxWidth")
|
||||||
if maxWidth then
|
if maxWidth then
|
||||||
self.set("width", math.min(maxWidth, self:getTotalWidth()), true)
|
self.set("width", math.min(maxWidth, self:getTotalWidth()), true)
|
||||||
else
|
else
|
||||||
@@ -74,8 +74,8 @@ end
|
|||||||
--- @shortDescription Calculates total width of menu items
|
--- @shortDescription Calculates total width of menu items
|
||||||
--- @return number totalWidth The total width of all items
|
--- @return number totalWidth The total width of all items
|
||||||
function Menu:getTotalWidth()
|
function Menu:getTotalWidth()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local spacing = self.get("spacing")
|
local spacing = self.getResolved("spacing")
|
||||||
local totalWidth = 0
|
local totalWidth = 0
|
||||||
|
|
||||||
for i, item in ipairs(items) do
|
for i, item in ipairs(items) do
|
||||||
@@ -97,10 +97,10 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Menu:render()
|
function Menu:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local viewportWidth = self.get("width")
|
local viewportWidth = self.getResolved("width")
|
||||||
local spacing = self.get("spacing")
|
local spacing = self.getResolved("spacing")
|
||||||
local offset = self.get("horizontalOffset")
|
local offset = self.getResolved("horizontalOffset")
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
|
|
||||||
local itemPositions = {}
|
local itemPositions = {}
|
||||||
local currentX = 1
|
local currentX = 1
|
||||||
@@ -143,13 +143,13 @@ function Menu:render()
|
|||||||
|
|
||||||
if #visibleText > 0 then
|
if #visibleText > 0 then
|
||||||
local isSelected = item.selected
|
local isSelected = item.selected
|
||||||
local fg = item.selectable == false and self.get("separatorColor") or
|
local fg = item.selectable == false and self.getResolved("separatorColor") or
|
||||||
(isSelected and (item.selectedForeground or self.get("selectedForeground")) or
|
(isSelected and (item.selectedForeground or self.getResolved("selectedForeground")) or
|
||||||
(item.foreground or self.get("foreground")))
|
(item.foreground or self.getResolved("foreground")))
|
||||||
|
|
||||||
local bg = isSelected and
|
local bg = isSelected and
|
||||||
(item.selectedBackground or self.get("selectedBackground")) or
|
(item.selectedBackground or self.getResolved("selectedBackground")) or
|
||||||
(item.background or self.get("background"))
|
(item.background or self.getResolved("background"))
|
||||||
|
|
||||||
self:blit(visibleStart, 1, visibleText,
|
self:blit(visibleStart, 1, visibleText,
|
||||||
string.rep(tHex[fg], #visibleText),
|
string.rep(tHex[fg], #visibleText),
|
||||||
@@ -168,8 +168,8 @@ function Menu:render()
|
|||||||
if spacingWidth > 0 then
|
if spacingWidth > 0 then
|
||||||
local spacingText = string.rep(" ", spacingWidth)
|
local spacingText = string.rep(" ", spacingWidth)
|
||||||
self:blit(visibleSpacingStart, 1, spacingText,
|
self:blit(visibleSpacingStart, 1, spacingText,
|
||||||
string.rep(tHex[self.get("foreground")], spacingWidth),
|
string.rep(tHex[self.getResolved("foreground")], spacingWidth),
|
||||||
string.rep(tHex[self.get("background")], spacingWidth))
|
string.rep(tHex[self.getResolved("background")], spacingWidth))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -181,11 +181,11 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Menu:mouse_click(button, x, y)
|
function Menu:mouse_click(button, x, y)
|
||||||
if not VisualElement.mouse_click(self, button, x, y) then return false end
|
if not VisualElement.mouse_click(self, button, x, y) then return false end
|
||||||
if(self.get("selectable") == false) then return false end
|
if(self.getResolved("selectable") == false) then return false end
|
||||||
local relX = select(1, self:getRelativePosition(x, y))
|
local relX = select(1, self:getRelativePosition(x, y))
|
||||||
local offset = self.get("horizontalOffset")
|
local offset = self.getResolved("horizontalOffset")
|
||||||
local spacing = self.get("spacing")
|
local spacing = self.getResolved("spacing")
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
|
|
||||||
local virtualX = relX + offset
|
local virtualX = relX + offset
|
||||||
local currentX = 1
|
local currentX = 1
|
||||||
@@ -200,7 +200,7 @@ function Menu:mouse_click(button, x, y)
|
|||||||
items[i] = item
|
items[i] = item
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("multiSelection") then
|
if not self.getResolved("multiSelection") then
|
||||||
for _, otherItem in ipairs(items) do
|
for _, otherItem in ipairs(items) do
|
||||||
if type(otherItem) == "table" then
|
if type(otherItem) == "table" then
|
||||||
otherItem.selected = false
|
otherItem.selected = false
|
||||||
@@ -230,8 +230,8 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Menu:mouse_scroll(direction, x, y)
|
function Menu:mouse_scroll(direction, x, y)
|
||||||
if VisualElement.mouse_scroll(self, direction, x, y) then
|
if VisualElement.mouse_scroll(self, direction, x, y) then
|
||||||
local offset = self.get("horizontalOffset")
|
local offset = self.getResolved("horizontalOffset")
|
||||||
local maxOffset = math.max(0, self:getTotalWidth() - self.get("width"))
|
local maxOffset = math.max(0, self:getTotalWidth() - self.getResolved("width"))
|
||||||
|
|
||||||
offset = math.min(maxOffset, math.max(0, offset + (direction * 3)))
|
offset = math.min(maxOffset, math.max(0, offset + (direction * 3)))
|
||||||
self.set("horizontalOffset", offset)
|
self.set("horizontalOffset", offset)
|
||||||
|
|||||||
@@ -254,15 +254,15 @@ function Program:init(props, basalt)
|
|||||||
VisualElement.init(self, props, basalt)
|
VisualElement.init(self, props, basalt)
|
||||||
self.set("type", "Program")
|
self.set("type", "Program")
|
||||||
self:observe("width", function(self, width)
|
self:observe("width", function(self, width)
|
||||||
local program = self.get("program")
|
local program = self.getResolved("program")
|
||||||
if program then
|
if program then
|
||||||
program:resize(width, self.get("height"))
|
program:resize(width, self.getResolved("height"))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
self:observe("height", function(self, height)
|
self:observe("height", function(self, height)
|
||||||
local program = self.get("program")
|
local program = self.getResolved("program")
|
||||||
if program then
|
if program then
|
||||||
program:resize(self.get("width"), height)
|
program:resize(self.getResolved("width"), height)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
return self
|
return self
|
||||||
@@ -280,7 +280,7 @@ function Program:execute(path, env, addEnvironment, ...)
|
|||||||
local program = BasaltProgram.new(self, env, addEnvironment)
|
local program = BasaltProgram.new(self, env, addEnvironment)
|
||||||
self.set("program", program)
|
self.set("program", program)
|
||||||
program:setArgs(...)
|
program:setArgs(...)
|
||||||
program:run(path, self.get("width"), self.get("height"), ...)
|
program:run(path, self.getResolved("width"), self.getResolved("height"), ...)
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -289,7 +289,7 @@ end
|
|||||||
--- @shortDescription Stops the program
|
--- @shortDescription Stops the program
|
||||||
--- @return Program self The Program instance
|
--- @return Program self The Program instance
|
||||||
function Program:stop()
|
function Program:stop()
|
||||||
local program = self.get("program")
|
local program = self.getResolved("program")
|
||||||
if program then
|
if program then
|
||||||
program:stop()
|
program:stop()
|
||||||
self.set("running", false)
|
self.set("running", false)
|
||||||
@@ -332,7 +332,7 @@ end
|
|||||||
--- @return any result The event result
|
--- @return any result The event result
|
||||||
--- @protected
|
--- @protected
|
||||||
function Program:dispatchEvent(event, ...)
|
function Program:dispatchEvent(event, ...)
|
||||||
local program = self.get("program")
|
local program = self.getResolved("program")
|
||||||
local result = VisualElement.dispatchEvent(self, event, ...)
|
local result = VisualElement.dispatchEvent(self, event, ...)
|
||||||
if program then
|
if program then
|
||||||
program:resume(event, ...)
|
program:resume(event, ...)
|
||||||
@@ -350,7 +350,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Program:focus()
|
function Program:focus()
|
||||||
if(VisualElement.focus(self))then
|
if(VisualElement.focus(self))then
|
||||||
local program = self.get("program")
|
local program = self.getResolved("program")
|
||||||
if program then
|
if program then
|
||||||
local cursorBlink = program.window.getCursorBlink()
|
local cursorBlink = program.window.getCursorBlink()
|
||||||
local cursorX, cursorY = program.window.getCursorPos()
|
local cursorX, cursorY = program.window.getCursorPos()
|
||||||
@@ -363,7 +363,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Program:render()
|
function Program:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local program = self.get("program")
|
local program = self.getResolved("program")
|
||||||
if program then
|
if program then
|
||||||
local _, height = program.window.getSize()
|
local _, height = program.window.getSize()
|
||||||
for y = 1, height do
|
for y = 1, height do
|
||||||
|
|||||||
@@ -47,29 +47,30 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function ProgressBar:render()
|
function ProgressBar:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local progress = math.min(100, math.max(0, self.get("progress")))
|
local progress = math.min(100, math.max(0, self.getResolved("progress")))
|
||||||
local fillWidth = math.floor((width * progress) / 100)
|
local fillWidth = math.floor((width * progress) / 100)
|
||||||
local fillHeight = math.floor((height * progress) / 100)
|
local fillHeight = math.floor((height * progress) / 100)
|
||||||
local direction = self.get("direction")
|
local direction = self.getResolved("direction")
|
||||||
local progressColor = self.get("progressColor")
|
local progressColor = self.getResolved("progressColor")
|
||||||
|
local foreground = self.getResolved("foreground")
|
||||||
|
|
||||||
if direction == "right" then
|
if direction == "right" then
|
||||||
self:multiBlit(1, 1, fillWidth, height, " ", tHex[self.get("foreground")], tHex[progressColor])
|
self:multiBlit(1, 1, fillWidth, height, " ", tHex[foreground], tHex[progressColor])
|
||||||
elseif direction == "left" then
|
elseif direction == "left" then
|
||||||
self:multiBlit(width - fillWidth + 1, 1, fillWidth, height, " ", tHex[self.get("foreground")], tHex[progressColor])
|
self:multiBlit(width - fillWidth + 1, 1, fillWidth, height, " ", tHex[foreground], tHex[progressColor])
|
||||||
elseif direction == "up" then
|
elseif direction == "up" then
|
||||||
self:multiBlit(1, height - fillHeight + 1, width, fillHeight, " ", tHex[self.get("foreground")], tHex[progressColor])
|
self:multiBlit(1, height - fillHeight + 1, width, fillHeight, " ", tHex[foreground], tHex[progressColor])
|
||||||
elseif direction == "down" then
|
elseif direction == "down" then
|
||||||
self:multiBlit(1, 1, width, fillHeight, " ", tHex[self.get("foreground")], tHex[progressColor])
|
self:multiBlit(1, 1, width, fillHeight, " ", tHex[foreground], tHex[progressColor])
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.get("showPercentage") then
|
if self.getResolved("showPercentage") then
|
||||||
local text = tostring(progress).."%"
|
local text = tostring(progress).."%"
|
||||||
local x = math.floor((width - #text) / 2) + 1
|
local x = math.floor((width - #text) / 2) + 1
|
||||||
local y = math.floor((height - 1) / 2) + 1
|
local y = math.floor((height - 1) / 2) + 1
|
||||||
self:textFg(x, y, text, self.get("foreground"))
|
self:textFg(x, y, text, foreground)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -80,8 +80,8 @@ function ScrollBar:attach(element, config)
|
|||||||
self.set("maxValue", config.max or 100)
|
self.set("maxValue", config.max or 100)
|
||||||
element:observe(config.property, function(_, value)
|
element:observe(config.property, function(_, value)
|
||||||
if value then
|
if value then
|
||||||
local min = self.get("minValue")
|
local min = self.getResolved("minValue")
|
||||||
local max = self.get("maxValue")
|
local max = self.getResolved("maxValue")
|
||||||
if min == max then return end
|
if min == max then return end
|
||||||
|
|
||||||
self.set("value", math.floor(
|
self.set("value", math.floor(
|
||||||
@@ -96,28 +96,28 @@ end
|
|||||||
--- @shortDescription Updates the attached element's property based on the ScrollBar value
|
--- @shortDescription Updates the attached element's property based on the ScrollBar value
|
||||||
--- @return ScrollBar self The ScrollBar instance
|
--- @return ScrollBar self The ScrollBar instance
|
||||||
function ScrollBar:updateAttachedElement()
|
function ScrollBar:updateAttachedElement()
|
||||||
local element = self.get("attachedElement")
|
local element = self.getResolved("attachedElement")
|
||||||
if not element then return end
|
if not element then return end
|
||||||
|
|
||||||
local value = self.get("value")
|
local value = self.getResolved("value")
|
||||||
local min = self.get("minValue")
|
local min = self.getResolved("minValue")
|
||||||
local max = self.get("maxValue")
|
local max = self.getResolved("maxValue")
|
||||||
|
|
||||||
if type(min) == "function" then min = min() end
|
if type(min) == "function" then min = min() end
|
||||||
if type(max) == "function" then max = max() end
|
if type(max) == "function" then max = max() end
|
||||||
|
|
||||||
local mappedValue = min + (value / 100) * (max - min)
|
local mappedValue = min + (value / 100) * (max - min)
|
||||||
element.set(self.get("attachedProperty"), math.floor(mappedValue + 0.5))
|
element.set(self.getResolved("attachedProperty"), math.floor(mappedValue + 0.5))
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getScrollbarSize(self)
|
local function getScrollbarSize(self)
|
||||||
return self.get("orientation") == "vertical" and self.get("height") or self.get("width")
|
return self.getResolved("orientation") == "vertical" and self.getResolved("height") or self.getResolved("width")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getRelativeScrollPosition(self, x, y)
|
local function getRelativeScrollPosition(self, x, y)
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
return self.get("orientation") == "vertical" and relY or relX
|
return self.getResolved("orientation") == "vertical" and relY or relX
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @shortDescription Handles mouse click events
|
--- @shortDescription Handles mouse click events
|
||||||
@@ -129,8 +129,8 @@ end
|
|||||||
function ScrollBar:mouse_click(button, x, y)
|
function ScrollBar:mouse_click(button, x, y)
|
||||||
if VisualElement.mouse_click(self, button, x, y) then
|
if VisualElement.mouse_click(self, button, x, y) then
|
||||||
local size = getScrollbarSize(self)
|
local size = getScrollbarSize(self)
|
||||||
local value = self.get("value")
|
local value = self.getResolved("value")
|
||||||
local handleSize = self.get("handleSize")
|
local handleSize = self.getResolved("handleSize")
|
||||||
|
|
||||||
local handlePos = math.floor((value / 100) * (size - handleSize)) + 1
|
local handlePos = math.floor((value / 100) * (size - handleSize)) + 1
|
||||||
local relPos = getRelativeScrollPosition(self, x, y)
|
local relPos = getRelativeScrollPosition(self, x, y)
|
||||||
@@ -155,8 +155,8 @@ end
|
|||||||
function ScrollBar:mouse_drag(button, x, y)
|
function ScrollBar:mouse_drag(button, x, y)
|
||||||
if(VisualElement.mouse_drag(self, button, x, y))then
|
if(VisualElement.mouse_drag(self, button, x, y))then
|
||||||
local size = getScrollbarSize(self)
|
local size = getScrollbarSize(self)
|
||||||
local handleSize = self.get("handleSize")
|
local handleSize = self.getResolved("handleSize")
|
||||||
local dragMultiplier = self.get("dragMultiplier")
|
local dragMultiplier = self.getResolved("dragMultiplier")
|
||||||
local relPos = getRelativeScrollPosition(self, x, y)
|
local relPos = getRelativeScrollPosition(self, x, y)
|
||||||
|
|
||||||
relPos = math.max(1, math.min(size, relPos))
|
relPos = math.max(1, math.min(size, relPos))
|
||||||
@@ -179,8 +179,8 @@ end
|
|||||||
function ScrollBar:mouse_scroll(direction, x, y)
|
function ScrollBar:mouse_scroll(direction, x, y)
|
||||||
if not self:isInBounds(x, y) then return false end
|
if not self:isInBounds(x, y) then return false end
|
||||||
direction = direction > 0 and -1 or 1
|
direction = direction > 0 and -1 or 1
|
||||||
local step = self.get("step")
|
local step = self.getResolved("step")
|
||||||
local currentValue = self.get("value")
|
local currentValue = self.getResolved("value")
|
||||||
local newValue = currentValue - direction * step
|
local newValue = currentValue - direction * step
|
||||||
|
|
||||||
self.set("value", math.min(100, math.max(0, newValue)))
|
self.set("value", math.min(100, math.max(0, newValue)))
|
||||||
@@ -194,21 +194,23 @@ function ScrollBar:render()
|
|||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local size = getScrollbarSize(self)
|
local size = getScrollbarSize(self)
|
||||||
local value = self.get("value")
|
local value = self.getResolved("value")
|
||||||
local handleSize = self.get("handleSize")
|
local handleSize = self.getResolved("handleSize")
|
||||||
local symbol = self.get("symbol")
|
local symbol = self.getResolved("symbol")
|
||||||
local symbolColor = self.get("symbolColor")
|
local symbolColor = self.getResolved("symbolColor")
|
||||||
local symbolBackgroundColor = self.get("symbolBackgroundColor")
|
local symbolBackgroundColor = self.getResolved("symbolBackgroundColor")
|
||||||
local bgSymbol = self.get("backgroundSymbol")
|
local bgSymbol = self.getResolved("backgroundSymbol")
|
||||||
local isVertical = self.get("orientation") == "vertical"
|
local isVertical = self.getResolved("orientation") == "vertical"
|
||||||
|
local foreground = self.getResolved("foreground")
|
||||||
|
local background = self.getResolved("background")
|
||||||
|
|
||||||
local handlePos = math.floor((value / 100) * (size - handleSize)) + 1
|
local handlePos = math.floor((value / 100) * (size - handleSize)) + 1
|
||||||
|
|
||||||
for i = 1, size do
|
for i = 1, size do
|
||||||
if isVertical then
|
if isVertical then
|
||||||
self:blit(1, i, bgSymbol, tHex[self.get("foreground")], tHex[self.get("background")])
|
self:blit(1, i, bgSymbol, tHex[foreground], tHex[background])
|
||||||
else
|
else
|
||||||
self:blit(i, 1, bgSymbol, tHex[self.get("foreground")], tHex[self.get("background")])
|
self:blit(i, 1, bgSymbol, tHex[foreground], tHex[background])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ ScrollFrame.defineProperty(ScrollFrame, "contentWidth", {
|
|||||||
type = "number",
|
type = "number",
|
||||||
getter = function(self)
|
getter = function(self)
|
||||||
local maxWidth = 0
|
local maxWidth = 0
|
||||||
local children = self.get("children")
|
local children = self.getResolved("children")
|
||||||
for _, child in ipairs(children) do
|
for _, child in ipairs(children) do
|
||||||
local childX = child.get("x")
|
local childX = child.get("x")
|
||||||
local childWidth = child.get("width")
|
local childWidth = child.get("width")
|
||||||
@@ -129,7 +129,7 @@ ScrollFrame.defineProperty(ScrollFrame, "contentHeight", {
|
|||||||
type = "number",
|
type = "number",
|
||||||
getter = function(self)
|
getter = function(self)
|
||||||
local maxHeight = 0
|
local maxHeight = 0
|
||||||
local children = self.get("children")
|
local children = self.getResolved("children")
|
||||||
for _, child in ipairs(children) do
|
for _, child in ipairs(children) do
|
||||||
local childY = child.get("y")
|
local childY = child.get("y")
|
||||||
local childHeight = child.get("height")
|
local childHeight = child.get("height")
|
||||||
@@ -182,11 +182,11 @@ end
|
|||||||
function ScrollFrame:mouse_click(button, x, y)
|
function ScrollFrame:mouse_click(button, x, y)
|
||||||
if Container.mouse_click(self, button, x, y) then
|
if Container.mouse_click(self, button, x, y) then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
local contentWidth = self.get("contentWidth")
|
local contentWidth = self.getResolved("contentWidth")
|
||||||
local contentHeight = self.get("contentHeight")
|
local contentHeight = self.getResolved("contentHeight")
|
||||||
local needsHorizontalScrollBar = showScrollBar and contentWidth > width
|
local needsHorizontalScrollBar = showScrollBar and contentWidth > width
|
||||||
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local needsVerticalScrollBar = showScrollBar and contentHeight > viewportHeight
|
local needsVerticalScrollBar = showScrollBar and contentHeight > viewportHeight
|
||||||
@@ -197,7 +197,7 @@ function ScrollFrame:mouse_click(button, x, y)
|
|||||||
local handleSize = math.max(1, math.floor((viewportHeight / contentHeight) * scrollHeight))
|
local handleSize = math.max(1, math.floor((viewportHeight / contentHeight) * scrollHeight))
|
||||||
local maxOffset = contentHeight - viewportHeight
|
local maxOffset = contentHeight - viewportHeight
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (self.get("offsetY") / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (self.getResolved("offsetY") / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (scrollHeight - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (scrollHeight - handleSize)) + 1
|
||||||
|
|
||||||
if relY >= handlePos and relY < handlePos + handleSize then
|
if relY >= handlePos and relY < handlePos + handleSize then
|
||||||
@@ -216,7 +216,7 @@ function ScrollFrame:mouse_click(button, x, y)
|
|||||||
local handleSize = math.max(1, math.floor((viewportWidth / contentWidth) * scrollWidth))
|
local handleSize = math.max(1, math.floor((viewportWidth / contentWidth) * scrollWidth))
|
||||||
local maxOffset = contentWidth - viewportWidth
|
local maxOffset = contentWidth - viewportWidth
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (self.get("offsetX") / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (self.getResolved("offsetX") / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (scrollWidth - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (scrollWidth - handleSize)) + 1
|
||||||
|
|
||||||
if relX >= handlePos and relX < handlePos + handleSize then
|
if relX >= handlePos and relX < handlePos + handleSize then
|
||||||
@@ -245,11 +245,11 @@ end
|
|||||||
function ScrollFrame:mouse_drag(button, x, y)
|
function ScrollFrame:mouse_drag(button, x, y)
|
||||||
if self._scrollBarDragging then
|
if self._scrollBarDragging then
|
||||||
local _, relY = self:getRelativePosition(x, y)
|
local _, relY = self:getRelativePosition(x, y)
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local contentWidth = self.get("contentWidth")
|
local contentWidth = self.getResolved("contentWidth")
|
||||||
local contentHeight = self.get("contentHeight")
|
local contentHeight = self.getResolved("contentHeight")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local needsHorizontalScrollBar = self.get("showScrollBar") and contentWidth > width
|
local needsHorizontalScrollBar = self.getResolved("showScrollBar") and contentWidth > width
|
||||||
|
|
||||||
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local scrollHeight = viewportHeight
|
local scrollHeight = viewportHeight
|
||||||
@@ -268,13 +268,13 @@ function ScrollFrame:mouse_drag(button, x, y)
|
|||||||
|
|
||||||
if self._hScrollBarDragging then
|
if self._hScrollBarDragging then
|
||||||
local relX, _ = self:getRelativePosition(x, y)
|
local relX, _ = self:getRelativePosition(x, y)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local contentWidth = self.get("contentWidth")
|
local contentWidth = self.getResolved("contentWidth")
|
||||||
local contentHeight = self.get("contentHeight")
|
local contentHeight = self.getResolved("contentHeight")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local needsHorizontalScrollBar = self.get("showScrollBar") and contentWidth > width
|
local needsHorizontalScrollBar = self.getResolved("showScrollBar") and contentWidth > width
|
||||||
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local needsVerticalScrollBar = self.get("showScrollBar") and contentHeight > viewportHeight
|
local needsVerticalScrollBar = self.getResolved("showScrollBar") and contentHeight > viewportHeight
|
||||||
local viewportWidth = needsVerticalScrollBar and width - 1 or width
|
local viewportWidth = needsVerticalScrollBar and width - 1 or width
|
||||||
local scrollWidth = viewportWidth
|
local scrollWidth = viewportWidth
|
||||||
local handleSize = math.max(1, math.floor((viewportWidth / contentWidth) * scrollWidth))
|
local handleSize = math.max(1, math.floor((viewportWidth / contentWidth) * scrollWidth))
|
||||||
@@ -325,7 +325,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function ScrollFrame:mouse_scroll(direction, x, y)
|
function ScrollFrame:mouse_scroll(direction, x, y)
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
local xOffset, yOffset = self.get("offsetX"), self.get("offsetY")
|
local xOffset, yOffset = self.getResolved("offsetX"), self.getResolved("offsetY")
|
||||||
local relX, relY = self:getRelativePosition(x + xOffset, y + yOffset)
|
local relX, relY = self:getRelativePosition(x + xOffset, y + yOffset)
|
||||||
|
|
||||||
local success, child = self:callChildrenEvent(true, "mouse_scroll", direction, relX, relY)
|
local success, child = self:callChildrenEvent(true, "mouse_scroll", direction, relX, relY)
|
||||||
@@ -333,16 +333,16 @@ function ScrollFrame:mouse_scroll(direction, x, y)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local offsetY = self.get("offsetY")
|
local offsetY = self.getResolved("offsetY")
|
||||||
local offsetX = self.get("offsetX")
|
local offsetX = self.getResolved("offsetX")
|
||||||
local contentWidth = self.get("contentWidth")
|
local contentWidth = self.getResolved("contentWidth")
|
||||||
local contentHeight = self.get("contentHeight")
|
local contentHeight = self.getResolved("contentHeight")
|
||||||
|
|
||||||
local needsHorizontalScrollBar = self.get("showScrollBar") and contentWidth > width
|
local needsHorizontalScrollBar = self.getResolved("showScrollBar") and contentWidth > width
|
||||||
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local needsVerticalScrollBar = self.get("showScrollBar") and contentHeight > viewportHeight
|
local needsVerticalScrollBar = self.getResolved("showScrollBar") and contentHeight > viewportHeight
|
||||||
local viewportWidth = needsVerticalScrollBar and width - 1 or width
|
local viewportWidth = needsVerticalScrollBar and width - 1 or width
|
||||||
|
|
||||||
if needsVerticalScrollBar then
|
if needsVerticalScrollBar then
|
||||||
@@ -366,13 +366,13 @@ end
|
|||||||
function ScrollFrame:render()
|
function ScrollFrame:render()
|
||||||
Container.render(self)
|
Container.render(self)
|
||||||
|
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local offsetY = self.get("offsetY")
|
local offsetY = self.getResolved("offsetY")
|
||||||
local offsetX = self.get("offsetX")
|
local offsetX = self.getResolved("offsetX")
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
local contentWidth = self.get("contentWidth")
|
local contentWidth = self.getResolved("contentWidth")
|
||||||
local contentHeight = self.get("contentHeight")
|
local contentHeight = self.getResolved("contentHeight")
|
||||||
local needsHorizontalScrollBar = showScrollBar and contentWidth > width
|
local needsHorizontalScrollBar = showScrollBar and contentWidth > width
|
||||||
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
local viewportHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local needsVerticalScrollBar = showScrollBar and contentHeight > viewportHeight
|
local needsVerticalScrollBar = showScrollBar and contentHeight > viewportHeight
|
||||||
@@ -382,10 +382,10 @@ function ScrollFrame:render()
|
|||||||
local scrollHeight = viewportHeight
|
local scrollHeight = viewportHeight
|
||||||
local handleSize = math.max(1, math.floor((viewportHeight / contentHeight) * scrollHeight))
|
local handleSize = math.max(1, math.floor((viewportHeight / contentHeight) * scrollHeight))
|
||||||
local maxOffset = contentHeight - viewportHeight
|
local maxOffset = contentHeight - viewportHeight
|
||||||
local scrollBarBg = self.get("scrollBarBackgroundSymbol")
|
local scrollBarBg = self.getResolved("scrollBarBackgroundSymbol")
|
||||||
local scrollBarColor = self.get("scrollBarColor")
|
local scrollBarColor = self.getResolved("scrollBarColor")
|
||||||
local scrollBarBgColor = self.get("scrollBarBackgroundColor")
|
local scrollBarBgColor = self.getResolved("scrollBarBackgroundColor")
|
||||||
local scrollBarBg2Color = self.get("scrollBarBackgroundColor2")
|
local scrollBarBg2Color = self.getResolved("scrollBarBackgroundColor2")
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (offsetY / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (offsetY / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (scrollHeight - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (scrollHeight - handleSize)) + 1
|
||||||
@@ -403,10 +403,10 @@ function ScrollFrame:render()
|
|||||||
local scrollWidth = viewportWidth
|
local scrollWidth = viewportWidth
|
||||||
local handleSize = math.max(1, math.floor((viewportWidth / contentWidth) * scrollWidth))
|
local handleSize = math.max(1, math.floor((viewportWidth / contentWidth) * scrollWidth))
|
||||||
local maxOffset = contentWidth - viewportWidth
|
local maxOffset = contentWidth - viewportWidth
|
||||||
local scrollBarBg = self.get("scrollBarBackgroundSymbol")
|
local scrollBarBg = self.getResolved("scrollBarBackgroundSymbol")
|
||||||
local scrollBarColor = self.get("scrollBarColor")
|
local scrollBarColor = self.getResolved("scrollBarColor")
|
||||||
local scrollBarBgColor = self.get("scrollBarBackgroundColor")
|
local scrollBarBgColor = self.getResolved("scrollBarBackgroundColor")
|
||||||
local scrollBarBg2Color = self.get("scrollBarBackgroundColor2")
|
local scrollBarBg2Color = self.getResolved("scrollBarBackgroundColor2")
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (offsetX / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (offsetX / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (scrollWidth - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (scrollWidth - handleSize)) + 1
|
||||||
@@ -421,7 +421,7 @@ function ScrollFrame:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if needsVerticalScrollBar and needsHorizontalScrollBar then
|
if needsVerticalScrollBar and needsHorizontalScrollBar then
|
||||||
local background = self.get("background")
|
local background = self.getResolved("background")
|
||||||
self:blit(width, height, " ", tHex[background], tHex[background])
|
self:blit(width, height, " ", tHex[background], tHex[background])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ end
|
|||||||
--- @param title string The title of the navigation item
|
--- @param title string The title of the navigation item
|
||||||
--- @return table tabHandler The navigation item handler proxy for adding elements
|
--- @return table tabHandler The navigation item handler proxy for adding elements
|
||||||
function SideNav:newTab(title)
|
function SideNav:newTab(title)
|
||||||
local tabs = self.get("tabs") or {}
|
local tabs = self.getResolved("tabs") or {}
|
||||||
local tabId = #tabs + 1
|
local tabId = #tabs + 1
|
||||||
|
|
||||||
table.insert(tabs, {
|
table.insert(tabs, {
|
||||||
@@ -164,7 +164,7 @@ function SideNav:newTab(title)
|
|||||||
|
|
||||||
self.set("tabs", tabs)
|
self.set("tabs", tabs)
|
||||||
|
|
||||||
if not self.get("activeTab") then
|
if not self.getResolved("activeTab") then
|
||||||
self.set("activeTab", tabId)
|
self.set("activeTab", tabId)
|
||||||
end
|
end
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -215,7 +215,7 @@ end
|
|||||||
--- @return table element The created element
|
--- @return table element The created element
|
||||||
function SideNav:addElement(elementType, tabId)
|
function SideNav:addElement(elementType, tabId)
|
||||||
local element = Container.addElement(self, elementType)
|
local element = Container.addElement(self, elementType)
|
||||||
local targetTab = tabId or self.get("activeTab")
|
local targetTab = tabId or self.getResolved("activeTab")
|
||||||
if targetTab then
|
if targetTab then
|
||||||
element._tabId = targetTab
|
element._tabId = targetTab
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -230,7 +230,7 @@ end
|
|||||||
function SideNav:addChild(child)
|
function SideNav:addChild(child)
|
||||||
Container.addChild(self, child)
|
Container.addChild(self, child)
|
||||||
if not child._tabId then
|
if not child._tabId then
|
||||||
local tabs = self.get("tabs") or {}
|
local tabs = self.getResolved("tabs") or {}
|
||||||
if #tabs > 0 then
|
if #tabs > 0 then
|
||||||
child._tabId = 1
|
child._tabId = 1
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -249,7 +249,7 @@ end
|
|||||||
--- @shortDescription Sets the active navigation item
|
--- @shortDescription Sets the active navigation item
|
||||||
--- @param tabId number The ID of the navigation item to activate
|
--- @param tabId number The ID of the navigation item to activate
|
||||||
function SideNav:setActiveTab(tabId)
|
function SideNav:setActiveTab(tabId)
|
||||||
local oldTab = self.get("activeTab")
|
local oldTab = self.getResolved("activeTab")
|
||||||
if oldTab == tabId then return self end
|
if oldTab == tabId then return self end
|
||||||
self.set("activeTab", tabId)
|
self.set("activeTab", tabId)
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -266,7 +266,7 @@ function SideNav:isChildVisible(child)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if child._tabId then
|
if child._tabId then
|
||||||
return child._tabId == self.get("activeTab")
|
return child._tabId == self.getResolved("activeTab")
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -280,11 +280,11 @@ function SideNav:getContentXOffset()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SideNav:_getSidebarMetrics()
|
function SideNav:_getSidebarMetrics()
|
||||||
local tabs = self.get("tabs") or {}
|
local tabs = self.getResolved("tabs") or {}
|
||||||
local height = self.get("height") or 1
|
local height = self.getResolved("height") or 1
|
||||||
local sidebarWidth = self.get("sidebarWidth") or 12
|
local sidebarWidth = self.getResolved("sidebarWidth") or 12
|
||||||
local scrollOffset = self.get("sidebarScrollOffset") or 0
|
local scrollOffset = self.getResolved("sidebarScrollOffset") or 0
|
||||||
local sidebarPos = self.get("sidebarPosition") or "left"
|
local sidebarPos = self.getResolved("sidebarPosition") or "left"
|
||||||
|
|
||||||
local positions = {}
|
local positions = {}
|
||||||
local actualY = 1
|
local actualY = 1
|
||||||
@@ -348,7 +348,7 @@ function SideNav:mouse_click(button, x, y)
|
|||||||
|
|
||||||
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
|
|
||||||
local inSidebar = false
|
local inSidebar = false
|
||||||
if metrics.sidebarPosition == "right" then
|
if metrics.sidebarPosition == "right" then
|
||||||
@@ -373,7 +373,7 @@ end
|
|||||||
|
|
||||||
function SideNav:getRelativePosition(x, y)
|
function SideNav:getRelativePosition(x, y)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
|
|
||||||
if x == nil or y == nil then
|
if x == nil or y == nil then
|
||||||
return VisualElement.getRelativePosition(self)
|
return VisualElement.getRelativePosition(self)
|
||||||
@@ -456,7 +456,7 @@ function SideNav:mouse_up(button, x, y)
|
|||||||
end
|
end
|
||||||
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
|
|
||||||
local inSidebar = false
|
local inSidebar = false
|
||||||
if metrics.sidebarPosition == "right" then
|
if metrics.sidebarPosition == "right" then
|
||||||
@@ -475,7 +475,7 @@ function SideNav:mouse_release(button, x, y)
|
|||||||
VisualElement.mouse_release(self, button, x, y)
|
VisualElement.mouse_release(self, button, x, y)
|
||||||
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
|
|
||||||
local inSidebar = false
|
local inSidebar = false
|
||||||
if metrics.sidebarPosition == "right" then
|
if metrics.sidebarPosition == "right" then
|
||||||
@@ -494,7 +494,7 @@ function SideNav:mouse_move(_, x, y)
|
|||||||
if VisualElement.mouse_move(self, _, x, y) then
|
if VisualElement.mouse_move(self, _, x, y) then
|
||||||
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
|
|
||||||
local inSidebar = false
|
local inSidebar = false
|
||||||
if metrics.sidebarPosition == "right" then
|
if metrics.sidebarPosition == "right" then
|
||||||
@@ -519,7 +519,7 @@ function SideNav:mouse_drag(button, x, y)
|
|||||||
if VisualElement.mouse_drag(self, button, x, y) then
|
if VisualElement.mouse_drag(self, button, x, y) then
|
||||||
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
|
|
||||||
local inSidebar = false
|
local inSidebar = false
|
||||||
if metrics.sidebarPosition == "right" then
|
if metrics.sidebarPosition == "right" then
|
||||||
@@ -542,7 +542,7 @@ end
|
|||||||
--- @return SideNav self For method chaining
|
--- @return SideNav self For method chaining
|
||||||
function SideNav:scrollSidebar(direction)
|
function SideNav:scrollSidebar(direction)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local currentOffset = self.get("sidebarScrollOffset") or 0
|
local currentOffset = self.getResolved("sidebarScrollOffset") or 0
|
||||||
local maxScroll = metrics.maxScroll or 0
|
local maxScroll = metrics.maxScroll or 0
|
||||||
|
|
||||||
local newOffset = currentOffset + (direction * 2)
|
local newOffset = currentOffset + (direction * 2)
|
||||||
@@ -556,7 +556,7 @@ function SideNav:mouse_scroll(direction, x, y)
|
|||||||
if VisualElement.mouse_scroll(self, direction, x, y) then
|
if VisualElement.mouse_scroll(self, direction, x, y) then
|
||||||
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
local baseRelX, baseRelY = VisualElement.getRelativePosition(self, x, y)
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
|
|
||||||
local inSidebar = false
|
local inSidebar = false
|
||||||
if metrics.sidebarPosition == "right" then
|
if metrics.sidebarPosition == "right" then
|
||||||
@@ -603,23 +603,25 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function SideNav:render()
|
function SideNav:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
|
local foreground = self.getResolved("foreground")
|
||||||
|
local sidebarBackground = self.getResolved("sidebarBackground")
|
||||||
local metrics = self:_getSidebarMetrics()
|
local metrics = self:_getSidebarMetrics()
|
||||||
local sidebarW = metrics.sidebarWidth or 12
|
local sidebarW = metrics.sidebarWidth or 12
|
||||||
|
|
||||||
for y = 1, height do
|
for y = 1, height do
|
||||||
VisualElement.multiBlit(self, 1, y, sidebarW, 1, " ", tHex[self.get("foreground")], tHex[self.get("sidebarBackground")])
|
VisualElement.multiBlit(self, 1, y, sidebarW, 1, " ", tHex[foreground], tHex[sidebarBackground])
|
||||||
end
|
end
|
||||||
|
|
||||||
local activeTab = self.get("activeTab")
|
local activeTab = self.getResolved("activeTab")
|
||||||
|
|
||||||
for _, pos in ipairs(metrics.positions) do
|
for _, pos in ipairs(metrics.positions) do
|
||||||
local bgColor = (pos.id == activeTab) and self.get("activeTabBackground") or self.get("sidebarBackground")
|
local bgColor = (pos.id == activeTab) and self.getResolved("activeTabBackground") or sidebarBackground
|
||||||
local fgColor = (pos.id == activeTab) and self.get("activeTabTextColor") or self.get("foreground")
|
local fgColor = (pos.id == activeTab) and self.getResolved("activeTabTextColor") or foreground
|
||||||
|
|
||||||
local itemHeight = pos.displayHeight or (pos.y2 - pos.y1 + 1)
|
local itemHeight = pos.displayHeight or (pos.y2 - pos.y1 + 1)
|
||||||
for dy = 0, itemHeight - 1 do
|
for dy = 0, itemHeight - 1 do
|
||||||
VisualElement.multiBlit(self, 1, pos.y1 + dy, sidebarW, 1, " ", tHex[self.get("foreground")], tHex[bgColor])
|
VisualElement.multiBlit(self, 1, pos.y1 + dy, sidebarW, 1, " ", tHex[foreground], tHex[bgColor])
|
||||||
end
|
end
|
||||||
|
|
||||||
local displayTitle = pos.title
|
local displayTitle = pos.title
|
||||||
@@ -630,16 +632,16 @@ function SideNav:render()
|
|||||||
VisualElement.textFg(self, 2, pos.y1, displayTitle, fgColor)
|
VisualElement.textFg(self, 2, pos.y1, displayTitle, fgColor)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("childrenSorted") then
|
if not self.getResolved("childrenSorted") then
|
||||||
self:sortChildren()
|
self:sortChildren()
|
||||||
end
|
end
|
||||||
if not self.get("childrenEventsSorted") then
|
if not self.getResolved("childrenEventsSorted") then
|
||||||
for eventName in pairs(self._values.childrenEvents or {}) do
|
for eventName in pairs(self._values.childrenEvents or {}) do
|
||||||
self:sortChildrenEvents(eventName)
|
self:sortChildrenEvents(eventName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, child in ipairs(self.get("visibleChildren") or {}) do
|
for _, child in ipairs(self.getResolved("visibleChildren") or {}) do
|
||||||
if child == self then error("CIRCULAR REFERENCE DETECTED!") return end
|
if child == self then error("CIRCULAR REFERENCE DETECTED!") return end
|
||||||
child:render()
|
child:render()
|
||||||
child:postRender()
|
child:postRender()
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ end
|
|||||||
--- @return number value The current value (0 to max)
|
--- @return number value The current value (0 to max)
|
||||||
--- @usage local value = slider:getValue()
|
--- @usage local value = slider:getValue()
|
||||||
function Slider:getValue()
|
function Slider:getValue()
|
||||||
local step = self.get("step")
|
local step = self.getResolved("step")
|
||||||
local max = self.get("max")
|
local max = self.getResolved("max")
|
||||||
local maxSteps = self.get("horizontal") and self.get("width") or self.get("height")
|
local maxSteps = self.getResolved("horizontal") and self.getResolved("width") or self.getResolved("height")
|
||||||
return math.floor((step - 1) * (max / (maxSteps - 1)))
|
return math.floor((step - 1) * (max / (maxSteps - 1)))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -74,8 +74,8 @@ end
|
|||||||
function Slider:mouse_click(button, x, y)
|
function Slider:mouse_click(button, x, y)
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local pos = self.get("horizontal") and relX or relY
|
local pos = self.getResolved("horizontal") and relX or relY
|
||||||
local maxSteps = self.get("horizontal") and self.get("width") or self.get("height")
|
local maxSteps = self.getResolved("horizontal") and self.getResolved("width") or self.getResolved("height")
|
||||||
|
|
||||||
self.set("step", math.min(maxSteps, math.max(1, pos)))
|
self.set("step", math.min(maxSteps, math.max(1, pos)))
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
@@ -93,8 +93,8 @@ Slider.mouse_drag = Slider.mouse_click
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Slider:mouse_scroll(direction, x, y)
|
function Slider:mouse_scroll(direction, x, y)
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
local step = self.get("step")
|
local step = self.getResolved("step")
|
||||||
local maxSteps = self.get("horizontal") and self.get("width") or self.get("height")
|
local maxSteps = self.getResolved("horizontal") and self.getResolved("width") or self.getResolved("height")
|
||||||
self.set("step", math.min(maxSteps, math.max(1, step + direction)))
|
self.set("step", math.min(maxSteps, math.max(1, step + direction)))
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
return true
|
return true
|
||||||
@@ -106,23 +106,23 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Slider:render()
|
function Slider:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local horizontal = self.get("horizontal")
|
local horizontal = self.getResolved("horizontal")
|
||||||
local step = self.get("step")
|
local step = self.getResolved("step")
|
||||||
|
|
||||||
local barChar = horizontal and "\140" or " "
|
local barChar = horizontal and "\140" or " "
|
||||||
local text = string.rep(barChar, horizontal and width or height)
|
local text = string.rep(barChar, horizontal and width or height)
|
||||||
|
|
||||||
if horizontal then
|
if horizontal then
|
||||||
self:textFg(1, 1, text, self.get("barColor"))
|
self:textFg(1, 1, text, self.getResolved("barColor"))
|
||||||
self:textBg(step, 1, " ", self.get("sliderColor"))
|
self:textBg(step, 1, " ", self.getResolved("sliderColor"))
|
||||||
else
|
else
|
||||||
local bg = self.get("background")
|
local bg = self.getResolved("background")
|
||||||
for y = 1, height do
|
for y = 1, height do
|
||||||
self:textBg(1, y, " ", bg)
|
self:textBg(1, y, " ", bg)
|
||||||
end
|
end
|
||||||
self:textBg(1, step, " ", self.get("sliderColor"))
|
self:textBg(1, step, " ", self.getResolved("sliderColor"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Switch:mouse_click(button, x, y)
|
function Switch:mouse_click(button, x, y)
|
||||||
if VisualElement.mouse_click(self, button, x, y) then
|
if VisualElement.mouse_click(self, button, x, y) then
|
||||||
self.set("checked", not self.get("checked"))
|
self.set("checked", not self.getResolved("checked"))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
@@ -62,20 +62,21 @@ end
|
|||||||
--- @shortDescription Renders the Switch
|
--- @shortDescription Renders the Switch
|
||||||
--- @protected
|
--- @protected
|
||||||
function Switch:render()
|
function Switch:render()
|
||||||
local checked = self.get("checked")
|
local checked = self.getResolved("checked")
|
||||||
local text = self.get("text")
|
local text = self.getResolved("text")
|
||||||
local switchWidth = self.get("width")
|
local switchWidth = self.getResolved("width")
|
||||||
local switchHeight = self.get("height")
|
local switchHeight = self.getResolved("height")
|
||||||
|
local foreground = self.getResolved("foreground")
|
||||||
|
|
||||||
local bgColor = checked and self.get("onBackground") or self.get("offBackground")
|
local bgColor = checked and self.getResolved("onBackground") or self.getResolved("offBackground")
|
||||||
self:multiBlit(1, 1, switchWidth, switchHeight, " ", tHex[self.get("foreground")], tHex[bgColor])
|
self:multiBlit(1, 1, switchWidth, switchHeight, " ", tHex[foreground], tHex[bgColor])
|
||||||
|
|
||||||
local sliderSize = math.floor(switchWidth / 2)
|
local sliderSize = math.floor(switchWidth / 2)
|
||||||
local sliderStart = checked and (switchWidth - sliderSize + 1) or 1
|
local sliderStart = checked and (switchWidth - sliderSize + 1) or 1
|
||||||
self:multiBlit(sliderStart, 1, sliderSize, switchHeight, " ", tHex[self.get("foreground")], tHex[self.get("background")])
|
self:multiBlit(sliderStart, 1, sliderSize, switchHeight, " ", tHex[foreground], tHex[self.getResolved("background")])
|
||||||
|
|
||||||
if text ~= "" then
|
if text ~= "" then
|
||||||
self:textFg(switchWidth + 2, 1, text, self.get("foreground"))
|
self:textFg(switchWidth + 2, 1, text, foreground)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ end
|
|||||||
--- @param title string The title of the tab
|
--- @param title string The title of the tab
|
||||||
--- @return table tabHandler The tab handler proxy for adding elements to the new tab
|
--- @return table tabHandler The tab handler proxy for adding elements to the new tab
|
||||||
function TabControl:newTab(title)
|
function TabControl:newTab(title)
|
||||||
local tabs = self.get("tabs") or {}
|
local tabs = self.getResolved("tabs") or {}
|
||||||
local tabId = #tabs + 1
|
local tabId = #tabs + 1
|
||||||
|
|
||||||
table.insert(tabs, {
|
table.insert(tabs, {
|
||||||
@@ -165,7 +165,7 @@ function TabControl:newTab(title)
|
|||||||
|
|
||||||
self.set("tabs", tabs)
|
self.set("tabs", tabs)
|
||||||
|
|
||||||
if not self.get("activeTab") then
|
if not self.getResolved("activeTab") then
|
||||||
self.set("activeTab", tabId)
|
self.set("activeTab", tabId)
|
||||||
end
|
end
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -216,7 +216,7 @@ end
|
|||||||
--- @return table element The created element
|
--- @return table element The created element
|
||||||
function TabControl:addElement(elementType, tabId)
|
function TabControl:addElement(elementType, tabId)
|
||||||
local element = Container.addElement(self, elementType)
|
local element = Container.addElement(self, elementType)
|
||||||
local targetTab = tabId or self.get("activeTab")
|
local targetTab = tabId or self.getResolved("activeTab")
|
||||||
if targetTab then
|
if targetTab then
|
||||||
element._tabId = targetTab
|
element._tabId = targetTab
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -231,7 +231,7 @@ end
|
|||||||
function TabControl:addChild(child)
|
function TabControl:addChild(child)
|
||||||
Container.addChild(self, child)
|
Container.addChild(self, child)
|
||||||
if not child._tabId then
|
if not child._tabId then
|
||||||
local tabs = self.get("tabs") or {}
|
local tabs = self.getResolved("tabs") or {}
|
||||||
if #tabs > 0 then
|
if #tabs > 0 then
|
||||||
child._tabId = 1
|
child._tabId = 1
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -250,7 +250,7 @@ end
|
|||||||
--- @shortDescription Sets the active tab
|
--- @shortDescription Sets the active tab
|
||||||
--- @param tabId number The ID of the tab to activate
|
--- @param tabId number The ID of the tab to activate
|
||||||
function TabControl:setActiveTab(tabId)
|
function TabControl:setActiveTab(tabId)
|
||||||
local oldTab = self.get("activeTab")
|
local oldTab = self.getResolved("activeTab")
|
||||||
if oldTab == tabId then return self end
|
if oldTab == tabId then return self end
|
||||||
self.set("activeTab", tabId)
|
self.set("activeTab", tabId)
|
||||||
self:updateTabVisibility()
|
self:updateTabVisibility()
|
||||||
@@ -267,7 +267,7 @@ function TabControl:isChildVisible(child)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if child._tabId then
|
if child._tabId then
|
||||||
return child._tabId == self.get("activeTab")
|
return child._tabId == self.getResolved("activeTab")
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -281,15 +281,15 @@ function TabControl:getContentYOffset()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TabControl:_getHeaderMetrics()
|
function TabControl:_getHeaderMetrics()
|
||||||
local tabs = self.get("tabs") or {}
|
local tabs = self.getResolved("tabs") or {}
|
||||||
local width = self.get("width") or 1
|
local width = self.getResolved("width") or 1
|
||||||
local minTabH = self.get("tabHeight") or 1
|
local minTabH = self.getResolved("tabHeight") or 1
|
||||||
local scrollable = self.get("scrollableTab")
|
local scrollable = self.getResolved("scrollableTab")
|
||||||
|
|
||||||
local positions = {}
|
local positions = {}
|
||||||
|
|
||||||
if scrollable then
|
if scrollable then
|
||||||
local scrollOffset = self.get("tabScrollOffset") or 0
|
local scrollOffset = self.getResolved("tabScrollOffset") or 0
|
||||||
local actualX = 1
|
local actualX = 1
|
||||||
local totalWidth = 0
|
local totalWidth = 0
|
||||||
|
|
||||||
@@ -500,10 +500,10 @@ end
|
|||||||
--- @param direction number -1 to scroll left, 1 to scroll right
|
--- @param direction number -1 to scroll left, 1 to scroll right
|
||||||
--- @return TabControl self For method chaining
|
--- @return TabControl self For method chaining
|
||||||
function TabControl:scrollTabs(direction)
|
function TabControl:scrollTabs(direction)
|
||||||
if not self.get("scrollableTab") then return self end
|
if not self.getResolved("scrollableTab") then return self end
|
||||||
|
|
||||||
local metrics = self:_getHeaderMetrics()
|
local metrics = self:_getHeaderMetrics()
|
||||||
local currentOffset = self.get("tabScrollOffset") or 0
|
local currentOffset = self.getResolved("tabScrollOffset") or 0
|
||||||
local maxScroll = metrics.maxScroll or 0
|
local maxScroll = metrics.maxScroll or 0
|
||||||
|
|
||||||
local newOffset = currentOffset + (direction * 5)
|
local newOffset = currentOffset + (direction * 5)
|
||||||
@@ -517,7 +517,7 @@ function TabControl:mouse_scroll(direction, x, y)
|
|||||||
if VisualElement.mouse_scroll(self, direction, x, y) then
|
if VisualElement.mouse_scroll(self, direction, x, y) then
|
||||||
local headerH = self:_getHeaderMetrics().headerHeight
|
local headerH = self:_getHeaderMetrics().headerHeight
|
||||||
|
|
||||||
if self.get("scrollableTab") and y == self.get("y") then
|
if self.getResolved("scrollableTab") and y == self.getResolved("y") then
|
||||||
self:scrollTabs(direction)
|
self:scrollTabs(direction)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -549,18 +549,20 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function TabControl:render()
|
function TabControl:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
|
local foreground = self.getResolved("foreground")
|
||||||
|
local headerBackground = self.getResolved("headerBackground")
|
||||||
local metrics = self:_getHeaderMetrics()
|
local metrics = self:_getHeaderMetrics()
|
||||||
local headerH = metrics.headerHeight or 1
|
local headerH = metrics.headerHeight or 1
|
||||||
|
|
||||||
VisualElement.multiBlit(self, 1, 1, width, headerH, " ", tHex[self.get("foreground")], tHex[self.get("headerBackground")])
|
VisualElement.multiBlit(self, 1, 1, width, headerH, " ", tHex[foreground], tHex[headerBackground])
|
||||||
local activeTab = self.get("activeTab")
|
local activeTab = self.getResolved("activeTab")
|
||||||
|
|
||||||
for _, pos in ipairs(metrics.positions) do
|
for _, pos in ipairs(metrics.positions) do
|
||||||
local bgColor = (pos.id == activeTab) and self.get("activeTabBackground") or self.get("headerBackground")
|
local bgColor = (pos.id == activeTab) and self.getResolved("activeTabBackground") or headerBackground
|
||||||
local fgColor = (pos.id == activeTab) and self.get("activeTabTextColor") or self.get("foreground")
|
local fgColor = (pos.id == activeTab) and self.getResolved("activeTabTextColor") or foreground
|
||||||
|
|
||||||
VisualElement.multiBlit(self, pos.x1, pos.line, pos.displayWidth or (pos.x2 - pos.x1 + 1), 1, " ", tHex[self.get("foreground")], tHex[bgColor])
|
VisualElement.multiBlit(self, pos.x1, pos.line, pos.displayWidth or (pos.x2 - pos.x1 + 1), 1, " ", tHex[foreground], tHex[bgColor])
|
||||||
|
|
||||||
local displayTitle = pos.title
|
local displayTitle = pos.title
|
||||||
local textStartInTitle = 1 + (pos.startClip or 0)
|
local textStartInTitle = 1 + (pos.startClip or 0)
|
||||||
@@ -576,16 +578,16 @@ function TabControl:render()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("childrenSorted") then
|
if not self.getResolved("childrenSorted") then
|
||||||
self:sortChildren()
|
self:sortChildren()
|
||||||
end
|
end
|
||||||
if not self.get("childrenEventsSorted") then
|
if not self.getResolved("childrenEventsSorted") then
|
||||||
for eventName in pairs(self._values.childrenEvents or {}) do
|
for eventName in pairs(self._values.childrenEvents or {}) do
|
||||||
self:sortChildrenEvents(eventName)
|
self:sortChildrenEvents(eventName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, child in ipairs(self.get("visibleChildren") or {}) do
|
for _, child in ipairs(self.getResolved("visibleChildren") or {}) do
|
||||||
if child == self then error("CIRCULAR REFERENCE DETECTED!") return end
|
if child == self then error("CIRCULAR REFERENCE DETECTED!") return end
|
||||||
child:render()
|
child:render()
|
||||||
child:postRender()
|
child:postRender()
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ Table.defineProperty(Table, "offset", {
|
|||||||
type = "number",
|
type = "number",
|
||||||
canTriggerRender = true,
|
canTriggerRender = true,
|
||||||
setter = function(self, value)
|
setter = function(self, value)
|
||||||
local maxOffset = math.max(0, #self.get("items") - (self.get("height") - 1))
|
local maxOffset = math.max(0, #self.getResolved("items") - (self.getResolved("height") - 1))
|
||||||
return math.min(maxOffset, math.max(0, value))
|
return math.min(maxOffset, math.max(0, value))
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
@@ -127,8 +127,8 @@ function Table:init(props, basalt)
|
|||||||
self.set("type", "Table")
|
self.set("type", "Table")
|
||||||
|
|
||||||
self:observe("sortColumn", function()
|
self:observe("sortColumn", function()
|
||||||
if self.get("sortColumn") then
|
if self.getResolved("sortColumn") then
|
||||||
self:sortByColumn(self.get("sortColumn"))
|
self:sortByColumn(self.getResolved("sortColumn"))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ end
|
|||||||
--- @param rowIndex number The index of the row to remove
|
--- @param rowIndex number The index of the row to remove
|
||||||
--- @return Table self The Table instance
|
--- @return Table self The Table instance
|
||||||
function Table:removeRow(rowIndex)
|
function Table:removeRow(rowIndex)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
if items[rowIndex] then
|
if items[rowIndex] then
|
||||||
table.remove(items, rowIndex)
|
table.remove(items, rowIndex)
|
||||||
self.set("items", items)
|
self.set("items", items)
|
||||||
@@ -168,7 +168,7 @@ end
|
|||||||
--- @param rowIndex number The index of the row
|
--- @param rowIndex number The index of the row
|
||||||
--- @return table? row The row data or nil
|
--- @return table? row The row data or nil
|
||||||
function Table:getRow(rowIndex)
|
function Table:getRow(rowIndex)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
return items[rowIndex]
|
return items[rowIndex]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ end
|
|||||||
--- @param value any The new value
|
--- @param value any The new value
|
||||||
--- @return Table self The Table instance
|
--- @return Table self The Table instance
|
||||||
function Table:updateCell(rowIndex, colIndex, value)
|
function Table:updateCell(rowIndex, colIndex, value)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
if items[rowIndex] and items[rowIndex].cells then
|
if items[rowIndex] and items[rowIndex].cells then
|
||||||
items[rowIndex].cells[colIndex] = value
|
items[rowIndex].cells[colIndex] = value
|
||||||
self.set("items", items)
|
self.set("items", items)
|
||||||
@@ -191,7 +191,7 @@ end
|
|||||||
--- @shortDescription Gets the currently selected row data
|
--- @shortDescription Gets the currently selected row data
|
||||||
--- @return table? row The selected row or nil
|
--- @return table? row The selected row or nil
|
||||||
function Table:getSelectedRow()
|
function Table:getSelectedRow()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
for _, item in ipairs(items) do
|
for _, item in ipairs(items) do
|
||||||
local isSelected = item._data and item._data.selected or item.selected
|
local isSelected = item._data and item._data.selected or item.selected
|
||||||
if isSelected then
|
if isSelected then
|
||||||
@@ -215,7 +215,7 @@ end
|
|||||||
--- @param width number|string The width of the column (number, "auto", or "30%")
|
--- @param width number|string The width of the column (number, "auto", or "30%")
|
||||||
--- @return Table self The Table instance
|
--- @return Table self The Table instance
|
||||||
function Table:addColumn(name, width)
|
function Table:addColumn(name, width)
|
||||||
local columns = self.get("columns")
|
local columns = self.getResolved("columns")
|
||||||
table.insert(columns, {name = name, width = width})
|
table.insert(columns, {name = name, width = width})
|
||||||
self.set("columns", columns)
|
self.set("columns", columns)
|
||||||
return self
|
return self
|
||||||
@@ -227,7 +227,7 @@ end
|
|||||||
--- @param sortFn function Function that takes (rowA, rowB) and returns comparison result
|
--- @param sortFn function Function that takes (rowA, rowB) and returns comparison result
|
||||||
--- @return Table self The Table instance
|
--- @return Table self The Table instance
|
||||||
function Table:setColumnSortFunction(columnIndex, sortFn)
|
function Table:setColumnSortFunction(columnIndex, sortFn)
|
||||||
local customSorts = self.get("customSortFunction")
|
local customSorts = self.getResolved("customSortFunction")
|
||||||
customSorts[columnIndex] = sortFn
|
customSorts[columnIndex] = sortFn
|
||||||
self.set("customSortFunction", customSorts)
|
self.set("customSortFunction", customSorts)
|
||||||
return self
|
return self
|
||||||
@@ -270,7 +270,7 @@ end
|
|||||||
--- @shortDescription Gets all rows as array of cell arrays
|
--- @shortDescription Gets all rows as array of cell arrays
|
||||||
--- @return table data Array of row cell arrays
|
--- @return table data Array of row cell arrays
|
||||||
function Table:getData()
|
function Table:getData()
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local data = {}
|
local data = {}
|
||||||
|
|
||||||
for _, item in ipairs(items) do
|
for _, item in ipairs(items) do
|
||||||
@@ -359,9 +359,9 @@ end
|
|||||||
--- @param fn function? Optional custom sorting function
|
--- @param fn function? Optional custom sorting function
|
||||||
--- @return Table self The Table instance
|
--- @return Table self The Table instance
|
||||||
function Table:sortByColumn(columnIndex, fn)
|
function Table:sortByColumn(columnIndex, fn)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local direction = self.get("sortDirection")
|
local direction = self.getResolved("sortDirection")
|
||||||
local customSorts = self.get("customSortFunction")
|
local customSorts = self.getResolved("customSortFunction")
|
||||||
|
|
||||||
local sortFn = fn or customSorts[columnIndex]
|
local sortFn = fn or customSorts[columnIndex]
|
||||||
|
|
||||||
@@ -429,10 +429,10 @@ function Table:mouse_click(button, x, y)
|
|||||||
if not Collection.mouse_click(self, button, x, y) then return false end
|
if not Collection.mouse_click(self, button, x, y) then return false end
|
||||||
|
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
local visibleRows = height - 1
|
local visibleRows = height - 1
|
||||||
|
|
||||||
if showScrollBar and #items > visibleRows and relX == width and relY > 1 then
|
if showScrollBar and #items > visibleRows and relX == width and relY > 1 then
|
||||||
@@ -440,7 +440,7 @@ function Table:mouse_click(button, x, y)
|
|||||||
local maxOffset = #items - visibleRows
|
local maxOffset = #items - visibleRows
|
||||||
local handleSize = math.max(1, math.floor((visibleRows / #items) * scrollBarHeight))
|
local handleSize = math.max(1, math.floor((visibleRows / #items) * scrollBarHeight))
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (self.get("offset") / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (self.getResolved("offset") / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (scrollBarHeight - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (scrollBarHeight - handleSize)) + 1
|
||||||
|
|
||||||
local scrollBarRelY = relY - 1
|
local scrollBarRelY = relY - 1
|
||||||
@@ -457,15 +457,15 @@ function Table:mouse_click(button, x, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if relY == 1 then
|
if relY == 1 then
|
||||||
local columns = self.get("columns")
|
local columns = self.getResolved("columns")
|
||||||
local calculatedColumns = self:calculateColumnWidths(columns, width)
|
local calculatedColumns = self:calculateColumnWidths(columns, width)
|
||||||
|
|
||||||
local currentX = 1
|
local currentX = 1
|
||||||
for i, col in ipairs(calculatedColumns) do
|
for i, col in ipairs(calculatedColumns) do
|
||||||
local colWidth = col.visibleWidth or col.width or 10
|
local colWidth = col.visibleWidth or col.width or 10
|
||||||
if relX >= currentX and relX < currentX + colWidth then
|
if relX >= currentX and relX < currentX + colWidth then
|
||||||
if self.get("sortColumn") == i then
|
if self.getResolved("sortColumn") == i then
|
||||||
self.set("sortDirection", self.get("sortDirection") == "asc" and "desc" or "asc")
|
self.set("sortDirection", self.getResolved("sortDirection") == "asc" and "desc" or "asc")
|
||||||
else
|
else
|
||||||
self.set("sortColumn", i)
|
self.set("sortColumn", i)
|
||||||
self.set("sortDirection", "asc")
|
self.set("sortDirection", "asc")
|
||||||
@@ -480,7 +480,7 @@ function Table:mouse_click(button, x, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if relY > 1 then
|
if relY > 1 then
|
||||||
local rowIndex = relY - 2 + self.get("offset")
|
local rowIndex = relY - 2 + self.getResolved("offset")
|
||||||
|
|
||||||
if rowIndex >= 0 and rowIndex < #items then
|
if rowIndex >= 0 and rowIndex < #items then
|
||||||
local actualIndex = rowIndex + 1
|
local actualIndex = rowIndex + 1
|
||||||
@@ -514,8 +514,8 @@ end
|
|||||||
function Table:mouse_drag(button, x, y)
|
function Table:mouse_drag(button, x, y)
|
||||||
if self._scrollBarDragging then
|
if self._scrollBarDragging then
|
||||||
local _, relY = self:getRelativePosition(x, y)
|
local _, relY = self:getRelativePosition(x, y)
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local visibleRows = height - 1
|
local visibleRows = height - 1
|
||||||
local scrollBarHeight = height - 1
|
local scrollBarHeight = height - 1
|
||||||
local handleSize = math.max(1, math.floor((visibleRows / #items) * scrollBarHeight))
|
local handleSize = math.max(1, math.floor((visibleRows / #items) * scrollBarHeight))
|
||||||
@@ -549,11 +549,11 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Table:mouse_scroll(direction, x, y)
|
function Table:mouse_scroll(direction, x, y)
|
||||||
if Collection.mouse_scroll(self, direction, x, y) then
|
if Collection.mouse_scroll(self, direction, x, y) then
|
||||||
local items = self.get("items")
|
local items = self.getResolved("items")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local visibleRows = height - 1 -- Subtract header
|
local visibleRows = height - 1 -- Subtract header
|
||||||
local maxOffset = math.max(0, #items - visibleRows)
|
local maxOffset = math.max(0, #items - visibleRows)
|
||||||
local newOffset = math.min(maxOffset, math.max(0, self.get("offset") + direction))
|
local newOffset = math.min(maxOffset, math.max(0, self.getResolved("offset") + direction))
|
||||||
|
|
||||||
self.set("offset", newOffset)
|
self.set("offset", newOffset)
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
@@ -570,9 +570,11 @@ function Table:render()
|
|||||||
local items = self.getResolved("items")
|
local items = self.getResolved("items")
|
||||||
local sortCol = self.getResolved("sortColumn")
|
local sortCol = self.getResolved("sortColumn")
|
||||||
local offset = self.getResolved("offset")
|
local offset = self.getResolved("offset")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local showScrollBar = self.getResolved("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
|
local background = self.getResolved("background")
|
||||||
|
local foreground = self.getResolved("foreground")
|
||||||
local visibleRows = height - 1
|
local visibleRows = height - 1
|
||||||
|
|
||||||
local needsScrollBar = showScrollBar and #items > visibleRows
|
local needsScrollBar = showScrollBar and #items > visibleRows
|
||||||
@@ -595,14 +597,14 @@ function Table:render()
|
|||||||
if i > lastVisibleColumn then break end
|
if i > lastVisibleColumn then break end
|
||||||
local text = col.name
|
local text = col.name
|
||||||
if i == sortCol then
|
if i == sortCol then
|
||||||
text = text .. (self.get("sortDirection") == "asc" and "\30" or "\31")
|
text = text .. (self.getResolved("sortDirection") == "asc" and "\30" or "\31")
|
||||||
end
|
end
|
||||||
self:textFg(currentX, 1, text:sub(1, col.visibleWidth), self.get("headerColor"))
|
self:textFg(currentX, 1, text:sub(1, col.visibleWidth), self.getResolved("headerColor"))
|
||||||
currentX = currentX + col.visibleWidth
|
currentX = currentX + col.visibleWidth
|
||||||
end
|
end
|
||||||
|
|
||||||
if currentX <= contentWidth then
|
if currentX <= contentWidth then
|
||||||
self:textBg(currentX, 1, string.rep(" ", contentWidth - currentX + 1), self.get("background"))
|
self:textBg(currentX, 1, string.rep(" ", contentWidth - currentX + 1), background)
|
||||||
end
|
end
|
||||||
|
|
||||||
for y = 2, height do
|
for y = 2, height do
|
||||||
@@ -615,7 +617,7 @@ function Table:render()
|
|||||||
|
|
||||||
if cells then
|
if cells then
|
||||||
currentX = 1
|
currentX = 1
|
||||||
local bg = isSelected and self.get("selectedBackground") or self.get("background")
|
local bg = isSelected and self.getResolved("selectedBackground") or background
|
||||||
|
|
||||||
for i, col in ipairs(calculatedColumns) do
|
for i, col in ipairs(calculatedColumns) do
|
||||||
if i > lastVisibleColumn then break end
|
if i > lastVisibleColumn then break end
|
||||||
@@ -625,7 +627,7 @@ function Table:render()
|
|||||||
paddedText = string.sub(paddedText, 1, col.visibleWidth - 1) .. " "
|
paddedText = string.sub(paddedText, 1, col.visibleWidth - 1) .. " "
|
||||||
end
|
end
|
||||||
local finalText = string.sub(paddedText, 1, col.visibleWidth)
|
local finalText = string.sub(paddedText, 1, col.visibleWidth)
|
||||||
local finalForeground = string.rep(tHex[self.get("foreground")], col.visibleWidth)
|
local finalForeground = string.rep(tHex[foreground], col.visibleWidth)
|
||||||
local finalBackground = string.rep(tHex[bg], col.visibleWidth)
|
local finalBackground = string.rep(tHex[bg], col.visibleWidth)
|
||||||
|
|
||||||
self:blit(currentX, y, finalText, finalForeground, finalBackground)
|
self:blit(currentX, y, finalText, finalForeground, finalBackground)
|
||||||
@@ -638,8 +640,8 @@ function Table:render()
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:blit(1, y, string.rep(" ", contentWidth),
|
self:blit(1, y, string.rep(" ", contentWidth),
|
||||||
string.rep(tHex[self.get("foreground")], contentWidth),
|
string.rep(tHex[foreground], contentWidth),
|
||||||
string.rep(tHex[self.get("background")], contentWidth))
|
string.rep(tHex[background], contentWidth))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -655,7 +657,6 @@ function Table:render()
|
|||||||
local scrollBarBg = self.getResolved("scrollBarBackground")
|
local scrollBarBg = self.getResolved("scrollBarBackground")
|
||||||
local scrollBarColor = self.getResolved("scrollBarColor")
|
local scrollBarColor = self.getResolved("scrollBarColor")
|
||||||
local scrollBarBgColor = self.getResolved("scrollBarBackgroundColor")
|
local scrollBarBgColor = self.getResolved("scrollBarBackgroundColor")
|
||||||
local foreground = self.getResolved("foreground")
|
|
||||||
|
|
||||||
for i = 2, height do
|
for i = 2, height do
|
||||||
self:blit(width, i, scrollBarBg, tHex[foreground], tHex[scrollBarBgColor])
|
self:blit(width, i, scrollBarBg, tHex[foreground], tHex[scrollBarBgColor])
|
||||||
|
|||||||
@@ -94,20 +94,20 @@ local function autoCompleteVisible(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function getBorderPadding(self)
|
local function getBorderPadding(self)
|
||||||
return self.get("autoCompleteShowBorder") and 1 or 0
|
return self.getResolved("autoCompleteShowBorder") and 1 or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function updateAutoCompleteStyles(self)
|
local function updateAutoCompleteStyles(self)
|
||||||
local frame = self._autoCompleteFrame
|
local frame = self._autoCompleteFrame
|
||||||
local list = self._autoCompleteList
|
local list = self._autoCompleteList
|
||||||
if not frame or frame._destroyed then return end
|
if not frame or frame._destroyed then return end
|
||||||
frame:setBackground(self.get("autoCompleteBackground"))
|
frame:setBackground(self.getResolved("autoCompleteBackground"))
|
||||||
frame:setForeground(self.get("autoCompleteForeground"))
|
frame:setForeground(self.getResolved("autoCompleteForeground"))
|
||||||
if list and not list._destroyed then
|
if list and not list._destroyed then
|
||||||
list:setBackground(self.get("autoCompleteBackground"))
|
list:setBackground(self.getResolved("autoCompleteBackground"))
|
||||||
list:setForeground(self.get("autoCompleteForeground"))
|
list:setForeground(self.getResolved("autoCompleteForeground"))
|
||||||
list:setSelectedBackground(self.get("autoCompleteSelectedBackground"))
|
list:setSelectedBackground(self.getResolved("autoCompleteSelectedBackground"))
|
||||||
list:setSelectedForeground(self.get("autoCompleteSelectedForeground"))
|
list:setSelectedForeground(self.getResolved("autoCompleteSelectedForeground"))
|
||||||
list:updateRender()
|
list:updateRender()
|
||||||
end
|
end
|
||||||
layoutAutoCompleteList(self)
|
layoutAutoCompleteList(self)
|
||||||
@@ -165,9 +165,9 @@ local function applyAutoCompleteSelection(self, item)
|
|||||||
local insertText = entry.insert or entry.text or ""
|
local insertText = entry.insert or entry.text or ""
|
||||||
if insertText == "" then return end
|
if insertText == "" then return end
|
||||||
|
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local line = lines[cursorY] or ""
|
local line = lines[cursorY] or ""
|
||||||
local startIndex = self._autoCompleteTokenStart or cursorX
|
local startIndex = self._autoCompleteTokenStart or cursorX
|
||||||
if startIndex < 1 then startIndex = 1 end
|
if startIndex < 1 then startIndex = 1 end
|
||||||
@@ -184,7 +184,7 @@ local function applyAutoCompleteSelection(self, item)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function ensureAutoCompleteUI(self)
|
local function ensureAutoCompleteUI(self)
|
||||||
if not self.get("autoCompleteEnabled") then return nil end
|
if not self.getResolved("autoCompleteEnabled") then return nil end
|
||||||
local frame = self._autoCompleteFrame
|
local frame = self._autoCompleteFrame
|
||||||
if frame and not frame._destroyed then
|
if frame and not frame._destroyed then
|
||||||
return self._autoCompleteList
|
return self._autoCompleteList
|
||||||
@@ -194,15 +194,15 @@ local function ensureAutoCompleteUI(self)
|
|||||||
if not base or not base.addFrame then return nil end
|
if not base or not base.addFrame then return nil end
|
||||||
|
|
||||||
frame = base:addFrame({
|
frame = base:addFrame({
|
||||||
width = self.get("width"),
|
width = self.getResolved("width"),
|
||||||
height = 1,
|
height = 1,
|
||||||
x = 1,
|
x = 1,
|
||||||
y = 1,
|
y = 1,
|
||||||
visible = false,
|
visible = false,
|
||||||
background = self.get("autoCompleteBackground"),
|
background = self.getResolved("autoCompleteBackground"),
|
||||||
foreground = self.get("autoCompleteForeground"),
|
foreground = self.getResolved("autoCompleteForeground"),
|
||||||
ignoreOffset = true,
|
ignoreOffset = true,
|
||||||
z = self.get("z") + self.get("autoCompleteZOffset"),
|
z = self.getResolved("z") + self.getResolved("autoCompleteZOffset"),
|
||||||
})
|
})
|
||||||
frame:setIgnoreOffset(true)
|
frame:setIgnoreOffset(true)
|
||||||
frame:setVisible(false)
|
frame:setVisible(false)
|
||||||
@@ -215,16 +215,16 @@ local function ensureAutoCompleteUI(self)
|
|||||||
height = math.max(1, frame.get("height") - padding * 2),
|
height = math.max(1, frame.get("height") - padding * 2),
|
||||||
selectable = true,
|
selectable = true,
|
||||||
multiSelection = false,
|
multiSelection = false,
|
||||||
background = self.get("autoCompleteBackground"),
|
background = self.getResolved("autoCompleteBackground"),
|
||||||
foreground = self.get("autoCompleteForeground"),
|
foreground = self.getResolved("autoCompleteForeground"),
|
||||||
})
|
})
|
||||||
list:setSelectedBackground(self.get("autoCompleteSelectedBackground"))
|
list:setSelectedBackground(self.getResolved("autoCompleteSelectedBackground"))
|
||||||
list:setSelectedForeground(self.get("autoCompleteSelectedForeground"))
|
list:setSelectedForeground(self.getResolved("autoCompleteSelectedForeground"))
|
||||||
list:setOffset(0)
|
list:setOffset(0)
|
||||||
list:onSelect(function(_, index, selectedItem)
|
list:onSelect(function(_, index, selectedItem)
|
||||||
if not autoCompleteVisible(self) then return end
|
if not autoCompleteVisible(self) then return end
|
||||||
setAutoCompleteSelection(self, index)
|
setAutoCompleteSelection(self, index)
|
||||||
if self.get("autoCompleteAcceptOnClick") then
|
if self.getResolved("autoCompleteAcceptOnClick") then
|
||||||
applyAutoCompleteSelection(self, selectedItem)
|
applyAutoCompleteSelection(self, selectedItem)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -272,12 +272,12 @@ updateAutoCompleteBorder = function(self)
|
|||||||
frame._autoCompleteBorderCommand = nil
|
frame._autoCompleteBorderCommand = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.get("autoCompleteShowBorder") then
|
if not self.getResolved("autoCompleteShowBorder") then
|
||||||
frame:updateRender()
|
frame:updateRender()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local borderColor = self.get("autoCompleteBorderColor") or colors.black
|
local borderColor = self.getResolved("autoCompleteBorderColor") or colors.black
|
||||||
|
|
||||||
local commandIndex = canvas:addCommand(function(element)
|
local commandIndex = canvas:addCommand(function(element)
|
||||||
local width = element.get("width") or 0
|
local width = element.get("width") or 0
|
||||||
@@ -303,12 +303,12 @@ updateAutoCompleteBorder = function(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function getTokenInfo(self)
|
local function getTokenInfo(self)
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local line = lines[cursorY] or ""
|
local line = lines[cursorY] or ""
|
||||||
local uptoCursor = line:sub(1, math.max(cursorX - 1, 0))
|
local uptoCursor = line:sub(1, math.max(cursorX - 1, 0))
|
||||||
local pattern = self.get("autoCompleteTokenPattern") or "[%w_]+"
|
local pattern = self.getResolved("autoCompleteTokenPattern") or "[%w_]+"
|
||||||
|
|
||||||
local token = ""
|
local token = ""
|
||||||
if pattern ~= "" then
|
if pattern ~= "" then
|
||||||
@@ -355,7 +355,7 @@ local function iterateSuggestions(source, handler)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function gatherSuggestions(self, token)
|
local function gatherSuggestions(self, token)
|
||||||
local provider = self.get("autoCompleteProvider")
|
local provider = self.getResolved("autoCompleteProvider")
|
||||||
local source = {}
|
local source = {}
|
||||||
if provider then
|
if provider then
|
||||||
local ok, result = pcall(provider, self, token)
|
local ok, result = pcall(provider, self, token)
|
||||||
@@ -363,11 +363,11 @@ local function gatherSuggestions(self, token)
|
|||||||
source = result
|
source = result
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
source = self.get("autoCompleteItems") or {}
|
source = self.getResolved("autoCompleteItems") or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local suggestions = {}
|
local suggestions = {}
|
||||||
local caseInsensitive = self.get("autoCompleteCaseInsensitive")
|
local caseInsensitive = self.getResolved("autoCompleteCaseInsensitive")
|
||||||
local target = caseInsensitive and token:lower() or token
|
local target = caseInsensitive and token:lower() or token
|
||||||
iterateSuggestions(source, function(entry)
|
iterateSuggestions(source, function(entry)
|
||||||
local normalized = normalizeSuggestion(entry)
|
local normalized = normalizeSuggestion(entry)
|
||||||
@@ -379,7 +379,7 @@ local function gatherSuggestions(self, token)
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local maxItems = self.get("autoCompleteMaxItems")
|
local maxItems = self.getResolved("autoCompleteMaxItems")
|
||||||
if #suggestions > maxItems then
|
if #suggestions > maxItems then
|
||||||
while #suggestions > maxItems do
|
while #suggestions > maxItems do
|
||||||
table.remove(suggestions)
|
table.remove(suggestions)
|
||||||
@@ -403,8 +403,8 @@ local function measureSuggestionWidth(self, suggestions)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local limit = self.get("autoCompleteMaxWidth")
|
local limit = self.getResolved("autoCompleteMaxWidth")
|
||||||
local maxWidth = self.get("width")
|
local maxWidth = self.getResolved("width")
|
||||||
if limit and limit > 0 then
|
if limit and limit > 0 then
|
||||||
maxWidth = math.min(maxWidth, limit)
|
maxWidth = math.min(maxWidth, limit)
|
||||||
end
|
end
|
||||||
@@ -430,7 +430,7 @@ local function placeAutoCompleteFrame(self, visibleCount, width)
|
|||||||
local list = self._autoCompleteList
|
local list = self._autoCompleteList
|
||||||
if not frame or frame._destroyed then return end
|
if not frame or frame._destroyed then return end
|
||||||
local border = getBorderPadding(self)
|
local border = getBorderPadding(self)
|
||||||
local contentWidth = math.max(1, width or self.get("width"))
|
local contentWidth = math.max(1, width or self.getResolved("width"))
|
||||||
local contentHeight = math.max(1, visibleCount or 1)
|
local contentHeight = math.max(1, visibleCount or 1)
|
||||||
|
|
||||||
local base = self:getBaseFrame()
|
local base = self:getBaseFrame()
|
||||||
@@ -457,17 +457,17 @@ local function placeAutoCompleteFrame(self, visibleCount, width)
|
|||||||
local frameWidth = contentWidth + border * 2
|
local frameWidth = contentWidth + border * 2
|
||||||
local frameHeight = contentHeight + border * 2
|
local frameHeight = contentHeight + border * 2
|
||||||
local originX, originY = self:calculatePosition()
|
local originX, originY = self:calculatePosition()
|
||||||
local scrollX = self.get("scrollX") or 0
|
local scrollX = self.getResolved("scrollX") or 0
|
||||||
local scrollY = self.get("scrollY") or 0
|
local scrollY = self.getResolved("scrollY") or 0
|
||||||
local tokenStart = (self._autoCompleteTokenStart or self.get("cursorX"))
|
local tokenStart = (self._autoCompleteTokenStart or self.getResolved("cursorX"))
|
||||||
local column = tokenStart - scrollX
|
local column = tokenStart - scrollX
|
||||||
column = math.max(1, math.min(self.get("width"), column))
|
column = math.max(1, math.min(self.getResolved("width"), column))
|
||||||
|
|
||||||
local cursorRow = self.get("cursorY") - scrollY
|
local cursorRow = self.getResolved("cursorY") - scrollY
|
||||||
cursorRow = math.max(1, math.min(self.get("height"), cursorRow))
|
cursorRow = math.max(1, math.min(self.getResolved("height"), cursorRow))
|
||||||
|
|
||||||
local offsetX = self.get("autoCompleteOffsetX")
|
local offsetX = self.getResolved("autoCompleteOffsetX")
|
||||||
local offsetY = self.get("autoCompleteOffsetY")
|
local offsetY = self.getResolved("autoCompleteOffsetY")
|
||||||
|
|
||||||
local baseX = originX + column - 1 + offsetX
|
local baseX = originX + column - 1 + offsetX
|
||||||
local x = baseX - border
|
local x = baseX - border
|
||||||
@@ -520,7 +520,7 @@ local function placeAutoCompleteFrame(self, visibleCount, width)
|
|||||||
frame:setPosition(x, y)
|
frame:setPosition(x, y)
|
||||||
frame:setWidth(frameWidth)
|
frame:setWidth(frameWidth)
|
||||||
frame:setHeight(frameHeight)
|
frame:setHeight(frameHeight)
|
||||||
frame:setZ(self.get("z") + self.get("autoCompleteZOffset"))
|
frame:setZ(self.getResolved("z") + self.getResolved("autoCompleteZOffset"))
|
||||||
|
|
||||||
layoutAutoCompleteList(self, contentWidth, contentHeight)
|
layoutAutoCompleteList(self, contentWidth, contentHeight)
|
||||||
|
|
||||||
@@ -531,7 +531,7 @@ local function placeAutoCompleteFrame(self, visibleCount, width)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function refreshAutoComplete(self)
|
local function refreshAutoComplete(self)
|
||||||
if not self.get("autoCompleteEnabled") then
|
if not self.getResolved("autoCompleteEnabled") then
|
||||||
hideAutoComplete(self, true)
|
hideAutoComplete(self, true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -544,7 +544,7 @@ local function refreshAutoComplete(self)
|
|||||||
self._autoCompleteToken = token
|
self._autoCompleteToken = token
|
||||||
self._autoCompleteTokenStart = startIndex
|
self._autoCompleteTokenStart = startIndex
|
||||||
|
|
||||||
if #token < self.get("autoCompleteMinChars") then
|
if #token < self.getResolved("autoCompleteMinChars") then
|
||||||
hideAutoComplete(self)
|
hideAutoComplete(self)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -576,7 +576,7 @@ end
|
|||||||
local function handleAutoCompleteKey(self, key)
|
local function handleAutoCompleteKey(self, key)
|
||||||
if not autoCompleteVisible(self) then return false end
|
if not autoCompleteVisible(self) then return false end
|
||||||
|
|
||||||
if key == keys.tab or (key == keys.enter and self.get("autoCompleteAcceptOnEnter")) then
|
if key == keys.tab or (key == keys.enter and self.getResolved("autoCompleteAcceptOnEnter")) then
|
||||||
applyAutoCompleteSelection(self)
|
applyAutoCompleteSelection(self)
|
||||||
return true
|
return true
|
||||||
elseif key == keys.up then
|
elseif key == keys.up then
|
||||||
@@ -593,7 +593,7 @@ local function handleAutoCompleteKey(self, key)
|
|||||||
local height = (self._autoCompleteList and self._autoCompleteList.get("height")) or 1
|
local height = (self._autoCompleteList and self._autoCompleteList.get("height")) or 1
|
||||||
setAutoCompleteSelection(self, (self._autoCompleteIndex or 1) + height)
|
setAutoCompleteSelection(self, (self._autoCompleteIndex or 1) + height)
|
||||||
return true
|
return true
|
||||||
elseif key == keys.escape and self.get("autoCompleteCloseOnEscape") then
|
elseif key == keys.escape and self.getResolved("autoCompleteCloseOnEscape") then
|
||||||
hideAutoComplete(self)
|
hideAutoComplete(self)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -647,7 +647,7 @@ function TextBox:init(props, basalt)
|
|||||||
self.set("type", "TextBox")
|
self.set("type", "TextBox")
|
||||||
|
|
||||||
local function refreshIfEnabled()
|
local function refreshIfEnabled()
|
||||||
if self.get("autoCompleteEnabled") and self:hasState("focused") then
|
if self.getResolved("autoCompleteEnabled") and self:hasState("focused") then
|
||||||
refreshAutoComplete(self)
|
refreshAutoComplete(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -659,7 +659,7 @@ function TextBox:init(props, basalt)
|
|||||||
local function reposition()
|
local function reposition()
|
||||||
if autoCompleteVisible(self) then
|
if autoCompleteVisible(self) then
|
||||||
local suggestions = rawget(self, "_autoCompleteSuggestions") or {}
|
local suggestions = rawget(self, "_autoCompleteSuggestions") or {}
|
||||||
placeAutoCompleteFrame(self, math.max(#suggestions, 1), rawget(self, "_autoCompletePopupWidth") or self.get("width"))
|
placeAutoCompleteFrame(self, math.max(#suggestions, 1), rawget(self, "_autoCompletePopupWidth") or self.getResolved("width"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -690,12 +690,12 @@ function TextBox:init(props, basalt)
|
|||||||
|
|
||||||
self:observe("autoCompleteZOffset", function()
|
self:observe("autoCompleteZOffset", function()
|
||||||
if self._autoCompleteFrame and not self._autoCompleteFrame._destroyed then
|
if self._autoCompleteFrame and not self._autoCompleteFrame._destroyed then
|
||||||
self._autoCompleteFrame:setZ(self.get("z") + self.get("autoCompleteZOffset"))
|
self._autoCompleteFrame:setZ(self.getResolved("z") + self.getResolved("autoCompleteZOffset"))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
self:observe("z", function()
|
self:observe("z", function()
|
||||||
if self._autoCompleteFrame and not self._autoCompleteFrame._destroyed then
|
if self._autoCompleteFrame and not self._autoCompleteFrame._destroyed then
|
||||||
self._autoCompleteFrame:setZ(self.get("z") + self.get("autoCompleteZOffset"))
|
self._autoCompleteFrame:setZ(self.getResolved("z") + self.getResolved("autoCompleteZOffset"))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -749,7 +749,7 @@ end
|
|||||||
--- @param color number The color to apply
|
--- @param color number The color to apply
|
||||||
--- @return TextBox self The TextBox instance
|
--- @return TextBox self The TextBox instance
|
||||||
function TextBox:addSyntaxPattern(pattern, color)
|
function TextBox:addSyntaxPattern(pattern, color)
|
||||||
table.insert(self.get("syntaxPatterns"), {pattern = pattern, color = color})
|
table.insert(self.getResolved("syntaxPatterns"), {pattern = pattern, color = color})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -757,7 +757,7 @@ end
|
|||||||
--- @param index number The index of the pattern to remove
|
--- @param index number The index of the pattern to remove
|
||||||
--- @return TextBox self
|
--- @return TextBox self
|
||||||
function TextBox:removeSyntaxPattern(index)
|
function TextBox:removeSyntaxPattern(index)
|
||||||
local patterns = self.get("syntaxPatterns") or {}
|
local patterns = self.getResolved("syntaxPatterns") or {}
|
||||||
if type(index) ~= "number" then return self end
|
if type(index) ~= "number" then return self end
|
||||||
if index >= 1 and index <= #patterns then
|
if index >= 1 and index <= #patterns then
|
||||||
table.remove(patterns, index)
|
table.remove(patterns, index)
|
||||||
@@ -776,9 +776,9 @@ function TextBox:clearSyntaxPatterns()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function insertChar(self, char)
|
local function insertChar(self, char)
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local currentLine = lines[cursorY]
|
local currentLine = lines[cursorY]
|
||||||
lines[cursorY] = currentLine:sub(1, cursorX-1) .. char .. currentLine:sub(cursorX)
|
lines[cursorY] = currentLine:sub(1, cursorX-1) .. char .. currentLine:sub(cursorX)
|
||||||
self.set("cursorX", cursorX + 1)
|
self.set("cursorX", cursorX + 1)
|
||||||
@@ -793,9 +793,9 @@ local function insertText(self, text)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function newLine(self)
|
local function newLine(self)
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local currentLine = lines[cursorY]
|
local currentLine = lines[cursorY]
|
||||||
|
|
||||||
local restOfLine = currentLine:sub(cursorX)
|
local restOfLine = currentLine:sub(cursorX)
|
||||||
@@ -809,9 +809,9 @@ local function newLine(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function backspace(self)
|
local function backspace(self)
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local currentLine = lines[cursorY]
|
local currentLine = lines[cursorY]
|
||||||
|
|
||||||
if cursorX > 1 then
|
if cursorX > 1 then
|
||||||
@@ -832,12 +832,12 @@ end
|
|||||||
--- @shortDescription Updates the viewport to keep the cursor in view
|
--- @shortDescription Updates the viewport to keep the cursor in view
|
||||||
--- @return TextBox self The TextBox instance
|
--- @return TextBox self The TextBox instance
|
||||||
function TextBox:updateViewport()
|
function TextBox:updateViewport()
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local scrollX = self.get("scrollX")
|
local scrollX = self.getResolved("scrollX")
|
||||||
local scrollY = self.get("scrollY")
|
local scrollY = self.getResolved("scrollY")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
|
|
||||||
-- Horizontal scrolling
|
-- Horizontal scrolling
|
||||||
if cursorX - scrollX > width then
|
if cursorX - scrollX > width then
|
||||||
@@ -860,14 +860,14 @@ end
|
|||||||
--- @return boolean handled Whether the event was handled
|
--- @return boolean handled Whether the event was handled
|
||||||
--- @protected
|
--- @protected
|
||||||
function TextBox:char(char)
|
function TextBox:char(char)
|
||||||
if not self.get("editable") or not self:hasState("focused") then return false end
|
if not self.getResolved("editable") or not self:hasState("focused") then return false end
|
||||||
-- Auto-pair logic only triggers for single characters
|
-- Auto-pair logic only triggers for single characters
|
||||||
local autoPair = self.get("autoPairEnabled")
|
local autoPair = self.getResolved("autoPairEnabled")
|
||||||
if autoPair and #char == 1 then
|
if autoPair and #char == 1 then
|
||||||
local map = self.get("autoPairCharacters") or {}
|
local map = self.getResolved("autoPairCharacters") or {}
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local line = lines[cursorY] or ""
|
local line = lines[cursorY] or ""
|
||||||
local afterChar = line:sub(cursorX, cursorX)
|
local afterChar = line:sub(cursorX, cursorX)
|
||||||
|
|
||||||
@@ -876,22 +876,22 @@ function TextBox:char(char)
|
|||||||
if closing then
|
if closing then
|
||||||
-- If skip closing and same closing already directly after, just insert opening?
|
-- If skip closing and same closing already directly after, just insert opening?
|
||||||
insertChar(self, char)
|
insertChar(self, char)
|
||||||
if self.get("autoPairSkipClosing") then
|
if self.getResolved("autoPairSkipClosing") then
|
||||||
if afterChar ~= closing then
|
if afterChar ~= closing then
|
||||||
insertChar(self, closing)
|
insertChar(self, closing)
|
||||||
-- Move cursor back inside pair
|
-- Move cursor back inside pair
|
||||||
self.set("cursorX", self.get("cursorX") - 1)
|
self.set("cursorX", self.getResolved("cursorX") - 1)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
insertChar(self, closing)
|
insertChar(self, closing)
|
||||||
self.set("cursorX", self.get("cursorX") - 1)
|
self.set("cursorX", self.getResolved("cursorX") - 1)
|
||||||
end
|
end
|
||||||
refreshAutoComplete(self)
|
refreshAutoComplete(self)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If typed char is a closing we might want to overtype
|
-- If typed char is a closing we might want to overtype
|
||||||
if self.get("autoPairOverType") then
|
if self.getResolved("autoPairOverType") then
|
||||||
for open, close in pairs(map) do
|
for open, close in pairs(map) do
|
||||||
if char == close and afterChar == close then
|
if char == close and afterChar == close then
|
||||||
-- move over instead of inserting
|
-- move over instead of inserting
|
||||||
@@ -913,24 +913,24 @@ end
|
|||||||
--- @return boolean handled Whether the event was handled
|
--- @return boolean handled Whether the event was handled
|
||||||
--- @protected
|
--- @protected
|
||||||
function TextBox:key(key)
|
function TextBox:key(key)
|
||||||
if not self.get("editable") or not self:hasState("focused") then return false end
|
if not self.getResolved("editable") or not self:hasState("focused") then return false end
|
||||||
if handleAutoCompleteKey(self, key) then
|
if handleAutoCompleteKey(self, key) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
|
|
||||||
if key == keys.enter then
|
if key == keys.enter then
|
||||||
-- Smart newline between matching braces/brackets if enabled
|
-- Smart newline between matching braces/brackets if enabled
|
||||||
if self.get("autoPairEnabled") and self.get("autoPairNewlineIndent") then
|
if self.getResolved("autoPairEnabled") and self.getResolved("autoPairNewlineIndent") then
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local cursorX = self.get("cursorX")
|
local cursorX = self.getResolved("cursorX")
|
||||||
local cursorY = self.get("cursorY")
|
local cursorY = self.getResolved("cursorY")
|
||||||
local line = lines[cursorY] or ""
|
local line = lines[cursorY] or ""
|
||||||
local before = line:sub(1, cursorX - 1)
|
local before = line:sub(1, cursorX - 1)
|
||||||
local after = line:sub(cursorX)
|
local after = line:sub(cursorX)
|
||||||
local pairMap = self.get("autoPairCharacters") or {}
|
local pairMap = self.getResolved("autoPairCharacters") or {}
|
||||||
local inverse = {}
|
local inverse = {}
|
||||||
for o,c in pairs(pairMap) do inverse[c]=o end
|
for o,c in pairs(pairMap) do inverse[c]=o end
|
||||||
local prevChar = before:sub(-1)
|
local prevChar = before:sub(-1)
|
||||||
@@ -989,9 +989,9 @@ function TextBox:mouse_scroll(direction, x, y)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if self:isInBounds(x, y) then
|
if self:isInBounds(x, y) then
|
||||||
local scrollY = self.get("scrollY")
|
local scrollY = self.getResolved("scrollY")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
|
|
||||||
local maxScroll = math.max(0, #lines - height + 2)
|
local maxScroll = math.max(0, #lines - height + 2)
|
||||||
|
|
||||||
@@ -1013,11 +1013,11 @@ end
|
|||||||
function TextBox:mouse_click(button, x, y)
|
function TextBox:mouse_click(button, x, y)
|
||||||
if VisualElement.mouse_click(self, button, x, y) then
|
if VisualElement.mouse_click(self, button, x, y) then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local scrollX = self.get("scrollX")
|
local scrollX = self.getResolved("scrollX")
|
||||||
local scrollY = self.get("scrollY")
|
local scrollY = self.getResolved("scrollY")
|
||||||
|
|
||||||
local targetY = (relY or 0) + (scrollY or 0)
|
local targetY = (relY or 0) + (scrollY or 0)
|
||||||
local lines = self.get("lines") or {}
|
local lines = self.getResolved("lines") or {}
|
||||||
|
|
||||||
-- clamp and validate before indexing to avoid nil errors
|
-- clamp and validate before indexing to avoid nil errors
|
||||||
if targetY < 1 then targetY = 1 end
|
if targetY < 1 then targetY = 1 end
|
||||||
@@ -1042,7 +1042,7 @@ end
|
|||||||
--- @shortDescription Handles paste events
|
--- @shortDescription Handles paste events
|
||||||
--- @protected
|
--- @protected
|
||||||
function TextBox:paste(text)
|
function TextBox:paste(text)
|
||||||
if not self.get("editable") or not self:hasState("focused") then return false end
|
if not self.getResolved("editable") or not self:hasState("focused") then return false end
|
||||||
|
|
||||||
for char in text:gmatch(".") do
|
for char in text:gmatch(".") do
|
||||||
if char == "\n" then
|
if char == "\n" then
|
||||||
@@ -1078,13 +1078,13 @@ end
|
|||||||
--- @shortDescription Gets the text of the TextBox
|
--- @shortDescription Gets the text of the TextBox
|
||||||
--- @return string text The text of the TextBox
|
--- @return string text The text of the TextBox
|
||||||
function TextBox:getText()
|
function TextBox:getText()
|
||||||
return table.concat(self.get("lines"), "\n")
|
return table.concat(self.getResolved("lines"), "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function applySyntaxHighlighting(self, line)
|
local function applySyntaxHighlighting(self, line)
|
||||||
local text = line
|
local text = line
|
||||||
local colors = string.rep(tHex[self.get("foreground")], #text)
|
local colors = string.rep(tHex[self.getResolved("foreground")], #text)
|
||||||
local patterns = self.get("syntaxPatterns")
|
local patterns = self.getResolved("syntaxPatterns")
|
||||||
|
|
||||||
for _, syntax in ipairs(patterns) do
|
for _, syntax in ipairs(patterns) do
|
||||||
local start = 1
|
local start = 1
|
||||||
@@ -1111,13 +1111,15 @@ end
|
|||||||
function TextBox:render()
|
function TextBox:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local lines = self.get("lines")
|
local lines = self.getResolved("lines")
|
||||||
local scrollX = self.get("scrollX")
|
local scrollX = self.getResolved("scrollX")
|
||||||
local scrollY = self.get("scrollY")
|
local scrollY = self.getResolved("scrollY")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local fg = tHex[self.get("foreground")]
|
local foreground = self.getResolved("foreground")
|
||||||
local bg = tHex[self.get("background")]
|
local background = self.getResolved("background")
|
||||||
|
local fg = tHex[foreground]
|
||||||
|
local bg = tHex[background]
|
||||||
|
|
||||||
for y = 1, height do
|
for y = 1, height do
|
||||||
local lineNum = y + scrollY
|
local lineNum = y + scrollY
|
||||||
@@ -1130,17 +1132,17 @@ function TextBox:render()
|
|||||||
local padLen = width - #text
|
local padLen = width - #text
|
||||||
if padLen > 0 then
|
if padLen > 0 then
|
||||||
text = text .. string.rep(" ", padLen)
|
text = text .. string.rep(" ", padLen)
|
||||||
colors = colors .. string.rep(tHex[self.get("foreground")], padLen)
|
colors = colors .. string.rep(tHex[foreground], padLen)
|
||||||
end
|
end
|
||||||
|
|
||||||
self:blit(1, y, text, colors, string.rep(bg, #text))
|
self:blit(1, y, text, colors, string.rep(bg, #text))
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:hasState("focused") then
|
if self:hasState("focused") then
|
||||||
local relativeX = self.get("cursorX") - scrollX
|
local relativeX = self.getResolved("cursorX") - scrollX
|
||||||
local relativeY = self.get("cursorY") - scrollY
|
local relativeY = self.getResolved("cursorY") - scrollY
|
||||||
if relativeX >= 1 and relativeX <= width and relativeY >= 1 and relativeY <= height then
|
if relativeX >= 1 and relativeX <= width and relativeY >= 1 and relativeY <= height then
|
||||||
self:setCursor(relativeX, relativeY, true, self.get("cursorColor") or self.get("foreground"))
|
self:setCursor(relativeX, relativeY, true, self.getResolved("cursorColor") or foreground)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ end
|
|||||||
function Timer:start()
|
function Timer:start()
|
||||||
if not self.running then
|
if not self.running then
|
||||||
self.running = true
|
self.running = true
|
||||||
local time = self.get("interval")
|
local time = self.getResolved("interval")
|
||||||
self.timerId = os.startTimer(time)
|
self.timerId = os.startTimer(time)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -70,12 +70,12 @@ function Timer:dispatchEvent(event, ...)
|
|||||||
local timerId = select(1, ...)
|
local timerId = select(1, ...)
|
||||||
if timerId == self.timerId then
|
if timerId == self.timerId then
|
||||||
self.action()
|
self.action()
|
||||||
local amount = self.get("amount")
|
local amount = self.getResolved("amount")
|
||||||
if amount > 0 then
|
if amount > 0 then
|
||||||
self.set("amount", amount - 1)
|
self.set("amount", amount - 1)
|
||||||
end
|
end
|
||||||
if amount ~= 0 then
|
if amount ~= 0 then
|
||||||
self.timerId = os.startTimer(self.get("interval"))
|
self.timerId = os.startTimer(self.getResolved("interval"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ function Toast:show(titleOrMessage, messageOrDuration, duration)
|
|||||||
if type(messageOrDuration) == "string" then
|
if type(messageOrDuration) == "string" then
|
||||||
title = titleOrMessage
|
title = titleOrMessage
|
||||||
message = messageOrDuration
|
message = messageOrDuration
|
||||||
dur = duration or self.get("duration")
|
dur = duration or self.getResolved("duration")
|
||||||
elseif type(messageOrDuration) == "number" then
|
elseif type(messageOrDuration) == "number" then
|
||||||
title = ""
|
title = ""
|
||||||
message = titleOrMessage
|
message = titleOrMessage
|
||||||
@@ -84,7 +84,7 @@ function Toast:show(titleOrMessage, messageOrDuration, duration)
|
|||||||
else
|
else
|
||||||
title = ""
|
title = ""
|
||||||
message = titleOrMessage
|
message = titleOrMessage
|
||||||
dur = self.get("duration")
|
dur = self.getResolved("duration")
|
||||||
end
|
end
|
||||||
|
|
||||||
self.set("title", title)
|
self.set("title", title)
|
||||||
@@ -96,7 +96,7 @@ function Toast:show(titleOrMessage, messageOrDuration, duration)
|
|||||||
self._hideTimerId = nil
|
self._hideTimerId = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.get("autoHide") and dur > 0 then
|
if self.getResolved("autoHide") and dur > 0 then
|
||||||
self._hideTimerId = os.startTimer(dur)
|
self._hideTimerId = os.startTimer(dur)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -179,12 +179,12 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Toast:render()
|
function Toast:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
if not self.get("active") then
|
if not self.getResolved("active") then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local title = self.getResolved("title")
|
local title = self.getResolved("title")
|
||||||
local message = self.getResolved("message")
|
local message = self.getResolved("message")
|
||||||
local toastType = self.getResolved("toastType")
|
local toastType = self.getResolved("toastType")
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ Tree.__index = Tree
|
|||||||
---@property nodes table {} The tree structure containing node objects with {text, children} properties
|
---@property nodes table {} The tree structure containing node objects with {text, children} properties
|
||||||
Tree.defineProperty(Tree, "nodes", {default = {}, type = "table", canTriggerRender = true, setter = function(self, value)
|
Tree.defineProperty(Tree, "nodes", {default = {}, type = "table", canTriggerRender = true, setter = function(self, value)
|
||||||
if #value > 0 then
|
if #value > 0 then
|
||||||
self.get("expandedNodes")[value[1]] = true
|
self.getResolved("expandedNodes")[value[1]] = true
|
||||||
end
|
end
|
||||||
return value
|
return value
|
||||||
end})
|
end})
|
||||||
@@ -210,7 +210,7 @@ end
|
|||||||
--- @param node table The node to expand
|
--- @param node table The node to expand
|
||||||
--- @return Tree self The Tree instance
|
--- @return Tree self The Tree instance
|
||||||
function Tree:expandNode(node)
|
function Tree:expandNode(node)
|
||||||
self.get("expandedNodes")[node] = true
|
self.getResolved("expandedNodes")[node] = true
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -220,7 +220,7 @@ end
|
|||||||
--- @param node table The node to collapse
|
--- @param node table The node to collapse
|
||||||
--- @return Tree self The Tree instance
|
--- @return Tree self The Tree instance
|
||||||
function Tree:collapseNode(node)
|
function Tree:collapseNode(node)
|
||||||
self.get("expandedNodes")[node] = nil
|
self.getResolved("expandedNodes")[node] = nil
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -230,7 +230,7 @@ end
|
|||||||
--- @param node table The node to toggle
|
--- @param node table The node to toggle
|
||||||
--- @return Tree self The Tree instance
|
--- @return Tree self The Tree instance
|
||||||
function Tree:toggleNode(node)
|
function Tree:toggleNode(node)
|
||||||
if self.get("expandedNodes")[node] then
|
if self.getResolved("expandedNodes")[node] then
|
||||||
self:collapseNode(node)
|
self:collapseNode(node)
|
||||||
else
|
else
|
||||||
self:expandNode(node)
|
self:expandNode(node)
|
||||||
@@ -248,10 +248,10 @@ end
|
|||||||
function Tree:mouse_click(button, x, y)
|
function Tree:mouse_click(button, x, y)
|
||||||
if VisualElement.mouse_click(self, button, x, y) then
|
if VisualElement.mouse_click(self, button, x, y) then
|
||||||
local relX, relY = self:getRelativePosition(x, y)
|
local relX, relY = self:getRelativePosition(x, y)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
|
local flatNodes = flattenTree(self.getResolved("nodes"), self.getResolved("expandedNodes"))
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
local maxContentWidth, _ = self:getNodeSize()
|
local maxContentWidth, _ = self:getNodeSize()
|
||||||
local needsHorizontalScrollBar = showScrollBar and maxContentWidth > width
|
local needsHorizontalScrollBar = showScrollBar and maxContentWidth > width
|
||||||
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
@@ -262,7 +262,7 @@ function Tree:mouse_click(button, x, y)
|
|||||||
local handleSize = math.max(1, math.floor((contentHeight / #flatNodes) * scrollHeight))
|
local handleSize = math.max(1, math.floor((contentHeight / #flatNodes) * scrollHeight))
|
||||||
local maxOffset = #flatNodes - contentHeight
|
local maxOffset = #flatNodes - contentHeight
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (self.get("offset") / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (self.getResolved("offset") / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (scrollHeight - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (scrollHeight - handleSize)) + 1
|
||||||
|
|
||||||
if relY >= handlePos and relY < handlePos + handleSize then
|
if relY >= handlePos and relY < handlePos + handleSize then
|
||||||
@@ -281,7 +281,7 @@ function Tree:mouse_click(button, x, y)
|
|||||||
local handleSize = math.max(1, math.floor((contentWidth / maxContentWidth) * contentWidth))
|
local handleSize = math.max(1, math.floor((contentWidth / maxContentWidth) * contentWidth))
|
||||||
local maxOffset = maxContentWidth - contentWidth
|
local maxOffset = maxContentWidth - contentWidth
|
||||||
|
|
||||||
local currentPercent = maxOffset > 0 and (self.get("horizontalOffset") / maxOffset * 100) or 0
|
local currentPercent = maxOffset > 0 and (self.getResolved("horizontalOffset") / maxOffset * 100) or 0
|
||||||
local handlePos = math.floor((currentPercent / 100) * (contentWidth - handleSize)) + 1
|
local handlePos = math.floor((currentPercent / 100) * (contentWidth - handleSize)) + 1
|
||||||
|
|
||||||
if relX >= handlePos and relX < handlePos + handleSize then
|
if relX >= handlePos and relX < handlePos + handleSize then
|
||||||
@@ -295,7 +295,7 @@ function Tree:mouse_click(button, x, y)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local visibleIndex = relY + self.get("offset")
|
local visibleIndex = relY + self.getResolved("offset")
|
||||||
|
|
||||||
if flatNodes[visibleIndex] then
|
if flatNodes[visibleIndex] then
|
||||||
local nodeInfo = flatNodes[visibleIndex]
|
local nodeInfo = flatNodes[visibleIndex]
|
||||||
@@ -331,10 +331,10 @@ end
|
|||||||
function Tree:mouse_drag(button, x, y)
|
function Tree:mouse_drag(button, x, y)
|
||||||
if self._scrollBarDragging then
|
if self._scrollBarDragging then
|
||||||
local _, relY = self:getRelativePosition(x, y)
|
local _, relY = self:getRelativePosition(x, y)
|
||||||
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
|
local flatNodes = flattenTree(self.getResolved("nodes"), self.getResolved("expandedNodes"))
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local maxContentWidth, _ = self:getNodeSize()
|
local maxContentWidth, _ = self:getNodeSize()
|
||||||
local needsHorizontalScrollBar = self.get("showScrollBar") and maxContentWidth > self.get("width")
|
local needsHorizontalScrollBar = self.getResolved("showScrollBar") and maxContentWidth > self.getResolved("width")
|
||||||
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local scrollHeight = contentHeight
|
local scrollHeight = contentHeight
|
||||||
local handleSize = math.max(1, math.floor((contentHeight / #flatNodes) * scrollHeight))
|
local handleSize = math.max(1, math.floor((contentHeight / #flatNodes) * scrollHeight))
|
||||||
@@ -352,13 +352,13 @@ function Tree:mouse_drag(button, x, y)
|
|||||||
|
|
||||||
if self._hScrollBarDragging then
|
if self._hScrollBarDragging then
|
||||||
local relX, _ = self:getRelativePosition(x, y)
|
local relX, _ = self:getRelativePosition(x, y)
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local maxContentWidth, _ = self:getNodeSize()
|
local maxContentWidth, _ = self:getNodeSize()
|
||||||
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
|
local flatNodes = flattenTree(self.getResolved("nodes"), self.getResolved("expandedNodes"))
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local needsHorizontalScrollBar = self.get("showScrollBar") and maxContentWidth > width
|
local needsHorizontalScrollBar = self.getResolved("showScrollBar") and maxContentWidth > width
|
||||||
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local needsVerticalScrollBar = self.get("showScrollBar") and #flatNodes > contentHeight
|
local needsVerticalScrollBar = self.getResolved("showScrollBar") and #flatNodes > contentHeight
|
||||||
local contentWidth = needsVerticalScrollBar and width - 1 or width
|
local contentWidth = needsVerticalScrollBar and width - 1 or width
|
||||||
local handleSize = math.max(1, math.floor((contentWidth / maxContentWidth) * contentWidth))
|
local handleSize = math.max(1, math.floor((contentWidth / maxContentWidth) * contentWidth))
|
||||||
local maxOffset = maxContentWidth - contentWidth
|
local maxOffset = maxContentWidth - contentWidth
|
||||||
@@ -406,15 +406,15 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Tree:mouse_scroll(direction, x, y)
|
function Tree:mouse_scroll(direction, x, y)
|
||||||
if VisualElement.mouse_scroll(self, direction, x, y) then
|
if VisualElement.mouse_scroll(self, direction, x, y) then
|
||||||
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
|
local flatNodes = flattenTree(self.getResolved("nodes"), self.getResolved("expandedNodes"))
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
local maxContentWidth, _ = self:getNodeSize()
|
local maxContentWidth, _ = self:getNodeSize()
|
||||||
local needsHorizontalScrollBar = showScrollBar and maxContentWidth > width
|
local needsHorizontalScrollBar = showScrollBar and maxContentWidth > width
|
||||||
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
local maxScroll = math.max(0, #flatNodes - contentHeight)
|
local maxScroll = math.max(0, #flatNodes - contentHeight)
|
||||||
local newScroll = math.min(maxScroll, math.max(0, self.get("offset") + direction))
|
local newScroll = math.min(maxScroll, math.max(0, self.getResolved("offset") + direction))
|
||||||
|
|
||||||
self.set("offset", newScroll)
|
self.set("offset", newScroll)
|
||||||
return true
|
return true
|
||||||
@@ -428,8 +428,8 @@ end
|
|||||||
--- @return number height The height of the tree
|
--- @return number height The height of the tree
|
||||||
function Tree:getNodeSize()
|
function Tree:getNodeSize()
|
||||||
local width, height = 0, 0
|
local width, height = 0, 0
|
||||||
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
|
local flatNodes = flattenTree(self.getResolved("nodes"), self.getResolved("expandedNodes"))
|
||||||
local expandedNodes = self.get("expandedNodes")
|
local expandedNodes = self.getResolved("expandedNodes")
|
||||||
|
|
||||||
for _, nodeInfo in ipairs(flatNodes) do
|
for _, nodeInfo in ipairs(flatNodes) do
|
||||||
local node = nodeInfo.node
|
local node = nodeInfo.node
|
||||||
@@ -453,14 +453,14 @@ end
|
|||||||
function Tree:render()
|
function Tree:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
|
local flatNodes = flattenTree(self.getResolved("nodes"), self.getResolved("expandedNodes"))
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
local selectedNode = self.get("selectedNode")
|
local selectedNode = self.getResolved("selectedNode")
|
||||||
local expandedNodes = self.get("expandedNodes")
|
local expandedNodes = self.getResolved("expandedNodes")
|
||||||
local offset = self.get("offset")
|
local offset = self.getResolved("offset")
|
||||||
local horizontalOffset = self.get("horizontalOffset")
|
local horizontalOffset = self.getResolved("horizontalOffset")
|
||||||
local showScrollBar = self.get("showScrollBar")
|
local showScrollBar = self.getResolved("showScrollBar")
|
||||||
local maxContentWidth, _ = self:getNodeSize()
|
local maxContentWidth, _ = self:getNodeSize()
|
||||||
local needsHorizontalScrollBar = showScrollBar and maxContentWidth > width
|
local needsHorizontalScrollBar = showScrollBar and maxContentWidth > width
|
||||||
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
local contentHeight = needsHorizontalScrollBar and height - 1 or height
|
||||||
@@ -480,8 +480,8 @@ function Tree:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local isSelected = node == selectedNode
|
local isSelected = node == selectedNode
|
||||||
local _bg = isSelected and self.get("selectedBackgroundColor") or (node.background or node.bg or self.get("background"))
|
local _bg = isSelected and self.getResolved("selectedBackgroundColor") or (node.background or node.bg or self.getResolved("background"))
|
||||||
local _fg = isSelected and self.get("selectedForegroundColor") or (node.foreground or node.fg or self.get("foreground"))
|
local _fg = isSelected and self.getResolved("selectedForegroundColor") or (node.foreground or node.fg or self.getResolved("foreground"))
|
||||||
|
|
||||||
local fullText = indent .. symbol .. " " .. (node.text or "Node")
|
local fullText = indent .. symbol .. " " .. (node.text or "Node")
|
||||||
local text = sub(fullText, horizontalOffset + 1, horizontalOffset + contentWidth)
|
local text = sub(fullText, horizontalOffset + 1, horizontalOffset + contentWidth)
|
||||||
@@ -492,7 +492,7 @@ function Tree:render()
|
|||||||
|
|
||||||
self:blit(1, y, paddedText, fg, bg)
|
self:blit(1, y, paddedText, fg, bg)
|
||||||
else
|
else
|
||||||
self:blit(1, y, string.rep(" ", contentWidth), tHex[self.get("foreground")]:rep(contentWidth), tHex[self.get("background")]:rep(contentWidth))
|
self:blit(1, y, string.rep(" ", contentWidth), tHex[self.getResolved("foreground")]:rep(contentWidth), tHex[self.getResolved("background")]:rep(contentWidth))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -537,7 +537,7 @@ function Tree:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if needsVerticalScrollBar and needsHorizontalScrollBar then
|
if needsVerticalScrollBar and needsHorizontalScrollBar then
|
||||||
self:blit(width, height, " ", tHex[foreground], tHex[self.get("background")])
|
self:blit(width, height, " ", tHex[foreground], tHex[self.getResolved("background")])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ end
|
|||||||
--- @param offset number The offset to apply (negative = inside, positive = outside, fractional = percentage)
|
--- @param offset number The offset to apply (negative = inside, positive = outside, fractional = percentage)
|
||||||
--- @return VisualElement self The element instance
|
--- @return VisualElement self The element instance
|
||||||
function VisualElement:setConstraint(property, targetElement, targetProperty, offset)
|
function VisualElement:setConstraint(property, targetElement, targetProperty, offset)
|
||||||
local constraints = self.get("constraints")
|
local constraints = self.getResolved("constraints")
|
||||||
if constraints[property] then
|
if constraints[property] then
|
||||||
self:_removeConstraintObservers(property, constraints[property])
|
self:_removeConstraintObservers(property, constraints[property])
|
||||||
end
|
end
|
||||||
@@ -187,7 +187,7 @@ end
|
|||||||
--- @param value any The value to set for the property
|
--- @param value any The value to set for the property
|
||||||
--- @return VisualElement self The element instance
|
--- @return VisualElement self The element instance
|
||||||
function VisualElement:setLayoutConfigProperty(key, value)
|
function VisualElement:setLayoutConfigProperty(key, value)
|
||||||
local layoutConfig = self.get("layoutConfig")
|
local layoutConfig = self.getResolved("layoutConfig")
|
||||||
layoutConfig[key] = value
|
layoutConfig[key] = value
|
||||||
self.set("layoutConfig", layoutConfig)
|
self.set("layoutConfig", layoutConfig)
|
||||||
return self
|
return self
|
||||||
@@ -198,7 +198,7 @@ end
|
|||||||
--- @param key string The layout config property to get
|
--- @param key string The layout config property to get
|
||||||
--- @return any value The value of the property, or nil if not set
|
--- @return any value The value of the property, or nil if not set
|
||||||
function VisualElement:getLayoutConfigProperty(key)
|
function VisualElement:getLayoutConfigProperty(key)
|
||||||
local layoutConfig = self.get("layoutConfig")
|
local layoutConfig = self.getResolved("layoutConfig")
|
||||||
return layoutConfig[key]
|
return layoutConfig[key]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ end
|
|||||||
--- @return VisualElement self The element instance
|
--- @return VisualElement self The element instance
|
||||||
function VisualElement:resolveAllConstraints()
|
function VisualElement:resolveAllConstraints()
|
||||||
if not self._constraintsDirty then return self end
|
if not self._constraintsDirty then return self end
|
||||||
local constraints = self.get("constraints")
|
local constraints = self.getResolved("constraints")
|
||||||
if not constraints or not next(constraints) then return self end
|
if not constraints or not next(constraints) then return self end
|
||||||
|
|
||||||
local order = {"width", "height", "left", "right", "top", "bottom", "x", "y", "centerX", "centerY"}
|
local order = {"width", "height", "left", "right", "top", "bottom", "x", "y", "centerX", "centerY"}
|
||||||
@@ -236,7 +236,7 @@ function VisualElement:_applyConstraintValue(property, value, constraints)
|
|||||||
self.set("width", width)
|
self.set("width", width)
|
||||||
self.set("x", leftValue)
|
self.set("x", leftValue)
|
||||||
else
|
else
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
self.set("x", value - width + 1)
|
self.set("x", value - width + 1)
|
||||||
end
|
end
|
||||||
elseif property == "bottom" then
|
elseif property == "bottom" then
|
||||||
@@ -246,14 +246,14 @@ function VisualElement:_applyConstraintValue(property, value, constraints)
|
|||||||
self.set("height", height)
|
self.set("height", height)
|
||||||
self.set("y", topValue)
|
self.set("y", topValue)
|
||||||
else
|
else
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
self.set("y", value - height + 1)
|
self.set("y", value - height + 1)
|
||||||
end
|
end
|
||||||
elseif property == "centerX" then
|
elseif property == "centerX" then
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
self.set("x", value - math.floor(width / 2))
|
self.set("x", value - math.floor(width / 2))
|
||||||
elseif property == "centerY" then
|
elseif property == "centerY" then
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
self.set("y", value - math.floor(height / 2))
|
self.set("y", value - math.floor(height / 2))
|
||||||
elseif property == "width" then
|
elseif property == "width" then
|
||||||
self.set("width", value)
|
self.set("width", value)
|
||||||
@@ -351,7 +351,7 @@ end
|
|||||||
--- @param property string The property of the constraint to remove
|
--- @param property string The property of the constraint to remove
|
||||||
--- @return VisualElement self The element instance
|
--- @return VisualElement self The element instance
|
||||||
function VisualElement:removeConstraint(property)
|
function VisualElement:removeConstraint(property)
|
||||||
local constraints = self.get("constraints")
|
local constraints = self.getResolved("constraints")
|
||||||
constraints[property] = nil
|
constraints[property] = nil
|
||||||
self.set("constraints", constraints)
|
self.set("constraints", constraints)
|
||||||
self:updateConstraints()
|
self:updateConstraints()
|
||||||
@@ -362,7 +362,7 @@ end
|
|||||||
--- @shortDescription Updates all constraints, recalculating positions and sizes
|
--- @shortDescription Updates all constraints, recalculating positions and sizes
|
||||||
--- @return VisualElement self The element instance
|
--- @return VisualElement self The element instance
|
||||||
function VisualElement:updateConstraints()
|
function VisualElement:updateConstraints()
|
||||||
local constraints = self.get("constraints")
|
local constraints = self.getResolved("constraints")
|
||||||
|
|
||||||
for property, constraint in pairs(constraints) do
|
for property, constraint in pairs(constraints) do
|
||||||
local value = self:_resolveConstraint(property, constraint)
|
local value = self:_resolveConstraint(property, constraint)
|
||||||
@@ -372,16 +372,16 @@ function VisualElement:updateConstraints()
|
|||||||
elseif property == "y" or property == "top" then
|
elseif property == "y" or property == "top" then
|
||||||
self.set("y", value)
|
self.set("y", value)
|
||||||
elseif property == "right" then
|
elseif property == "right" then
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
self.set("x", value - width + 1)
|
self.set("x", value - width + 1)
|
||||||
elseif property == "bottom" then
|
elseif property == "bottom" then
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
self.set("y", value - height + 1)
|
self.set("y", value - height + 1)
|
||||||
elseif property == "centerX" then
|
elseif property == "centerX" then
|
||||||
local width = self.get("width")
|
local width = self.getResolved("width")
|
||||||
self.set("x", value - math.floor(width / 2))
|
self.set("x", value - math.floor(width / 2))
|
||||||
elseif property == "centerY" then
|
elseif property == "centerY" then
|
||||||
local height = self.get("height")
|
local height = self.getResolved("height")
|
||||||
self.set("y", value - math.floor(height / 2))
|
self.set("y", value - math.floor(height / 2))
|
||||||
elseif property == "width" then
|
elseif property == "width" then
|
||||||
self.set("width", value)
|
self.set("width", value)
|
||||||
@@ -403,7 +403,7 @@ function VisualElement:_resolveConstraint(property, constraint)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not targetEl then
|
if not targetEl then
|
||||||
return self.get(property) or 1
|
return self.getResolved(property) or 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local value
|
local value
|
||||||
@@ -761,9 +761,9 @@ end
|
|||||||
--- @param y number The y position to check
|
--- @param y number The y position to check
|
||||||
--- @return boolean isInBounds Whether the coordinates are within the bounds of the element
|
--- @return boolean isInBounds Whether the coordinates are within the bounds of the element
|
||||||
function VisualElement:isInBounds(x, y)
|
function VisualElement:isInBounds(x, y)
|
||||||
local xPos, yPos = self.get("x"), self.get("y")
|
local xPos, yPos = self.getResolved("x"), self.getResolved("y")
|
||||||
local width, height = self.get("width"), self.get("height")
|
local width, height = self.getResolved("width"), self.getResolved("height")
|
||||||
if(self.get("ignoreOffset"))then
|
if(self.getResolved("ignoreOffset"))then
|
||||||
if(self.parent)then
|
if(self.parent)then
|
||||||
x = x - self.parent.get("offsetX")
|
x = x - self.parent.get("offsetX")
|
||||||
y = y - self.parent.get("offsetY")
|
y = y - self.parent.get("offsetY")
|
||||||
@@ -824,7 +824,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function VisualElement:mouse_move(_, x, y)
|
function VisualElement:mouse_move(_, x, y)
|
||||||
if(x==nil)or(y==nil)then return false end
|
if(x==nil)or(y==nil)then return false end
|
||||||
local hover = self.get("hover")
|
local hover = self.getResolved("hover")
|
||||||
if(self:isInBounds(x, y))then
|
if(self:isInBounds(x, y))then
|
||||||
if(not hover)then
|
if(not hover)then
|
||||||
self.set("hover", true)
|
self.set("hover", true)
|
||||||
@@ -1000,8 +1000,8 @@ end
|
|||||||
--- @return number y The y position
|
--- @return number y The y position
|
||||||
function VisualElement:calculatePosition()
|
function VisualElement:calculatePosition()
|
||||||
self:resolveAllConstraints()
|
self:resolveAllConstraints()
|
||||||
local x, y = self.get("x"), self.get("y")
|
local x, y = self.getResolved("x"), self.getResolved("y")
|
||||||
if not self.get("ignoreOffset") then
|
if not self.getResolved("ignoreOffset") then
|
||||||
if self.parent ~= nil then
|
if self.parent ~= nil then
|
||||||
local xO, yO = self.parent.get("offsetX"), self.parent.get("offsetY")
|
local xO, yO = self.parent.get("offsetX"), self.parent.get("offsetY")
|
||||||
x = x - xO
|
x = x - xO
|
||||||
@@ -1018,7 +1018,7 @@ end
|
|||||||
---@return number x The absolute x position
|
---@return number x The absolute x position
|
||||||
---@return number y The absolute y position
|
---@return number y The absolute y position
|
||||||
function VisualElement:getAbsolutePosition(x, y)
|
function VisualElement:getAbsolutePosition(x, y)
|
||||||
local xPos, yPos = self.get("x"), self.get("y")
|
local xPos, yPos = self.getResolved("x"), self.getResolved("y")
|
||||||
if(x ~= nil) then
|
if(x ~= nil) then
|
||||||
xPos = xPos + x - 1
|
xPos = xPos + x - 1
|
||||||
end
|
end
|
||||||
@@ -1045,7 +1045,7 @@ end
|
|||||||
--- @return number y The relative y position
|
--- @return number y The relative y position
|
||||||
function VisualElement:getRelativePosition(x, y)
|
function VisualElement:getRelativePosition(x, y)
|
||||||
if (x == nil) or (y == nil) then
|
if (x == nil) or (y == nil) then
|
||||||
x, y = self.get("x"), self.get("y")
|
x, y = self.getResolved("x"), self.getResolved("y")
|
||||||
end
|
end
|
||||||
|
|
||||||
local parentX, parentY = 1, 1
|
local parentX, parentY = 1, 1
|
||||||
@@ -1053,7 +1053,7 @@ function VisualElement:getRelativePosition(x, y)
|
|||||||
parentX, parentY = self.parent:getRelativePosition()
|
parentX, parentY = self.parent:getRelativePosition()
|
||||||
end
|
end
|
||||||
|
|
||||||
local elementX, elementY = self.get("x"), self.get("y")
|
local elementX, elementY = self.getResolved("x"), self.getResolved("y")
|
||||||
return x - (elementX - 1) - (parentX - 1),
|
return x - (elementX - 1) - (parentX - 1),
|
||||||
y - (elementY - 1) - (parentY - 1)
|
y - (elementY - 1) - (parentY - 1)
|
||||||
end
|
end
|
||||||
@@ -1094,7 +1094,7 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function VisualElement:render()
|
function VisualElement:render()
|
||||||
if(not self.getResolved("backgroundEnabled"))then return end
|
if(not self.getResolved("backgroundEnabled"))then return end
|
||||||
local width, height = self.get("width"), self.get("height")
|
local width, height = self.getResolved("width"), self.getResolved("height")
|
||||||
local fgHex = tHex[self.getResolved("foreground")]
|
local fgHex = tHex[self.getResolved("foreground")]
|
||||||
local bgHex = tHex[self.getResolved("background")]
|
local bgHex = tHex[self.getResolved("background")]
|
||||||
local bTop, bBottom, bLeft, bRight =
|
local bTop, bBottom, bLeft, bRight =
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ local function parseExpression(expr, element, propName)
|
|||||||
if objName == "self" then
|
if objName == "self" then
|
||||||
-- Check if property exists
|
-- Check if property exists
|
||||||
if element._properties[propName] then
|
if element._properties[propName] then
|
||||||
return element.get(propName)
|
return element.getResolved(propName)
|
||||||
end
|
end
|
||||||
if element._registeredStates and element._registeredStates[propName] then
|
if element._registeredStates and element._registeredStates[propName] then
|
||||||
return element:hasState(propName)
|
return element:hasState(propName)
|
||||||
@@ -104,7 +104,7 @@ local function parseExpression(expr, element, propName)
|
|||||||
return nil
|
return nil
|
||||||
elseif objName == "parent" then
|
elseif objName == "parent" then
|
||||||
if element.parent._properties[propName] then
|
if element.parent._properties[propName] then
|
||||||
return element.parent.get(propName)
|
return element.parent.getResolved(propName)
|
||||||
end
|
end
|
||||||
if element.parent._registeredStates and element.parent._registeredStates[propName] then
|
if element.parent._registeredStates and element.parent._registeredStates[propName] then
|
||||||
return element.parent:hasState(propName)
|
return element.parent:hasState(propName)
|
||||||
@@ -125,7 +125,7 @@ local function parseExpression(expr, element, propName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if target._properties[propName] then
|
if target._properties[propName] then
|
||||||
return target.get(propName)
|
return target.getResolved(propName)
|
||||||
end
|
end
|
||||||
if target._registeredStates and target._registeredStates[propName] then
|
if target._registeredStates and target._registeredStates[propName] then
|
||||||
return target:hasState(propName)
|
return target:hasState(propName)
|
||||||
|
|||||||
157
src/plugins/responsive.lua
Normal file
157
src/plugins/responsive.lua
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
local errorManager = require("errorManager")
|
||||||
|
---@configDefault false
|
||||||
|
|
||||||
|
--- This is the responsive plugin. It provides a fluent builder API for creating responsive states with an intuitive when/apply/otherwise syntax.
|
||||||
|
---@class BaseElement
|
||||||
|
local BaseElement = {}
|
||||||
|
|
||||||
|
--- Creates a responsive builder for defining responsive states
|
||||||
|
--- @shortDescription Creates a responsive state builder
|
||||||
|
--- @param self BaseElement The element to create the builder for
|
||||||
|
--- @return ResponsiveBuilder builder The responsive builder instance
|
||||||
|
function BaseElement:responsive()
|
||||||
|
local builder = {
|
||||||
|
_element = self,
|
||||||
|
_rules = {},
|
||||||
|
_currentStateName = nil,
|
||||||
|
_currentCondition = nil,
|
||||||
|
_stateCounter = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Defines a condition for responsive behavior
|
||||||
|
--- @param condition string|function The condition as string expression or function
|
||||||
|
--- @return ResponsiveBuilder self For method chaining
|
||||||
|
function builder:when(condition)
|
||||||
|
if self._currentCondition then
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("Previous when() must be followed by apply() before starting a new when()")
|
||||||
|
end
|
||||||
|
|
||||||
|
self._stateCounter = self._stateCounter + 1
|
||||||
|
self._currentStateName = "__responsive_" .. self._stateCounter
|
||||||
|
self._currentCondition = condition
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Applies properties when the current condition is met
|
||||||
|
--- @param properties table The properties to apply {property = value, ...}
|
||||||
|
--- @return ResponsiveBuilder self For method chaining
|
||||||
|
function builder:apply(properties)
|
||||||
|
if not self._currentCondition then
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("apply() must follow a when() call")
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(properties) ~= "table" then
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("apply() requires a table of properties")
|
||||||
|
end
|
||||||
|
|
||||||
|
self._element:registerResponsiveState(
|
||||||
|
self._currentStateName,
|
||||||
|
self._currentCondition,
|
||||||
|
100
|
||||||
|
)
|
||||||
|
|
||||||
|
for propName, value in pairs(properties) do
|
||||||
|
local capitalizedName = propName:sub(1,1):upper() .. propName:sub(2)
|
||||||
|
local setter = "set" .. capitalizedName .. "State"
|
||||||
|
|
||||||
|
if self._element[setter] then
|
||||||
|
self._element[setter](self._element, self._currentStateName, value)
|
||||||
|
else
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("Unknown property: " .. propName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(self._rules, {
|
||||||
|
stateName = self._currentStateName,
|
||||||
|
condition = self._currentCondition,
|
||||||
|
properties = properties
|
||||||
|
})
|
||||||
|
|
||||||
|
self._currentCondition = nil
|
||||||
|
self._currentStateName = nil
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Defines a fallback condition (else case)
|
||||||
|
--- @param properties table The properties to apply when no other conditions match
|
||||||
|
--- @return ResponsiveBuilder self For method chaining
|
||||||
|
function builder:otherwise(properties)
|
||||||
|
if self._currentCondition then
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("otherwise() cannot be used after when() without apply()")
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(properties) ~= "table" then
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("otherwise() requires a table of properties")
|
||||||
|
end
|
||||||
|
|
||||||
|
self._stateCounter = self._stateCounter + 1
|
||||||
|
local otherwiseStateName = "__responsive_otherwise_" .. self._stateCounter
|
||||||
|
|
||||||
|
local otherRules = {}
|
||||||
|
for _, rule in ipairs(self._rules) do
|
||||||
|
table.insert(otherRules, rule.condition)
|
||||||
|
end
|
||||||
|
|
||||||
|
local otherwiseCondition
|
||||||
|
if type(otherRules[1]) == "string" then
|
||||||
|
local negatedExprs = {}
|
||||||
|
for _, cond in ipairs(otherRules) do
|
||||||
|
table.insert(negatedExprs, "not (" .. cond .. ")")
|
||||||
|
end
|
||||||
|
otherwiseCondition = table.concat(negatedExprs, " and ")
|
||||||
|
else
|
||||||
|
otherwiseCondition = function(elem)
|
||||||
|
for _, cond in ipairs(otherRules) do
|
||||||
|
if cond(elem) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self._element:registerResponsiveState(
|
||||||
|
otherwiseStateName,
|
||||||
|
otherwiseCondition,
|
||||||
|
50
|
||||||
|
)
|
||||||
|
|
||||||
|
for propName, value in pairs(properties) do
|
||||||
|
local capitalizedName = propName:sub(1,1):upper() .. propName:sub(2)
|
||||||
|
local setter = "set" .. capitalizedName .. "State"
|
||||||
|
|
||||||
|
if self._element[setter] then
|
||||||
|
self._element[setter](self._element, otherwiseStateName, value)
|
||||||
|
else
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("Unknown property: " .. propName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Completes the builder (optional, for clarity)
|
||||||
|
--- @return BaseElement element The original element
|
||||||
|
function builder:done()
|
||||||
|
if self._currentCondition then
|
||||||
|
errorManager.header = "Responsive Builder Error"
|
||||||
|
errorManager.error("Unfinished when() without apply()")
|
||||||
|
end
|
||||||
|
return self._element
|
||||||
|
end
|
||||||
|
|
||||||
|
return builder
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
BaseElement = BaseElement
|
||||||
|
}
|
||||||
@@ -335,12 +335,16 @@ function PropertySystem:__init()
|
|||||||
end
|
end
|
||||||
|
|
||||||
self.getResolved = function(name, ...)
|
self.getResolved = function(name, ...)
|
||||||
local currentState = self:getCurrentState()
|
local activeStates = self:getActiveStates()
|
||||||
local value
|
local value = nil
|
||||||
|
for _, stateInfo in ipairs(activeStates) do
|
||||||
|
if self._states and self._states[stateInfo.name] and self._states[stateInfo.name][name] ~= nil then
|
||||||
|
value = self._states[stateInfo.name][name]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if currentState and self._states and self._states[currentState] and self._states[currentState][name] ~= nil then
|
if value == nil then
|
||||||
value = self._states[currentState][name]
|
|
||||||
else
|
|
||||||
value = self._values[name]
|
value = self._values[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user