Reviewed-on: #1 Co-authored-by: Gonçalo Correia <goncalojoaocorreia@gmail.com> Co-committed-by: Gonçalo Correia <goncalojoaocorreia@gmail.com>
698 lines
25 KiB
Lua
Executable file
698 lines
25 KiB
Lua
Executable file
-- AltSystem UI
|
|
-- Creates the main dialog window with tabbed layout.
|
|
-- The "Use Skills" tab contains controls on the left and a Log panel on the right.
|
|
-- Uses the modern DropdownButton API (WoW 10.2.5+ / 12.0+).
|
|
|
|
AltSystem = AltSystem or {}
|
|
|
|
local WINDOW_WIDTH = 720
|
|
local WINDOW_HEIGHT = 520
|
|
local CONTROLS_WIDTH = 360
|
|
local LOG_WIDTH = 360
|
|
local PADDING = 12
|
|
local PADDING_HEADER = 6
|
|
local ROW_HEIGHT = 26
|
|
local LABEL_HEIGHT = 14 -- approximate height of GameFontNormal text
|
|
local LABEL_GAP = 4 -- gap between a sub-label and its input
|
|
local ITEM_GAP = 10 -- gap between inputs within the same section
|
|
local SECTION_GAP = 22 -- gap between major sections
|
|
|
|
-- Helper: Build the skill option list from current AltSystem.Data.Skills
|
|
local function BuildSkillOptions()
|
|
local options = {}
|
|
for _, skill in ipairs(AltSystem.Data.Skills) do
|
|
local sign = skill.modifier >= 0 and "+" or ""
|
|
local text
|
|
if skill.level == "Base" or skill.level == "Inept" then
|
|
text = skill.name .. " (" .. sign .. skill.modifier .. ")"
|
|
else
|
|
text = skill.name .. " (" .. skill.level .. " " .. sign .. skill.modifier .. ")"
|
|
end
|
|
table.insert(options, { text = text })
|
|
end
|
|
return options
|
|
end
|
|
|
|
-- Helper: Create a flat dark dropdown with label on top (reuses shared CreateFlatDropdown)
|
|
local function CreateDropdown(parent, name, labelText, options, defaultIndex, onSelect, labelFont)
|
|
local hasLabel = labelText and labelText ~= ""
|
|
local containerHeight = hasLabel and (LABEL_HEIGHT + LABEL_GAP + 28) or ROW_HEIGHT
|
|
|
|
local container = CreateFrame("Frame", nil, parent)
|
|
container:SetHeight(containerHeight)
|
|
|
|
local label
|
|
if hasLabel then
|
|
label = container:CreateFontString(nil, "OVERLAY", labelFont or "GameFontNormal")
|
|
label:SetPoint("TOPLEFT", container, "TOPLEFT", 0, 0)
|
|
label:SetText(labelText)
|
|
label:SetJustifyH("LEFT")
|
|
label:SetTextColor(0.9, 0.75, 0.2)
|
|
end
|
|
|
|
local selectedIndex = defaultIndex or 1
|
|
|
|
local dropdown = AltSystem.CreateFlatDropdown(name, container, 190)
|
|
if hasLabel then
|
|
dropdown:SetPoint("TOPLEFT", container, "TOPLEFT", 0, -(LABEL_HEIGHT + LABEL_GAP))
|
|
dropdown:SetPoint("TOPRIGHT", container, "TOPRIGHT", 0, -(LABEL_HEIGHT + LABEL_GAP))
|
|
else
|
|
dropdown:SetPoint("LEFT", container, "LEFT", 0, 0)
|
|
dropdown:SetPoint("RIGHT", container, "RIGHT", 0, 0)
|
|
end
|
|
|
|
-- Set initial label text
|
|
if options[selectedIndex] then
|
|
dropdown.label:SetText(options[selectedIndex].text)
|
|
end
|
|
|
|
dropdown:SetupMenu(function(owner, rootDescription)
|
|
for i, option in ipairs(options) do
|
|
rootDescription:CreateRadio(
|
|
option.text,
|
|
function()
|
|
return i == selectedIndex
|
|
end,
|
|
function()
|
|
selectedIndex = i
|
|
dropdown.label:SetText(option.text)
|
|
if onSelect then
|
|
onSelect(i, option)
|
|
end
|
|
end
|
|
)
|
|
end
|
|
end)
|
|
|
|
return container, dropdown, function()
|
|
return selectedIndex
|
|
end, function(idx)
|
|
selectedIndex = idx
|
|
if options[idx] then
|
|
dropdown.label:SetText(options[idx].text)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Helper: Create a custom flat radio button (gold circle when selected, grey when not)
|
|
local function CreateRadioButton(parent, name, text, x, y, isChecked, onClick)
|
|
local size = 20
|
|
local btn = CreateFrame("CheckButton", name, parent)
|
|
btn:SetSize(size, size)
|
|
btn:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
|
|
|
|
-- Outer grey circle (always visible, acts as border)
|
|
local border = btn:CreateTexture(nil, "BACKGROUND")
|
|
border:SetAllPoints()
|
|
border:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
local borderMask = btn:CreateMaskTexture()
|
|
borderMask:SetAllPoints()
|
|
borderMask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
|
|
border:AddMaskTexture(borderMask)
|
|
|
|
-- Inner yellow circle (shown when selected, slightly smaller to reveal grey border)
|
|
local inner = btn:CreateTexture(nil, "BORDER")
|
|
local inset = 3
|
|
inner:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
|
|
inner:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
|
|
inner:SetColorTexture(0.9, 0.75, 0.2, 1)
|
|
local innerMask = btn:CreateMaskTexture()
|
|
innerMask:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
|
|
innerMask:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
|
|
innerMask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
|
|
inner:AddMaskTexture(innerMask)
|
|
inner:Hide()
|
|
|
|
btn.checkTex = nil -- unused, kept for compatibility
|
|
|
|
local function UpdateVisual()
|
|
if btn:GetChecked() then
|
|
inner:Show()
|
|
else
|
|
inner:Hide()
|
|
end
|
|
end
|
|
|
|
btn:SetChecked(isChecked)
|
|
UpdateVisual()
|
|
|
|
local label = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
label:SetPoint("LEFT", btn, "RIGHT", 6, 0)
|
|
label:SetText(text)
|
|
|
|
btn:SetScript("OnClick", function(self)
|
|
onClick(self)
|
|
UpdateVisual()
|
|
end)
|
|
|
|
btn.UpdateVisual = UpdateVisual
|
|
return btn
|
|
end
|
|
|
|
-- Helper: Create a section header (golden text)
|
|
local function CreateSectionHeader(parent, text, x, y)
|
|
local header = parent:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
header:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
|
|
header:SetText(text)
|
|
header:SetTextColor(0.9, 0.75, 0.2)
|
|
return header
|
|
end
|
|
|
|
-- Helper: Create a sub-label (smaller golden text)
|
|
local function CreateSubLabel(parent, text, x, y)
|
|
local label = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
label:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
|
|
label:SetText(text)
|
|
label:SetTextColor(0.9, 0.75, 0.2)
|
|
return label
|
|
end
|
|
|
|
function AltSystem:CreateMainFrame()
|
|
if AltSystem.MainFrame then
|
|
return
|
|
end
|
|
|
|
-- Main frame
|
|
local f = CreateFrame("Frame", "AltSystemMainFrame", UIParent, "BasicFrameTemplateWithInset")
|
|
f:SetSize(WINDOW_WIDTH, WINDOW_HEIGHT)
|
|
f:SetPoint("CENTER")
|
|
f:SetMovable(true)
|
|
f:EnableMouse(true)
|
|
f:RegisterForDrag("LeftButton")
|
|
f:SetScript("OnDragStart", f.StartMoving)
|
|
f:SetScript("OnDragStop", f.StopMovingOrSizing)
|
|
f:SetClampedToScreen(true)
|
|
|
|
f.TitleBg:SetHeight(30)
|
|
f.title = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
f.title:SetPoint("TOPLEFT", f.TitleBg, "TOPLEFT", 5, -3)
|
|
f.title:SetText("AltSystem")
|
|
|
|
---------------------
|
|
-- TAB BUTTONS (span full window width)
|
|
---------------------
|
|
local contentTop = -24
|
|
local tabHeight = 36
|
|
local contentWidth = WINDOW_WIDTH - 8 -- 4px inset on each side
|
|
local tabWidth = contentWidth / 2
|
|
|
|
local tabUseSkills = CreateFrame("Button", "AltSystemTabUseSkills", f)
|
|
tabUseSkills:SetSize(tabWidth, tabHeight)
|
|
tabUseSkills:SetPoint("TOPLEFT", f, "TOPLEFT", 4, contentTop)
|
|
tabUseSkills:SetNormalFontObject("GameFontNormalLarge")
|
|
tabUseSkills:SetHighlightFontObject("GameFontNormalLarge")
|
|
tabUseSkills:SetText("Use Skills")
|
|
|
|
local tabUseSkillsBg = tabUseSkills:CreateTexture(nil, "BACKGROUND")
|
|
tabUseSkillsBg:SetAllPoints()
|
|
tabUseSkillsBg:SetColorTexture(0, 0, 0, 0)
|
|
|
|
local tabUseSkillsText = tabUseSkills:GetFontString()
|
|
tabUseSkillsText:SetTextColor(0.9, 0.75, 0.2, 1)
|
|
|
|
local tabBuildSkills = CreateFrame("Button", "AltSystemTabBuildSkills", f)
|
|
tabBuildSkills:SetSize(tabWidth, tabHeight)
|
|
tabBuildSkills:SetPoint("TOPLEFT", tabUseSkills, "TOPRIGHT", 0, 0)
|
|
tabBuildSkills:SetNormalFontObject("GameFontNormalLarge")
|
|
tabBuildSkills:SetHighlightFontObject("GameFontNormalLarge")
|
|
tabBuildSkills:SetText("Build Skills")
|
|
|
|
local tabBuildSkillsBg = tabBuildSkills:CreateTexture(nil, "BACKGROUND")
|
|
tabBuildSkillsBg:SetAllPoints()
|
|
tabBuildSkillsBg:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
|
|
local tabBuildSkillsText = tabBuildSkills:GetFontString()
|
|
tabBuildSkillsText:SetTextColor(1, 1, 1, 1)
|
|
|
|
---------------------
|
|
-- TAB CONTENT FRAMES
|
|
---------------------
|
|
local tabContentTop = contentTop - tabHeight
|
|
local tabContentHeight = WINDOW_HEIGHT - 28 - tabHeight
|
|
|
|
local useSkillsContent = CreateFrame("Frame", "AltSystemUseSkillsContent", f)
|
|
useSkillsContent:SetPoint("TOPLEFT", f, "TOPLEFT", 4, tabContentTop)
|
|
useSkillsContent:SetSize(contentWidth, tabContentHeight)
|
|
|
|
local buildSkillsContent = CreateFrame("Frame", "AltSystemBuildSkillsContent", f)
|
|
buildSkillsContent:SetPoint("TOPLEFT", f, "TOPLEFT", 4, tabContentTop)
|
|
buildSkillsContent:SetSize(contentWidth, tabContentHeight)
|
|
buildSkillsContent:Hide()
|
|
|
|
-- Build Skills tab content (created in BuildSkillsUI.lua)
|
|
AltSystem:CreateBuildSkillsContent(buildSkillsContent)
|
|
|
|
-- Tab switching logic
|
|
local function SelectTab(tabIndex)
|
|
if tabIndex == 1 then
|
|
useSkillsContent:Show()
|
|
buildSkillsContent:Hide()
|
|
tabUseSkillsBg:SetColorTexture(0, 0, 0, 0)
|
|
tabBuildSkillsBg:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
tabUseSkillsText:SetTextColor(0.9, 0.75, 0.2, 1)
|
|
tabBuildSkillsText:SetTextColor(1, 1, 1, 1)
|
|
else
|
|
useSkillsContent:Hide()
|
|
buildSkillsContent:Show()
|
|
tabUseSkillsBg:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
tabBuildSkillsBg:SetColorTexture(0, 0, 0, 0)
|
|
tabUseSkillsText:SetTextColor(1, 1, 1, 1)
|
|
tabBuildSkillsText:SetTextColor(0.9, 0.75, 0.2, 1)
|
|
AltSystem:RefreshBuildSkillsList()
|
|
end
|
|
end
|
|
|
|
tabUseSkills:SetScript("OnClick", function()
|
|
SelectTab(1)
|
|
end)
|
|
tabBuildSkills:SetScript("OnClick", function()
|
|
SelectTab(2)
|
|
end)
|
|
|
|
---------------------
|
|
-- USE SKILLS TAB CONTENT (left: controls, right: log)
|
|
---------------------
|
|
local controlsPanel = CreateFrame("Frame", nil, useSkillsContent)
|
|
controlsPanel:SetPoint("TOPLEFT", useSkillsContent, "TOPLEFT", 0, 0)
|
|
controlsPanel:SetSize(CONTROLS_WIDTH, tabContentHeight)
|
|
|
|
local content = controlsPanel
|
|
local yPos = -PADDING
|
|
|
|
-- Section: Define Your Base Roll
|
|
CreateSectionHeader(content, "Base Roll", PADDING_HEADER, yPos)
|
|
yPos = yPos - 26
|
|
|
|
-- Roll Type label
|
|
CreateSubLabel(content, "Roll Type", PADDING, yPos)
|
|
yPos = yPos - (LABEL_HEIGHT + LABEL_GAP)
|
|
|
|
-- Roll Type radio buttons
|
|
local attackRadio, defenseRadio
|
|
|
|
local function UpdateRollTypeSelection(rollType)
|
|
AltSystem.State.rollType = rollType
|
|
attackRadio:SetChecked(rollType == "attack")
|
|
defenseRadio:SetChecked(rollType == "defense")
|
|
attackRadio.UpdateVisual()
|
|
defenseRadio.UpdateVisual()
|
|
-- Update roll button text
|
|
if AltSystem.RollButton then
|
|
local label = rollType == "attack" and "Roll Attack" or "Roll Defense"
|
|
AltSystem.RollButton:SetText(label)
|
|
end
|
|
end
|
|
|
|
attackRadio = CreateRadioButton(content, "AltSystemAttackRadio", "Attack Roll", PADDING, yPos,
|
|
AltSystem.State.rollType == "attack",
|
|
function()
|
|
UpdateRollTypeSelection("attack")
|
|
end)
|
|
|
|
defenseRadio = CreateRadioButton(content, "AltSystemDefenseRadio", "Defense Roll", CONTROLS_WIDTH / 2, yPos,
|
|
AltSystem.State.rollType == "defense",
|
|
function()
|
|
UpdateRollTypeSelection("defense")
|
|
end)
|
|
|
|
yPos = yPos - ROW_HEIGHT - ITEM_GAP
|
|
|
|
-- Skill dropdown
|
|
local skillOptions = BuildSkillOptions()
|
|
local UpdateSkillWarning -- forward declaration
|
|
|
|
local skillContainer, skillDropdown, getSkillIndex, setSkillIndex = CreateDropdown(
|
|
content, "AltSystemSkillDropdown", "Skill", skillOptions,
|
|
AltSystem.State.selectedSkillIndex,
|
|
function(index)
|
|
AltSystem.State.selectedSkillIndex = index
|
|
AltSystem.State.selectedSkillName = AltSystem.Data.Skills[index] and AltSystem.Data.Skills[index].name or nil
|
|
UpdateSkillWarning(index)
|
|
end,
|
|
"GameFontNormal"
|
|
)
|
|
skillContainer:SetPoint("TOPLEFT", content, "TOPLEFT", PADDING, yPos)
|
|
skillContainer:SetWidth(CONTROLS_WIDTH - PADDING * 2)
|
|
|
|
-- Warning icon for skill mismatch
|
|
local skillWarning = CreateFrame("Frame", nil, skillContainer)
|
|
skillWarning:SetSize(20, 20)
|
|
skillWarning:SetPoint("LEFT", skillDropdown, "RIGHT", 4, 0)
|
|
|
|
local skillWarningIcon = skillWarning:CreateTexture(nil, "ARTWORK")
|
|
skillWarningIcon:SetAllPoints()
|
|
skillWarningIcon:SetAtlas("services-icon-warning")
|
|
|
|
skillWarning:SetScript("OnEnter", function(self)
|
|
if self.tooltipText then
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText(self.tooltipText, 1, 0.82, 0)
|
|
GameTooltip:Show()
|
|
end
|
|
end)
|
|
skillWarning:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
skillWarning:Hide()
|
|
|
|
UpdateSkillWarning = function(index)
|
|
local skill = AltSystem.Data.Skills[index]
|
|
if skill and skill.warning then
|
|
skillWarning.tooltipText = skill.warning
|
|
skillWarning:Show()
|
|
else
|
|
skillWarning:Hide()
|
|
end
|
|
end
|
|
|
|
-- Store references for refreshing
|
|
AltSystem.SkillDropdown = skillDropdown
|
|
AltSystem.GetSkillIndex = getSkillIndex
|
|
AltSystem.SetSkillIndex = setSkillIndex
|
|
AltSystem.UpdateSkillWarning = UpdateSkillWarning
|
|
|
|
yPos = yPos - (LABEL_HEIGHT + LABEL_GAP + 28) - ITEM_GAP
|
|
|
|
-- Armor label
|
|
CreateSubLabel(content, "Extra Armor", PADDING, yPos)
|
|
yPos = yPos - (LABEL_HEIGHT + LABEL_GAP)
|
|
|
|
-- Armor radio buttons
|
|
local armorRadios = {}
|
|
|
|
local function UpdateArmorSelection(index)
|
|
AltSystem.State.selectedDefenseIndex = index
|
|
for i, radio in ipairs(armorRadios) do
|
|
radio:SetChecked(i == index)
|
|
radio.UpdateVisual()
|
|
end
|
|
end
|
|
|
|
local armorX = PADDING
|
|
for i, def in ipairs(AltSystem.Data.Defenses) do
|
|
local text = def.name
|
|
if def.modifier > 0 then
|
|
text = text .. " (+" .. def.modifier .. ")"
|
|
end
|
|
local radio = CreateRadioButton(content, "AltSystemArmorRadio" .. i, text, armorX, yPos,
|
|
AltSystem.State.selectedDefenseIndex == i,
|
|
function()
|
|
UpdateArmorSelection(i)
|
|
end)
|
|
table.insert(armorRadios, radio)
|
|
armorX = armorX + 110
|
|
end
|
|
|
|
yPos = yPos - ROW_HEIGHT - SECTION_GAP
|
|
|
|
-- Section: Modifiers (optional)
|
|
CreateSectionHeader(content, "Modifiers (optional)", PADDING_HEADER, yPos)
|
|
yPos = yPos - 26
|
|
--CreateSubLabel(content, "Label", PADDING, yPos)
|
|
--yPos = yPos - 22
|
|
|
|
-- Shield checkbox (flat square toggle)
|
|
local shieldCheck = CreateFrame("CheckButton", "AltSystemShieldCheck", content)
|
|
shieldCheck:SetSize(20, 20)
|
|
shieldCheck:SetPoint("TOPLEFT", content, "TOPLEFT", PADDING, yPos)
|
|
shieldCheck:SetChecked(AltSystem.State.shieldEnabled)
|
|
|
|
local shieldBg = shieldCheck:CreateTexture(nil, "BACKGROUND")
|
|
shieldBg:SetAllPoints()
|
|
shieldBg:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
|
|
local shieldCheckMark = shieldCheck:CreateTexture(nil, "ARTWORK")
|
|
shieldCheckMark:SetSize(14, 14)
|
|
shieldCheckMark:SetPoint("CENTER")
|
|
shieldCheckMark:SetTexture("Interface\\RAIDFRAME\\ReadyCheck-Ready")
|
|
shieldCheckMark:SetVertexColor(0.9, 0.75, 0.2, 1)
|
|
|
|
local function UpdateShieldVisual()
|
|
if shieldCheck:GetChecked() then
|
|
shieldCheckMark:Show()
|
|
shieldBg:SetColorTexture(0.25, 0.25, 0.25, 1)
|
|
else
|
|
shieldCheckMark:Hide()
|
|
shieldBg:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
end
|
|
end
|
|
UpdateShieldVisual()
|
|
|
|
local shieldLabel = shieldCheck:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
shieldLabel:SetPoint("LEFT", shieldCheck, "RIGHT", 6, 0)
|
|
shieldLabel:SetText("Shield (+ 1)")
|
|
|
|
shieldCheck:SetScript("OnClick", function(self)
|
|
AltSystem.State.shieldEnabled = self:GetChecked()
|
|
UpdateShieldVisual()
|
|
end)
|
|
|
|
-- Pet checkbox (flat square toggle)
|
|
local petCheck = CreateFrame("CheckButton", "AltSystemPetSummonCheck", content)
|
|
petCheck:SetSize(20, 20)
|
|
petCheck:SetPoint("LEFT", shieldCheck, "RIGHT", 80, 0)
|
|
petCheck:SetChecked(AltSystem.State.petSummonEnabled)
|
|
|
|
local petBg = petCheck:CreateTexture(nil, "BACKGROUND")
|
|
petBg:SetAllPoints()
|
|
petBg:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
|
|
local petCheckMark = petCheck:CreateTexture(nil, "ARTWORK")
|
|
petCheckMark:SetSize(14, 14)
|
|
petCheckMark:SetPoint("CENTER")
|
|
petCheckMark:SetTexture("Interface\\RAIDFRAME\\ReadyCheck-Ready")
|
|
petCheckMark:SetVertexColor(0.9, 0.75, 0.2, 1)
|
|
|
|
local function UpdatePetVisual()
|
|
if petCheck:GetChecked() then
|
|
petCheckMark:Show()
|
|
petBg:SetColorTexture(0.25, 0.25, 0.25, 1)
|
|
else
|
|
petCheckMark:Hide()
|
|
petBg:SetColorTexture(0.3, 0.3, 0.3, 1)
|
|
end
|
|
end
|
|
UpdatePetVisual()
|
|
|
|
local petLabel = petCheck:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
petLabel:SetPoint("LEFT", petCheck, "RIGHT", 6, 0)
|
|
petLabel:SetText("Pet (+d5)")
|
|
|
|
petCheck:SetScript("OnClick", function(self)
|
|
AltSystem.State.petSummonEnabled = self:GetChecked()
|
|
UpdatePetVisual()
|
|
end)
|
|
|
|
yPos = yPos - ROW_HEIGHT - ITEM_GAP
|
|
|
|
-- Item label
|
|
CreateSubLabel(content, "Item", PADDING, yPos)
|
|
yPos = yPos - (LABEL_HEIGHT + LABEL_GAP)
|
|
|
|
-- Item radio buttons
|
|
local itemRadios = {}
|
|
|
|
local function UpdateItemSelection(index)
|
|
AltSystem.State.selectedItemIndex = index
|
|
for i, radio in ipairs(itemRadios) do
|
|
radio:SetChecked(i == index)
|
|
radio.UpdateVisual()
|
|
end
|
|
end
|
|
|
|
local itemX = PADDING
|
|
for i, item in ipairs(AltSystem.Data.Items) do
|
|
local text = item.name
|
|
if item.modifier > 0 then
|
|
text = text .. " (+" .. item.modifier .. ")"
|
|
end
|
|
local radio = CreateRadioButton(content, "AltSystemItemRadio" .. i, text, itemX, yPos,
|
|
AltSystem.State.selectedItemIndex == i,
|
|
function()
|
|
UpdateItemSelection(i)
|
|
end)
|
|
table.insert(itemRadios, radio)
|
|
itemX = itemX + 110
|
|
end
|
|
|
|
yPos = yPos - ROW_HEIGHT - SECTION_GAP
|
|
|
|
-- Section: Roll Dice
|
|
CreateSectionHeader(content, "Roll Mode", PADDING_HEADER, yPos)
|
|
yPos = yPos - 26
|
|
|
|
-- Announce Roll dropdown (Self Roll + channels)
|
|
local announceOptions = { { text = "Self Roll" } }
|
|
for _, ch in ipairs(AltSystem.AnnounceChannels) do
|
|
table.insert(announceOptions, { text = ch.name })
|
|
end
|
|
|
|
local announceContainer, announceDropdown = CreateDropdown(
|
|
content, "AltSystemAnnounceDropdown", "", announceOptions,
|
|
AltSystem.State.announceOptionIndex,
|
|
function(index)
|
|
AltSystem.State.announceOptionIndex = index
|
|
if index > 1 then
|
|
AltSystem.State.announceEnabled = true
|
|
AltSystem.State.announceChannelIndex = index - 1
|
|
else
|
|
AltSystem.State.announceEnabled = false
|
|
AltSystem.State.announceChannelIndex = 1
|
|
end
|
|
end,
|
|
"GameFontNormal")
|
|
announceContainer:SetPoint("TOPLEFT", content, "TOPLEFT", PADDING, yPos)
|
|
announceContainer:SetWidth(CONTROLS_WIDTH - PADDING * 2)
|
|
|
|
yPos = yPos - ROW_HEIGHT - ITEM_GAP
|
|
|
|
-- Roll button
|
|
local rollLabel = AltSystem.State.rollType == "attack" and "Roll Attack" or "Roll Defense"
|
|
local rollBtn = AltSystem.CreateFlatButton("AltSystemRollBtn", content, CONTROLS_WIDTH - PADDING * 2, 32, rollLabel)
|
|
rollBtn:SetPoint("TOPLEFT", content, "TOPLEFT", PADDING, yPos)
|
|
|
|
rollBtn:SetScript("OnClick", function()
|
|
AltSystem:PerformRoll(AltSystem.State.rollType)
|
|
end)
|
|
|
|
AltSystem.RollButton = rollBtn
|
|
|
|
---------------------
|
|
-- LOG PANEL (right side of Use Skills tab)
|
|
---------------------
|
|
local logPanel = CreateFrame("Frame", nil, useSkillsContent)
|
|
logPanel:SetPoint("TOPLEFT", useSkillsContent, "TOPLEFT", CONTROLS_WIDTH, 0)
|
|
logPanel:SetSize(LOG_WIDTH, tabContentHeight)
|
|
|
|
-- Log header
|
|
local logHeader = CreateSectionHeader(logPanel, "Log", 0, -PADDING)
|
|
|
|
-- Log scroll area background
|
|
local logBg = CreateFrame("Frame", nil, logPanel, "InsetFrameTemplate")
|
|
logBg:SetPoint("TOPLEFT", logPanel, "TOPLEFT", 4, -38)
|
|
logBg:SetPoint("BOTTOMRIGHT", logPanel, "BOTTOMRIGHT", -PADDING, 4)
|
|
|
|
-- Scroll frame for log entries
|
|
local scrollFrame = CreateFrame("ScrollFrame", "AltSystemLogScrollFrame", logBg, "UIPanelScrollFrameTemplate")
|
|
scrollFrame:SetPoint("TOPLEFT", logBg, "TOPLEFT", 6, -6)
|
|
scrollFrame:SetPoint("BOTTOMRIGHT", logBg, "BOTTOMRIGHT", -28, 6)
|
|
|
|
local scrollChild = CreateFrame("Frame", "AltSystemLogScrollChild", scrollFrame)
|
|
scrollChild:SetWidth(scrollFrame:GetWidth() or (LOG_WIDTH - 50))
|
|
scrollChild:SetHeight(1) -- Will be updated dynamically
|
|
scrollFrame:SetScrollChild(scrollChild)
|
|
|
|
AltSystem.LogScrollFrame = scrollFrame
|
|
AltSystem.LogScrollChild = scrollChild
|
|
|
|
-- Refresh skills from TRP3 profile each time the window is shown
|
|
f:SetScript("OnShow", function()
|
|
AltSystem:RefreshSkillDropdown()
|
|
AltSystem:RefreshLogPanel()
|
|
end)
|
|
|
|
f:Hide()
|
|
AltSystem.MainFrame = f
|
|
end
|
|
|
|
-- Refresh the log panel UI from AltSystem.State.rollLog
|
|
function AltSystem:RefreshLogPanel()
|
|
local scrollChild = AltSystem.LogScrollChild
|
|
if not scrollChild then
|
|
return
|
|
end
|
|
|
|
-- Remove existing log entry fontstrings
|
|
if scrollChild.entries then
|
|
for _, entry in ipairs(scrollChild.entries) do
|
|
entry:Hide()
|
|
entry:SetText("")
|
|
end
|
|
end
|
|
scrollChild.entries = scrollChild.entries or {}
|
|
|
|
local rollLog = AltSystem.State.rollLog
|
|
local entryHeight = 16
|
|
local spacing = 4
|
|
local yPos = 0
|
|
local childWidth = AltSystem.LogScrollFrame:GetWidth() or 250
|
|
|
|
-- Entries are newest-first
|
|
for i = #rollLog, 1, -1 do
|
|
local idx = #rollLog - i + 1
|
|
local logEntry = rollLog[i]
|
|
local fontStr = scrollChild.entries[idx]
|
|
|
|
if not fontStr then
|
|
fontStr = scrollChild:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
scrollChild.entries[idx] = fontStr
|
|
end
|
|
|
|
fontStr:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 2, -yPos)
|
|
fontStr:SetWidth(childWidth - 4)
|
|
fontStr:SetJustifyH("LEFT")
|
|
fontStr:SetText(logEntry.text)
|
|
fontStr:Show()
|
|
|
|
yPos = yPos + entryHeight + spacing
|
|
end
|
|
|
|
scrollChild:SetHeight(math.max(yPos, 1))
|
|
end
|
|
|
|
-- Refresh the skill dropdown with current TRP3 profile data
|
|
function AltSystem:RefreshSkillDropdown()
|
|
AltSystem.Data:RefreshSkills()
|
|
|
|
-- Try to restore the previously selected skill by name; fall back to 1 (Base roll)
|
|
local newIndex = 1
|
|
local savedName = AltSystem.State.selectedSkillName
|
|
if savedName then
|
|
for i, skill in ipairs(AltSystem.Data.Skills) do
|
|
if skill.name == savedName then
|
|
newIndex = i
|
|
break
|
|
end
|
|
end
|
|
end
|
|
AltSystem.State.selectedSkillIndex = newIndex
|
|
AltSystem.State.selectedSkillName = AltSystem.Data.Skills[newIndex] and AltSystem.Data.Skills[newIndex].name or nil
|
|
if AltSystem.SetSkillIndex then
|
|
AltSystem.SetSkillIndex(newIndex)
|
|
end
|
|
if AltSystem.UpdateSkillWarning then
|
|
AltSystem.UpdateSkillWarning(newIndex)
|
|
end
|
|
|
|
-- Rebuild the dropdown menu with the new skill list
|
|
if AltSystem.SkillDropdown then
|
|
local skillOptions = BuildSkillOptions()
|
|
-- Update the displayed label text
|
|
if skillOptions[newIndex] then
|
|
AltSystem.SkillDropdown.label:SetText(skillOptions[newIndex].text)
|
|
end
|
|
AltSystem.SkillDropdown:SetupMenu(function(owner, rootDescription)
|
|
for i, option in ipairs(skillOptions) do
|
|
rootDescription:CreateRadio(
|
|
option.text,
|
|
function()
|
|
return i == AltSystem.State.selectedSkillIndex
|
|
end,
|
|
function()
|
|
AltSystem.State.selectedSkillIndex = i
|
|
AltSystem.State.selectedSkillName = AltSystem.Data.Skills[i] and AltSystem.Data.Skills[i].name or nil
|
|
AltSystem.SkillDropdown.label:SetText(option.text)
|
|
if AltSystem.SetSkillIndex then
|
|
AltSystem.SetSkillIndex(i)
|
|
end
|
|
if AltSystem.UpdateSkillWarning then
|
|
AltSystem.UpdateSkillWarning(i)
|
|
end
|
|
end
|
|
)
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- Frame is created by AltSystem:Init() in Core.lua, after saved variables are loaded
|