add gs
This commit is contained in:
@@ -0,0 +1,460 @@
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
local TweenService = game:GetService("TweenService")
|
||||
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local Utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
local INPUT_TYPE_ROW_HEIGHT = 30
|
||||
local ACTION_ROW_HEIGHT = 20
|
||||
local ROW_PADDING = 5
|
||||
local COLUMN_PADDING = 5
|
||||
|
||||
local CORE_SECURITY_COLUMN_COLOR = Color3.new(0.1, 0, 0)
|
||||
local DEV_SECURITY_COLUMN_COLOR = Color3.new(0, 0, 0)
|
||||
|
||||
local EXPAND_ROTATE_IMAGE_TWEEN_OUT = TweenInfo.new(0.150, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
|
||||
local EXPAND_ROTATE_IMAGE_TWEEN_IN = TweenInfo.new(0.150, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
|
||||
|
||||
local ROW_PULSE = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, 0, true, 0)
|
||||
local CONTAINER_SCROLL = TweenInfo.new(0.25, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
|
||||
|
||||
local container = nil
|
||||
local boundInputTypeRows = {}
|
||||
local boundInputTypesByRows = {}
|
||||
local boundInputTypeActionRows = {}
|
||||
local boundActionInfoByRows = {}
|
||||
local inputTypesByActionRows = {}
|
||||
local inputTypesByHeaders = {}
|
||||
local headersByInputTypes = {}
|
||||
local inputTypesExpanded = {}
|
||||
|
||||
local layoutOrderDirty = true
|
||||
|
||||
local rowTypePrecedence = {
|
||||
BoundInputType = 3,
|
||||
TableHeader = 2,
|
||||
BoundAction = 1
|
||||
}
|
||||
|
||||
local function sortInputTypeRows(a, b)
|
||||
local inputTypeA = boundInputTypesByRows[a]
|
||||
local inputTypeB = boundInputTypesByRows[b]
|
||||
return tostring(inputTypeA) < tostring(inputTypeB)
|
||||
end
|
||||
|
||||
local function sortActionRows(a, b)
|
||||
local actionA = boundActionInfoByRows[a]
|
||||
local actionB = boundActionInfoByRows[b]
|
||||
if actionA and actionB then
|
||||
local rowInputTypeA = inputTypesByActionRows[a]
|
||||
local rowInputTypeB = inputTypesByActionRows[b]
|
||||
if rowInputTypeA ~= rowInputTypeB then
|
||||
return tostring(rowInputTypeA) < tostring(rowInputTypeB)
|
||||
end
|
||||
if actionA.isCore and not actionB.isCore then
|
||||
return true
|
||||
elseif not actionA.isCore and actionB.isCore then
|
||||
return false
|
||||
end
|
||||
local stackOrderA = actionA.stackOrder
|
||||
local stackOrderB = actionB.stackOrder
|
||||
if stackOrderA and stackOrderB then
|
||||
return stackOrderA > stackOrderB --descending sort
|
||||
else
|
||||
return true
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function createEmptyRow(name, height)
|
||||
local row = Utility:Create("Frame") {
|
||||
Name = name,
|
||||
BackgroundTransparency = 1,
|
||||
ZIndex = 6,
|
||||
Size = UDim2.new(1, 0, 0, height or 0)
|
||||
}
|
||||
local columnList = Utility:Create("UIListLayout") {
|
||||
FillDirection = Enum.FillDirection.Horizontal,
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
Padding = UDim.new(0, COLUMN_PADDING),
|
||||
Parent = row
|
||||
}
|
||||
return row
|
||||
end
|
||||
|
||||
local function createButtonRow(name, height)
|
||||
local row = Utility:Create("TextButton") {
|
||||
Name = name,
|
||||
BackgroundTransparency = 1,
|
||||
ZIndex = 6,
|
||||
Text = "",
|
||||
Size = UDim2.new(1, 0, 0, height or 0),
|
||||
}
|
||||
local columnList = Utility:Create("UIListLayout") {
|
||||
FillDirection = Enum.FillDirection.Horizontal,
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
Padding = UDim.new(0, COLUMN_PADDING),
|
||||
Parent = row
|
||||
}
|
||||
return row
|
||||
end
|
||||
|
||||
local function createEmptyColumn(row, columnName)
|
||||
local column = Utility:Create("Frame") {
|
||||
Name = columnName,
|
||||
BackgroundColor3 = Color3.new(0, 0, 0),
|
||||
BackgroundTransparency = 0.75,
|
||||
BorderSizePixel = 0,
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
ZIndex = 6,
|
||||
ClipsDescendants = true,
|
||||
Parent = row
|
||||
}
|
||||
|
||||
return column
|
||||
end
|
||||
|
||||
local function createImageColumn(row, columnName, image, aspectRatio, imageSize)
|
||||
local column = createEmptyColumn(row, columnName)
|
||||
|
||||
local aspectRatioConstraint = Utility:Create("UIAspectRatioConstraint") {
|
||||
AspectRatio = aspectRatio or 1,
|
||||
Parent = column
|
||||
}
|
||||
|
||||
local imageLabel = Utility:Create("ImageLabel") {
|
||||
Name = "ColumnImage",
|
||||
BackgroundTransparency = 1,
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0),
|
||||
Size = UDim2.new(imageSize or 1, 0, imageSize or 1, 0),
|
||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||
ZIndex = 6,
|
||||
Image = image,
|
||||
Parent = column
|
||||
}
|
||||
|
||||
return column
|
||||
end
|
||||
|
||||
local function createTextColumn(row, columnName, text)
|
||||
local column = createEmptyColumn(row, columnName)
|
||||
|
||||
local textLabel = Utility:Create("TextLabel") {
|
||||
Name = "ColumnText",
|
||||
BackgroundTransparency = 1,
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0),
|
||||
Size = UDim2.new(1, -10, 1, -10),
|
||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||
ZIndex = 6,
|
||||
Text = text,
|
||||
TextSize = 18,
|
||||
TextColor3 = Color3.new(1, 1, 1),
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Font = Enum.Font.SourceSans,
|
||||
Parent = column
|
||||
}
|
||||
|
||||
return column
|
||||
end
|
||||
|
||||
local function createActionColumns(row, backgroundColor)
|
||||
local x = 0
|
||||
|
||||
local insetWidth = ACTION_ROW_HEIGHT + (COLUMN_PADDING * 2)
|
||||
local insetCol = createEmptyColumn(row, "Inset")
|
||||
insetCol.LayoutOrder = 0
|
||||
insetCol.BackgroundTransparency = 1
|
||||
insetCol.Size = UDim2.new(0, insetWidth, 1, 0)
|
||||
x = x + insetWidth + COLUMN_PADDING
|
||||
|
||||
local priorityWidth = 80
|
||||
local priorityCol = createTextColumn(row, "Priority", "Priority")
|
||||
priorityCol.LayoutOrder = 1
|
||||
priorityCol.BackgroundColor3 = backgroundColor
|
||||
priorityCol.Size = UDim2.new(0, priorityWidth, 1, 0)
|
||||
x = x + priorityWidth + COLUMN_PADDING
|
||||
|
||||
local securityWidth = 80
|
||||
local securityCol = createTextColumn(row, "Security", "Security")
|
||||
securityCol.LayoutOrder = 2
|
||||
securityCol.BackgroundColor3 = backgroundColor
|
||||
securityCol.Size = UDim2.new(0, securityWidth, 1, 0)
|
||||
x = x + securityWidth + COLUMN_PADDING
|
||||
|
||||
local nameCol = createTextColumn(row, "ActionName", "Action Name")
|
||||
nameCol.LayoutOrder = 3
|
||||
nameCol.BackgroundColor3 = backgroundColor
|
||||
nameCol.Size = UDim2.new(1/4, 0, 1, 0)
|
||||
|
||||
local inputTypesCol = createTextColumn(row, "InputTypes", "Input Types")
|
||||
inputTypesCol.LayoutOrder = 4
|
||||
inputTypesCol.BackgroundColor3 = backgroundColor
|
||||
inputTypesCol.Size = UDim2.new(3/4, -x - COLUMN_PADDING, 1, 0)
|
||||
|
||||
return insetCol, priorityCol, securityCol, nameCol, inputTypesCol
|
||||
end
|
||||
|
||||
local function updateContainerCanvas()
|
||||
debug.profilebegin("updateContainerCanvas")
|
||||
|
||||
if layoutOrderDirty then
|
||||
layoutOrderDirty = false
|
||||
local idx = 1
|
||||
|
||||
local inputTypeRowList = {}
|
||||
|
||||
for inputType, inputTypeRow in pairs(boundInputTypeRows) do
|
||||
table.insert(inputTypeRowList, inputTypeRow)
|
||||
end
|
||||
|
||||
table.sort(inputTypeRowList, sortInputTypeRows)
|
||||
|
||||
for i, inputTypeRow in pairs(inputTypeRowList) do
|
||||
local inputType = boundInputTypesByRows[inputTypeRow]
|
||||
inputTypeRow.LayoutOrder = idx; idx = idx + 1
|
||||
local headerRow = headersByInputTypes[inputType]
|
||||
if headerRow then
|
||||
headerRow.LayoutOrder = idx; idx = idx + 1
|
||||
end
|
||||
|
||||
local actionRows = boundInputTypeActionRows[inputType]
|
||||
if actionRows then
|
||||
local actionRowList = {}
|
||||
for actionName, actionRow in pairs(actionRows) do
|
||||
table.insert(actionRowList, actionRow)
|
||||
end
|
||||
|
||||
table.sort(actionRowList, sortActionRows)
|
||||
|
||||
for i, actionRow in pairs(actionRowList) do
|
||||
actionRow.LayoutOrder = idx; idx = idx + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
debug.profileend()
|
||||
end
|
||||
|
||||
local function scrollContainerToRow(row)
|
||||
local scrollOffset = row.AbsolutePosition.Y - container.AbsolutePosition.Y
|
||||
local newCanvasPosition = container.CanvasPosition + Vector2.new(0, scrollOffset)
|
||||
TweenService:Create(container, CONTAINER_SCROLL, { CanvasPosition = newCanvasPosition }):Play()
|
||||
end
|
||||
|
||||
local ActionBindingsTab = {}
|
||||
|
||||
function ActionBindingsTab.initializeGui(tabFrame)
|
||||
local scrollingFrame = Utility:Create("ScrollingFrame") {
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0),
|
||||
Size = UDim2.new(1, -10, 1, -10),
|
||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||
BorderSizePixel = 0,
|
||||
ScrollBarThickness = 4,
|
||||
BackgroundTransparency = 1,
|
||||
ZIndex = 6,
|
||||
Parent = tabFrame
|
||||
}
|
||||
container = scrollingFrame
|
||||
|
||||
local listLayout = Utility:Create("UIListLayout") {
|
||||
Padding = UDim.new(0, ROW_PADDING),
|
||||
Parent = scrollingFrame
|
||||
}
|
||||
listLayout.SortOrder = Enum.SortOrder.LayoutOrder
|
||||
listLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function() container.CanvasSize = UDim2.new(0, 0, 0, listLayout.AbsoluteContentSize.Y) end)
|
||||
|
||||
ActionBindingsTab.updateGuis()
|
||||
|
||||
ContextActionService.BoundActionAdded:connect(function(actionName, createTouchButton, actionInfo, isCore)
|
||||
actionInfo.isCore = isCore
|
||||
ActionBindingsTab.updateActionRows(actionName, actionInfo)
|
||||
|
||||
layoutOrderDirty = true
|
||||
updateContainerCanvas()
|
||||
end)
|
||||
ContextActionService.BoundActionRemoved:connect(function(actionName, actionInfo, isCore)
|
||||
actionInfo.isCore = isCore
|
||||
ActionBindingsTab.removeActionRows(actionName, actionInfo)
|
||||
|
||||
layoutOrderDirty = true
|
||||
updateContainerCanvas()
|
||||
end)
|
||||
end
|
||||
|
||||
function ActionBindingsTab.updateBoundInputTypeRow(inputType)
|
||||
local existingRow = boundInputTypeRows[inputType]
|
||||
if not existingRow then
|
||||
local row = createButtonRow("BoundInputType", INPUT_TYPE_ROW_HEIGHT)
|
||||
|
||||
local expandImageCol = createImageColumn(row, "ExpandImage", "rbxasset://textures/ui/ExpandArrowSheet.png", 1, 0.35)
|
||||
expandImageCol.ColumnImage.ImageRectSize = Vector2.new(21, 21)
|
||||
expandImageCol.ColumnImage.ImageRectOffset = Vector2.new(0, 0)
|
||||
|
||||
local inputTypeCol = createTextColumn(row, "InputType", tostring(inputType))
|
||||
inputTypeCol.Size = UDim2.new(1, -INPUT_TYPE_ROW_HEIGHT - COLUMN_PADDING, 1, 0)
|
||||
inputTypeCol.ColumnText.Font = Enum.Font.SourceSansBold
|
||||
|
||||
local tableHeaderRow = createEmptyRow("TableHeader", ACTION_ROW_HEIGHT)
|
||||
tableHeaderRow.Visible = false
|
||||
local _, priorityCol, securityCol, nameCol, inputTypesCol = createActionColumns(tableHeaderRow, DEV_SECURITY_COLUMN_COLOR)
|
||||
priorityCol.ColumnText.Font = Enum.Font.SourceSansBold
|
||||
securityCol.ColumnText.Font = Enum.Font.SourceSansBold
|
||||
nameCol.ColumnText.Font = Enum.Font.SourceSansBold
|
||||
inputTypesCol.ColumnText.Font = Enum.Font.SourceSansBold
|
||||
|
||||
boundInputTypeRows[inputType] = row
|
||||
boundInputTypesByRows[row] = inputType
|
||||
inputTypesByHeaders[tableHeaderRow] = inputType
|
||||
headersByInputTypes[inputType] = tableHeaderRow
|
||||
|
||||
tableHeaderRow.Parent = container
|
||||
row.Parent = container
|
||||
|
||||
TweenService:Create(inputTypeCol, ROW_PULSE, { BackgroundColor3 = Color3.new(0.5, 0.5, 0.5) }):Play()
|
||||
|
||||
inputTypesExpanded[inputType] = false
|
||||
row.MouseButton1Click:connect(function()
|
||||
inputTypesExpanded[inputType] = not inputTypesExpanded[inputType]
|
||||
|
||||
local inputTypeActionRows = boundInputTypeActionRows[inputType]
|
||||
if not inputTypesExpanded[inputType] then
|
||||
expandImageCol.ColumnImage.ImageRectOffset = Vector2.new(0, 0)
|
||||
tableHeaderRow.Visible = false
|
||||
if inputTypeActionRows then
|
||||
for _, actionRow in pairs(inputTypeActionRows) do
|
||||
actionRow.Visible = false
|
||||
end
|
||||
end
|
||||
else
|
||||
expandImageCol.ColumnImage.ImageRectOffset = Vector2.new(21, 0)
|
||||
tableHeaderRow.Visible = true
|
||||
if inputTypeActionRows then
|
||||
for _, actionRow in pairs(inputTypeActionRows) do
|
||||
actionRow.Visible = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
updateContainerCanvas()
|
||||
if inputTypesExpanded[inputType] then
|
||||
TweenService:Create(inputTypeCol, ROW_PULSE, { BackgroundColor3 = Color3.new(0.5, 0.5, 0.5) }):Play()
|
||||
scrollContainerToRow(row)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function ActionBindingsTab.updateActionRowForInputType(actionName, actionInfo, inputType)
|
||||
local inputTypeActionRows = boundInputTypeActionRows[inputType]
|
||||
if not inputTypeActionRows then
|
||||
inputTypeActionRows = {}
|
||||
boundInputTypeActionRows[inputType] = inputTypeActionRows
|
||||
end
|
||||
|
||||
local existingRow = inputTypeActionRows[actionName]
|
||||
if not existingRow then
|
||||
local row = createEmptyRow("BoundAction", ACTION_ROW_HEIGHT)
|
||||
row.Visible = inputTypesExpanded[inputType]
|
||||
|
||||
local inputTypeNames = {}
|
||||
for i, inputType in pairs(actionInfo.inputTypes) do
|
||||
inputTypeNames[i] = tostring(inputType)
|
||||
end
|
||||
|
||||
local insetCol, priorityCol, securityCol, nameCol, inputTypesCol = createActionColumns(row, actionInfo.isCore and CORE_SECURITY_COLUMN_COLOR or DEV_SECURITY_COLUMN_COLOR)
|
||||
priorityCol.ColumnText.Text = actionInfo.priorityLevel or "Default"
|
||||
securityCol.ColumnText.Text = actionInfo.isCore and "Core" or "Developer"
|
||||
nameCol.ColumnText.Text = actionName
|
||||
inputTypesCol.ColumnText.Text = table.concat(inputTypeNames, ", ")
|
||||
|
||||
if actionInfo.isCore then
|
||||
priorityCol.ColumnText.Font = Enum.Font.SourceSansItalic
|
||||
securityCol.ColumnText.Font = Enum.Font.SourceSansItalic
|
||||
nameCol.ColumnText.Font = Enum.Font.SourceSansItalic
|
||||
inputTypesCol.ColumnText.Font = Enum.Font.SourceSansItalic
|
||||
end
|
||||
|
||||
inputTypeActionRows[actionName] = row
|
||||
inputTypesByActionRows[row] = inputType
|
||||
boundActionInfoByRows[row] = actionInfo
|
||||
row.Parent = container
|
||||
|
||||
if row.Visible then
|
||||
TweenService:Create(nameCol, ROW_PULSE, { BackgroundColor3 = Color3.new(0.5, 0.5, 0.5) }):Play()
|
||||
else
|
||||
local inputTypeRow = boundInputTypeRows[inputType]
|
||||
if inputTypeRow then
|
||||
TweenService:Create(inputTypeRow.InputType, ROW_PULSE, { BackgroundColor3 = Color3.new(0.5, 0.5, 0.5) }):Play()
|
||||
end
|
||||
end
|
||||
|
||||
existingRow = row
|
||||
end
|
||||
end
|
||||
|
||||
function ActionBindingsTab.updateActionRows(actionName, actionInfo)
|
||||
for _, inputType in pairs(actionInfo.inputTypes) do
|
||||
ActionBindingsTab.updateBoundInputTypeRow(inputType)
|
||||
ActionBindingsTab.updateActionRowForInputType(actionName, actionInfo, inputType)
|
||||
end
|
||||
end
|
||||
|
||||
function ActionBindingsTab.removeActionRows(actionName, actionInfo)
|
||||
for _, inputType in pairs(actionInfo.inputTypes) do
|
||||
local inputTypeActionRows = boundInputTypeActionRows[inputType]
|
||||
if inputTypeActionRows then
|
||||
local row = inputTypeActionRows[actionName]
|
||||
row:Destroy()
|
||||
inputTypeActionRows[actionName] = nil
|
||||
|
||||
--The following code looks weird. It's because Lua has no way to determine
|
||||
--if a table is explicitly empty in both the array and dictionary parts.
|
||||
--This does it though.
|
||||
local isEmpty = true
|
||||
for _, __ in pairs(inputTypeActionRows) do
|
||||
isEmpty = false
|
||||
break
|
||||
end
|
||||
|
||||
if isEmpty then
|
||||
local inputTypeRow = boundInputTypeRows[inputType]
|
||||
if inputTypeRow then
|
||||
inputTypeRow:Destroy()
|
||||
boundInputTypeRows[inputType] = nil
|
||||
end
|
||||
local tableHeaderRow = headersByInputTypes[inputType]
|
||||
if tableHeaderRow then
|
||||
headersByInputTypes[tableHeaderRow] = nil
|
||||
tableHeaderRow:Destroy()
|
||||
headersByInputTypes[inputType] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
updateContainerCanvas()
|
||||
container.UIListLayout:ApplyLayout()
|
||||
end
|
||||
|
||||
function ActionBindingsTab.updateGuis()
|
||||
local boundCoreActions = ContextActionService:GetAllBoundCoreActionInfo()
|
||||
for actionName, actionInfo in pairs(boundCoreActions) do
|
||||
actionInfo.isCore = true
|
||||
ActionBindingsTab.updateActionRows(actionName, actionInfo)
|
||||
end
|
||||
local boundActions = ContextActionService:GetAllBoundActionInfo()
|
||||
for actionName, actionInfo in pairs(boundActions) do
|
||||
actionInfo.isCore = false
|
||||
ActionBindingsTab.updateActionRows(actionName, actionInfo)
|
||||
end
|
||||
|
||||
layoutOrderDirty = true
|
||||
updateContainerCanvas()
|
||||
end
|
||||
|
||||
return ActionBindingsTab
|
||||
Reference in New Issue
Block a user