-- AltSystem Build Skills UI -- Creates the Build Skills tab content with editable skill rows, add/delete functionality, and save to TRP. AltSystem = AltSystem or {} local PADDING = 12 local ROW_HEIGHT = 36 local ROW_SPACING = 8 local NAME_WIDTH = 340 local LEVEL_WIDTH = 140 local VALUE_WIDTH = 80 local DELETE_WIDTH = 30 -- Working copy of skills being edited (not saved until user clicks Save) local editableSkills = {} -- Pool of created row frames for reuse local skillRowFrames = {} -- References set during creation local scrollFrame, scrollChild, addRowButton -- ─── Create a single skill row frame ──────────────────────────────────────── local function CreateSkillRowFrame(index) local row = CreateFrame("Frame", "AltSystemSkillRow" .. index, scrollChild) row:SetHeight(ROW_HEIGHT) -- Dark background local bg = row:CreateTexture(nil, "BACKGROUND") bg:SetAllPoints() bg:SetColorTexture(0.1, 0.1, 0.1, 0.8) row.bg = bg -- Name EditBox local nameBox = CreateFrame("EditBox", "AltSystemSkillName" .. index, row, "InputBoxTemplate") nameBox:SetPoint("LEFT", row, "LEFT", 8, 0) nameBox:SetSize(NAME_WIDTH, 24) nameBox:SetAutoFocus(false) nameBox:SetFontObject("GameFontHighlight") row.nameBox = nameBox -- Level Dropdown local levelDropdown = CreateFrame("DropdownButton", "AltSystemSkillLevel" .. index, row, "WowStyle1DropdownTemplate") levelDropdown:SetPoint("LEFT", nameBox, "RIGHT", 12, 0) levelDropdown:SetWidth(LEVEL_WIDTH) row.levelDropdown = levelDropdown -- Value Dropdown local valueDropdown = CreateFrame("DropdownButton", "AltSystemSkillValue" .. index, row, "WowStyle1DropdownTemplate") valueDropdown:SetPoint("LEFT", levelDropdown, "RIGHT", 8, 0) valueDropdown:SetWidth(VALUE_WIDTH) row.valueDropdown = valueDropdown -- Delete Button local deleteBtn = CreateFrame("Button", "AltSystemSkillDelete" .. index, row) deleteBtn:SetSize(DELETE_WIDTH, DELETE_WIDTH) deleteBtn:SetPoint("LEFT", valueDropdown, "RIGHT", 8, 0) local deleteBg = deleteBtn:CreateTexture(nil, "BACKGROUND") deleteBg:SetAllPoints() deleteBg:SetColorTexture(0.5, 0.1, 0.1, 0.9) deleteBtn.bg = deleteBg local deleteText = deleteBtn:CreateFontString(nil, "OVERLAY", "GameFontNormal") deleteText:SetPoint("CENTER") deleteText:SetText("X") deleteText:SetTextColor(1, 0.3, 0.3) deleteBtn:SetScript("OnEnter", function(self) self.bg:SetColorTexture(0.7, 0.15, 0.15, 1) end) deleteBtn:SetScript("OnLeave", function(self) self.bg:SetColorTexture(0.5, 0.1, 0.1, 0.9) end) row.deleteBtn = deleteBtn return row end -- ─── Refresh all skill rows ───────────────────────────────────────────────── local function RefreshSkillRows() -- Hide all existing row frames for _, row in ipairs(skillRowFrames) do row:Hide() end local yPos = 0 for i, skillData in ipairs(editableSkills) do local row = skillRowFrames[i] if not row then row = CreateSkillRowFrame(i) skillRowFrames[i] = row end -- Clear previous anchor points before repositioning row:ClearAllPoints() row:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -yPos) row:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", 0, -yPos) -- Populate name row.nameBox:SetText(skillData.name or "") row.nameBox:SetScript("OnTextChanged", function(self) local idx = nil for j, s in ipairs(editableSkills) do if skillRowFrames[j] == row then idx = j break end end if idx then editableSkills[idx].name = self:GetText() end end) -- Setup level dropdown local currentRowIndex = i row.levelDropdown:SetupMenu(function(dropdown, rootDescription) for _, levelName in ipairs(AltSystem.Data.SkillLevelOrder) do rootDescription:CreateRadio( levelName, function() return editableSkills[currentRowIndex] and editableSkills[currentRowIndex].level == levelName end, function() if editableSkills[currentRowIndex] then editableSkills[currentRowIndex].level = levelName editableSkills[currentRowIndex].value = AltSystem.Data:GetDefaultValueForLevel(levelName) RefreshSkillRows() end end ) end end) -- Setup value dropdown based on current level local range = AltSystem.Data.SkillValueRanges[skillData.level] if range then row.valueDropdown:SetupMenu(function(dropdown, rootDescription) for v = range.min, range.max do rootDescription:CreateRadio( tostring(v), function() return editableSkills[currentRowIndex] and editableSkills[currentRowIndex].value == v end, function() if editableSkills[currentRowIndex] then editableSkills[currentRowIndex].value = v end end ) end end) end -- Bind delete button for current index row.deleteBtn:SetScript("OnClick", function() table.remove(editableSkills, currentRowIndex) RefreshSkillRows() end) row:Show() yPos = yPos + ROW_HEIGHT + ROW_SPACING end -- Reposition Add A Row button if addRowButton then addRowButton:ClearAllPoints() addRowButton:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -PADDING, -(yPos + 4)) end -- Update scroll child height local totalHeight = yPos + ROW_HEIGHT + 20 -- extra space for Add A Row button if scrollChild then scrollChild:SetHeight(math.max(totalHeight, 1)) end end -- ─── Create Build Skills Content ──────────────────────────────────────────── function AltSystem:CreateBuildSkillsContent(parentFrame) local contentWidth = parentFrame:GetWidth() or 692 local contentHeight = parentFrame:GetHeight() or 444 local yPos = -PADDING -- Info text paragraph 1 local info1 = parentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") info1:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", PADDING, yPos) info1:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -PADDING, yPos) info1:SetJustifyH("LEFT") info1:SetText("All skills below are directly extracted from your TRP's characteristics sheet. You can view and edit them there at any time.") info1:SetTextColor(0.9, 0.75, 0.2) info1:SetWordWrap(true) yPos = yPos - (info1:GetStringHeight() or 16) - 10 -- Info text paragraph 2 local info2 = parentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") info2:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", PADDING, yPos) info2:SetPoint("TOPRIGHT", parentFrame, "TOPRIGHT", -PADDING, yPos) info2:SetJustifyH("LEFT") info2:SetText("This menu serves as an easy alternative for if you want to use this system fast without diving deep into understanding it and/or styling your TRP sheet at this point in time. All your changes made will not be saved to TRP up until you hit the specific button to do so.") info2:SetTextColor(0.9, 0.75, 0.2) info2:SetWordWrap(true) yPos = yPos - (info2:GetStringHeight() or 32) - 16 -- "Skill list" section header local sectionHeader = parentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge") sectionHeader:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", PADDING, yPos) sectionHeader:SetText("Skill list") sectionHeader:SetTextColor(1, 1, 1) yPos = yPos - 24 -- Column headers local nameHeader = parentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") nameHeader:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", PADDING + 8, yPos) nameHeader:SetText("Name") nameHeader:SetTextColor(0.9, 0.75, 0.2) local levelHeader = parentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") levelHeader:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", PADDING + 8 + NAME_WIDTH + 12, yPos) levelHeader:SetText("Level") levelHeader:SetTextColor(0.9, 0.75, 0.2) local valueHeader = parentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") valueHeader:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", PADDING + 8 + NAME_WIDTH + 12 + LEVEL_WIDTH + 8, yPos) valueHeader:SetText("Value") valueHeader:SetTextColor(0.9, 0.75, 0.2) yPos = yPos - 20 -- Save button (pinned to bottom, outside scroll frame) local saveButton = CreateFrame("Button", "AltSystemSaveSkillsButton", parentFrame, "UIPanelButtonTemplate") saveButton:SetSize(180, 30) saveButton:SetPoint("BOTTOM", parentFrame, "BOTTOM", 0, PADDING) saveButton:SetText("Save Skills to TRP") -- Style the save button with a dark red tint local saveBg = saveButton:CreateTexture(nil, "BACKGROUND") saveBg:SetAllPoints() saveBg:SetColorTexture(0.4, 0.08, 0.08, 0.9) saveButton:SetScript("OnClick", function() local success = AltSystem.Data:SaveSkills(editableSkills) if success and AltSystem.RefreshSkillDropdown then AltSystem:RefreshSkillDropdown() end end) -- Scrollable skill list area (between column headers and save button) scrollFrame = CreateFrame("ScrollFrame", "AltSystemBuildSkillsScrollFrame", parentFrame, "UIPanelScrollFrameTemplate") scrollFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", PADDING, yPos) scrollFrame:SetPoint("BOTTOMRIGHT", parentFrame, "BOTTOMRIGHT", -PADDING - 22, saveButton:GetHeight() + PADDING + 8) scrollChild = CreateFrame("Frame", "AltSystemBuildSkillsScrollChild", scrollFrame) scrollChild:SetWidth(scrollFrame:GetWidth() or (contentWidth - PADDING * 2 - 22)) scrollChild:SetHeight(1) scrollFrame:SetScrollChild(scrollChild) -- Update scroll child width when frame resizes scrollFrame:SetScript("OnSizeChanged", function(self) scrollChild:SetWidth(self:GetWidth()) end) -- "Add A Row" button (inside scroll child, below last row) addRowButton = CreateFrame("Button", "AltSystemAddRowButton", scrollChild, "UIPanelButtonTemplate") addRowButton:SetSize(130, 26) addRowButton:SetText("+ Add A Row") addRowButton:SetPoint("TOPRIGHT", scrollChild, "TOPRIGHT", -PADDING, 0) -- Style add row button local addBg = addRowButton:CreateTexture(nil, "BACKGROUND") addBg:SetAllPoints() addBg:SetColorTexture(0.4, 0.08, 0.08, 0.9) addRowButton:SetScript("OnClick", function() table.insert(editableSkills, { name = "Skillname", level = "Novice", value = 1, icon = "inv_misc_questionmark", isNew = true, }) RefreshSkillRows() -- Auto-scroll to bottom to show the new row C_Timer.After(0.05, function() if scrollFrame then scrollFrame:SetVerticalScroll(scrollFrame:GetVerticalScrollRange()) end end) end) AltSystem.BuildSkillsScrollFrame = scrollFrame AltSystem.BuildSkillsScrollChild = scrollChild end -- ─── Refresh Build Skills list (called on tab switch) ─────────────────────── function AltSystem:RefreshBuildSkillsList() -- Reload skills from TRP3 into working copy, discarding any unsaved edits editableSkills = AltSystem.Data:GetEditableSkills() RefreshSkillRows() end