Dropdown Fix
Progressbar Fix List 2 new Methods: scrollToBottom scrollToTop Readme Update Generate-config size addition
This commit is contained in:
20
README.md
20
README.md
@@ -1,30 +1,28 @@
|
||||
# Basalt - A UI Framework for CC:Tweaked
|
||||
# Basalt 2 - A UI Framework for CC:Tweaked
|
||||
|
||||

|
||||
[](https://discord.gg/yNNnmBVBpE)
|
||||
|
||||
This is a complete rework of Basalt. It provides an intuitive way to create complex user interfaces for your CC:Tweaked programs.
|
||||
Welcome,
|
||||
|
||||
Basalt is intended to be an easy-to-understand UI Framework designed for CC:Tweaked - a popular minecraft mod. For more information about CC:Tweaked, checkout the project's [wiki](https://tweaked.cc/) or [download](https://modrinth.com/mod/cc-tweaked).
|
||||
**Note:** Basalt is still under developement and you may find bugs!
|
||||
This is a complete rework of [Basalt](https://github.com/Pyroxenium/Basalt). There are many new features, including auto-generated LuaLS annotations and auto-generated documentation, ensuring that everything is always up-to-date.
|
||||
|
||||
Check out the [wiki](https://basalt.madefor.cc/) for more information.
|
||||
If you have questions, feel free to join the discord server: [discord.gg/yNNnmBVBpE](https://discord.gg/yNNnmBVBpE).
|
||||
Basalt is a UI framework designed for [CC:Tweaked](https://tweaked.cc/) - a popular Minecraft mod. For more information about CC:Tweaked, check out the project's [wiki](https://tweaked.cc/) or download it from [Modrinth](https://modrinth.com/mod/cc-tweaked) or [CurseForge](https://www.curseforge.com/minecraft/mc-mods/cc-tweaked).
|
||||
|
||||
## Documentation
|
||||
|
||||
For detailed documentation, examples and guides, visit [basalt.madefor.cc](https://basalt.madefor.cc/)
|
||||
For detailed documentation, examples, and guides, visit our documentation on [basalt.madefor.cc](https://basalt.madefor.cc/).
|
||||
|
||||
## Support
|
||||
|
||||
If you need help or have questions:
|
||||
- Check the [documentation](https://basalt.madefor.cc/)
|
||||
- Join our [Discord](https://discord.gg/yNNnmBVBpE)
|
||||
- Report issues on [GitHub](https://github.com/Pyroxenium/Basalt2/issues)
|
||||
- Check the [documentation](https://basalt.madefor.cc/).
|
||||
- Join our [Discord](https://discord.gg/yNNnmBVBpE).
|
||||
- Report issues or contribute on [GitHub](https://github.com/Pyroxenium/Basalt2/issues).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License.
|
||||
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).
|
||||
|
||||
## Demo
|
||||
|
||||
|
||||
84
install.lua
84
install.lua
@@ -1,4 +1,5 @@
|
||||
local basalt = require("src")
|
||||
local url = "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/src/"
|
||||
local configPath = "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/config.lua"
|
||||
|
||||
local coloring = {foreground=colors.black, background=colors.white}
|
||||
@@ -135,19 +136,33 @@ end)
|
||||
|
||||
installScreen:addLabel(coloring)
|
||||
:setText("Path:")
|
||||
:setPosition(2, "{versionDesc.y + versionDesc.height + 1}")
|
||||
:setPosition(2, "{versionDesc.y + versionDesc.height + 5}")
|
||||
|
||||
installScreen:addLabel(coloring)
|
||||
:setText("Additional Components:")
|
||||
:setPosition(2, "{versionDesc.y + versionDesc.height + 1}")
|
||||
|
||||
local luaLSCheckbox = installScreen:addCheckbox()
|
||||
:setPosition(2, 12)
|
||||
local luaLSCheckbox = installScreen:addCheckbox()
|
||||
:setText("[ ] LLS definitions")
|
||||
:setCheckedText("[x] LLS definitions")
|
||||
:setPosition(2, "{versionDesc.y + versionDesc.height + 2}")
|
||||
:setBackground(colors.white)
|
||||
:setForeground(colors.black)
|
||||
|
||||
local luaMinifyCheckbox = installScreen:addCheckbox()
|
||||
:setText("[ ] Minify Project")
|
||||
:setCheckedText("[x] Minify Project")
|
||||
:setPosition(2, "{versionDesc.y + versionDesc.height + 3}")
|
||||
:setBackground(colors.white)
|
||||
:setForeground(colors.black)
|
||||
|
||||
local installPathInput = installScreen:addInput()
|
||||
:setPosition(8, "{versionDesc.y + versionDesc.height + 5}")
|
||||
:setPlaceholder("basalt")
|
||||
:setSize(12, 1)
|
||||
:setBackground(colors.black)
|
||||
:setForeground(colors.white)
|
||||
|
||||
-- Screen 3: Elements
|
||||
local elementsScreen = createScreen(3)
|
||||
elementsScreen:addLabel(coloring)
|
||||
@@ -179,7 +194,13 @@ local eleScreenDesc = elementsScreen:addLabel()
|
||||
local function addElements()
|
||||
elementsList:clear()
|
||||
for k,v in pairs(getConfig().categories.elements.files)do
|
||||
elementsList:addItem({selected=true, text=v.name, callback=function() elementDesc:setText(v.description) end})
|
||||
elementsList:addItem({selected=v.default, text=k, item=v, callback=function()
|
||||
if(v.description)and(v.description~="")then
|
||||
elementDesc:setText(v.description)
|
||||
else
|
||||
elementDesc:setText("No description available.")
|
||||
end
|
||||
end})
|
||||
end
|
||||
end
|
||||
addElements()
|
||||
@@ -215,11 +236,24 @@ local pluScreenDesc = pluginScreen:addLabel()
|
||||
local function addPlugins()
|
||||
pluginList:clear()
|
||||
for k,v in pairs(getConfig().categories.plugins.files)do
|
||||
pluginList:addItem({selected = true, text= v.name, callback=function() pluginDesc:setText(v.description) end})
|
||||
pluginList:addItem({selected = v.default, text=k, item=v, callback=function()
|
||||
if(v.description)and(v.description~="")then
|
||||
elementDesc:setText(v.description)
|
||||
else
|
||||
elementDesc:setText("No description available.")
|
||||
end
|
||||
end})
|
||||
|
||||
end
|
||||
end
|
||||
addPlugins()
|
||||
|
||||
local function tableGet(t)
|
||||
local count = 0
|
||||
for _ in pairs(t) do count = count + 1 end
|
||||
return count
|
||||
end
|
||||
|
||||
-- Screen 5 Installation Progress
|
||||
local progressScreen = createScreen(5)
|
||||
local progressBar = progressScreen:addProgressBar()
|
||||
@@ -234,8 +268,14 @@ local log = progressScreen:addList("log")
|
||||
local function install()
|
||||
local function logMessage(message)
|
||||
log:addItem(message)
|
||||
log:scrollToBottom()
|
||||
end
|
||||
|
||||
local fileCount = tableGet(getConfig().categories.core.files) + tableGet(getConfig().categories.libraries.files)
|
||||
fileCount = fileCount + tableGet(elementsList:getSelectedItems()) + tableGet(pluginList:getSelectedItems())
|
||||
progressBar:setProgress(0)
|
||||
local progressStep = math.ceil(100 / fileCount)
|
||||
|
||||
local function downloadFile(url, path)
|
||||
logMessage("Downloading " .. url .. "...")
|
||||
local request = http.get(url)
|
||||
@@ -250,25 +290,43 @@ local function install()
|
||||
end
|
||||
end
|
||||
|
||||
local function installElement(name, url)
|
||||
local path = installPathInput:getText()
|
||||
if path == "" then
|
||||
path = "basalt"
|
||||
end
|
||||
|
||||
for k, v in pairs(getConfig().categories.core.files) do
|
||||
logMessage("Installing core: " .. k)
|
||||
downloadFile(url..v.path, fs.combine(path, v.path))
|
||||
progressBar:setProgress(progressBar:getProgress() + progressStep)
|
||||
end
|
||||
|
||||
for k, v in pairs(getConfig().categories.libraries.files) do
|
||||
logMessage("Installing library: " .. k)
|
||||
downloadFile(url..v.path, fs.combine(path, v.path))
|
||||
progressBar:setProgress(progressBar:getProgress() + progressStep)
|
||||
end
|
||||
|
||||
local function installElement(name, item)
|
||||
logMessage("Installing element: " .. name)
|
||||
--downloadFile(url, "/path/to/install/" .. name)
|
||||
downloadFile(url..item.path, fs.combine(path, item.path))
|
||||
progressBar:setProgress(progressBar:getProgress() + progressStep)
|
||||
end
|
||||
|
||||
local function installPlugin(name, url)
|
||||
local function installPlugin(name, item)
|
||||
logMessage("Installing plugin: " .. name)
|
||||
--downloadFile(url, "/path/to/install/" .. name)
|
||||
downloadFile(url..item.path, fs.combine(path, item.path))
|
||||
progressBar:setProgress(progressBar:getProgress() + progressStep)
|
||||
end
|
||||
|
||||
for _, element in ipairs(elementsList:getSelectedItems()) do
|
||||
for k, element in ipairs(elementsList:getSelectedItems()) do
|
||||
local item = element.item
|
||||
basalt.LOGGER.debug(item.text)
|
||||
installElement(item.text, getConfig().categories.elements.files[item.text].url)
|
||||
installElement(item.text, item.item)
|
||||
end
|
||||
|
||||
for _, plugin in ipairs(pluginList:getSelectedItems()) do
|
||||
local item = plugin.item
|
||||
installPlugin(item.text, getConfig().categories.plugins.files[item.text].url)
|
||||
installPlugin(item.text, item.item)
|
||||
end
|
||||
|
||||
progressBar:setProgress(100)
|
||||
|
||||
@@ -62,13 +62,37 @@ function Dropdown:mouse_click(button, x, y)
|
||||
self.set("height", 1 + math.min(self.get("dropdownHeight"), #self.get("items")))
|
||||
end
|
||||
return true
|
||||
elseif self.get("isOpen") and relY > 1 then
|
||||
-- Nutze List's mouse_click für Item-Selektion
|
||||
List.mouse_click(self, button, x, y)
|
||||
-- Nach Selektion Dropdown schließen
|
||||
self.set("isOpen", false)
|
||||
self.set("height", 1)
|
||||
return true
|
||||
elseif self.get("isOpen") and relY > 1 and self.get("selectable") then
|
||||
local itemIndex = (relY - 1) + self.get("offset")
|
||||
local items = self.get("items")
|
||||
|
||||
if itemIndex <= #items then
|
||||
local item = items[itemIndex]
|
||||
if type(item) == "string" then
|
||||
item = {text = item}
|
||||
items[itemIndex] = item
|
||||
end
|
||||
|
||||
if not self.get("multiSelection") then
|
||||
for _, otherItem in ipairs(items) do
|
||||
if type(otherItem) == "table" then
|
||||
otherItem.selected = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
item.selected = not item.selected
|
||||
|
||||
if item.callback then
|
||||
item.callback(self)
|
||||
end
|
||||
|
||||
self:fireEvent("select", itemIndex, item)
|
||||
self.set("isOpen", false)
|
||||
self.set("height", 1)
|
||||
self:updateRender()
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -78,10 +102,8 @@ end
|
||||
function Dropdown:render()
|
||||
VisualElement.render(self)
|
||||
|
||||
-- Header rendern
|
||||
local text = self.get("selectedText")
|
||||
if #text == 0 then
|
||||
-- Suche nach selektiertem Item
|
||||
local selectedItems = self:getSelectedItems()
|
||||
if #selectedItems > 0 then
|
||||
local selectedItem = selectedItems[1].item
|
||||
@@ -89,20 +111,51 @@ function Dropdown:render()
|
||||
end
|
||||
end
|
||||
|
||||
-- Header mit Dropdown Symbol
|
||||
self:blit(1, 1, text .. string.rep(" ", self.get("width") - #text - 1) .. (self.get("isOpen") and "\31" or "\17"),
|
||||
string.rep(tHex[self.get("foreground")], self.get("width")),
|
||||
string.rep(tHex[self.get("background")], self.get("width")))
|
||||
|
||||
-- Liste rendern wenn offen
|
||||
if self.get("isOpen") then
|
||||
-- Offset um 1 verschieben wegen Header
|
||||
local oldOffset = self.get("offset")
|
||||
self.set("offset", oldOffset + 1)
|
||||
-- Liste ab Zeile 2 rendern
|
||||
List.render(self)
|
||||
-- Offset zurücksetzen
|
||||
self.set("offset", oldOffset)
|
||||
local items = self.get("items")
|
||||
local height = self.get("height") - 1
|
||||
local offset = self.get("offset")
|
||||
local width = self.get("width")
|
||||
|
||||
for i = 1, height do
|
||||
local itemIndex = i + offset
|
||||
local item = items[itemIndex]
|
||||
|
||||
if item then
|
||||
if type(item) == "string" then
|
||||
item = {text = item}
|
||||
items[itemIndex] = item
|
||||
end
|
||||
|
||||
if item.separator then
|
||||
local separatorChar = (item.text or "-"):sub(1,1)
|
||||
local separatorText = string.rep(separatorChar, width)
|
||||
local fg = item.foreground or self.get("foreground")
|
||||
local bg = item.background or self.get("background")
|
||||
|
||||
self:textBg(1, i + 1, string.rep(" ", width), bg)
|
||||
self:textFg(1, i + 1, separatorText, fg)
|
||||
else
|
||||
local text = item.text
|
||||
local isSelected = item.selected
|
||||
|
||||
local bg = isSelected and
|
||||
(item.selectedBackground or self.get("selectedBackground")) or
|
||||
(item.background or self.get("background"))
|
||||
|
||||
local fg = isSelected and
|
||||
(item.selectedForeground or self.get("selectedForeground")) or
|
||||
(item.foreground or self.get("foreground"))
|
||||
|
||||
self:textBg(1, i + 1, string.rep(" ", width), bg)
|
||||
self:textFg(1, i + 1, text, fg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -167,6 +167,23 @@ function List:onSelect(callback)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Scrolls the list to the bottom
|
||||
--- @shortDescription Scrolls the list to the bottom
|
||||
--- @return List self The List instance
|
||||
function List:scrollToBottom()
|
||||
local maxOffset = math.max(0, #self.get("items") - self.get("height"))
|
||||
self.set("offset", maxOffset)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Scrolls the list to the top
|
||||
--- @shortDescription Scrolls the list to the top
|
||||
--- @return List self The List instance
|
||||
function List:scrollToTop()
|
||||
self.set("offset", 0)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Renders the list
|
||||
--- @shortDescription Renders the list
|
||||
function List:render()
|
||||
|
||||
@@ -11,7 +11,7 @@ ProgressBar.defineProperty(ProgressBar, "progress", {default = 0, type = "number
|
||||
---@property showPercentage boolean false Whether to show the percentage text in the center
|
||||
ProgressBar.defineProperty(ProgressBar, "showPercentage", {default = false, type = "boolean"})
|
||||
---@property progressColor color lime The color used for the filled portion of the progress bar
|
||||
ProgressBar.defineProperty(ProgressBar, "progressColor", {default = colors.lime, type = "number"})
|
||||
ProgressBar.defineProperty(ProgressBar, "progressColor", {default = colors.black, type = "number"})
|
||||
|
||||
--- Creates a new ProgressBar instance
|
||||
--- @shortDescription Creates a new ProgressBar instance
|
||||
@@ -42,7 +42,9 @@ function ProgressBar:render()
|
||||
local progress = math.min(100, math.max(0, self.get("progress")))
|
||||
local fillWidth = math.floor((width * progress) / 100)
|
||||
|
||||
self:textBg(1, 1, string.rep(" ", fillWidth), self.get("progressColor"))
|
||||
for i = 1, self.get("height") do
|
||||
self:textBg(1, i, string.rep(" ", fillWidth), self.get("progressColor"))
|
||||
end
|
||||
|
||||
if self.get("showPercentage") then
|
||||
local text = tostring(progress).."%"
|
||||
|
||||
@@ -24,16 +24,20 @@ local function serialize(t, indent)
|
||||
end
|
||||
|
||||
local function parseFile(filePath)
|
||||
if filePath:match("LuaLS%.lua$") then return nil end
|
||||
|
||||
local file = io.open(filePath, "r")
|
||||
if not file then return nil end
|
||||
|
||||
local content = file:read("*all")
|
||||
local size = #content
|
||||
file:close()
|
||||
|
||||
local config = {
|
||||
description = "",
|
||||
default = true,
|
||||
requires = {}
|
||||
requires = {},
|
||||
size = size
|
||||
}
|
||||
|
||||
local description = content:match("%-%-%-@configDescription%s*(.-)%s*\n")
|
||||
@@ -79,11 +83,13 @@ local function scanDirectory(srcPath)
|
||||
if not pipe then return end
|
||||
|
||||
for path in pipe:lines() do
|
||||
local config = parseFile(path)
|
||||
if config then
|
||||
config.name = path:match("([^/]+)%.lua$")
|
||||
config.path = path:gsub("^" .. srcPath .. "/", "")
|
||||
files[path] = config
|
||||
if(path~="LuaLS.lua")then
|
||||
local config = parseFile(path)
|
||||
if config then
|
||||
config.name = path:match("([^/]+)%.lua$")
|
||||
config.path = path:gsub("^" .. srcPath .. "/", "")
|
||||
files[path] = config
|
||||
end
|
||||
end
|
||||
end
|
||||
pipe:close()
|
||||
@@ -109,7 +115,8 @@ local function generateConfig(srcPath)
|
||||
path = fileConfig.path,
|
||||
description = fileConfig.description,
|
||||
default = fileConfig.default,
|
||||
requires = fileConfig.requires
|
||||
requires = fileConfig.requires,
|
||||
size = fileConfig.size
|
||||
}
|
||||
end
|
||||
|
||||
@@ -139,7 +146,6 @@ local function generateConfig(srcPath)
|
||||
}
|
||||
end
|
||||
|
||||
-- Config generieren und speichern
|
||||
local config = generateConfig("src")
|
||||
local configFile = io.open("config.lua", "w")
|
||||
configFile:write("return " .. serialize(config))
|
||||
|
||||
Reference in New Issue
Block a user