Dropdown Fix

Progressbar Fix
List 2 new Methods: scrollToBottom scrollToTop
Readme Update
Generate-config size addition
This commit is contained in:
Robert Jelic
2025-02-22 11:26:20 +01:00
parent e6bc79ff5e
commit 3d7c7aa02a
6 changed files with 186 additions and 52 deletions

View File

@@ -1,30 +1,28 @@
# Basalt - A UI Framework for CC:Tweaked
# Basalt 2 - A UI Framework for CC:Tweaked
![GitHub Repo stars](https://img.shields.io/github/stars/Pyroxenium/Basalt2?style=for-the-badge)
[![Discord](https://img.shields.io/discord/976905222251233320?label=Discord&style=for-the-badge)](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

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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).."%"

View File

@@ -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))