diff --git a/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua b/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua index 281ba853..e701bea8 100644 --- a/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua +++ b/EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua @@ -284,12 +284,43 @@ initFrame:SetScript("OnEvent", function(self) end } ); y = y - h + -- GROUP BUTTONS + -- + -- One switch per optional action. Ready Check has none: it is the + -- reason the panel exists. Turning a button off closes the gap it + -- leaves -- the survivors re-flow across the rows. + _, h = W:SectionHeader(parent, "GROUP BUTTONS", y); y = y - h + + local function ButtonToggle(key, text, tooltip) + return { type = "toggle", text = text, tooltip = tooltip, + disabled = Disabled, + getValue = function() return Cfg(key) ~= false end, + setValue = function(v) + Set(key, v) + Refresh() + end } + end + + _, h = W:DualRow(parent, y, + ButtonToggle("showRoleCheck", "Show Role Check", + "Shows the Role Check button. Turn it off and the remaining buttons close the gap."), + ButtonToggle("showConvert", "Show Convert to Raid", + "Shows the Convert to Raid button, which reads Convert to Party while you are in a raid.") + ); y = y - h + _, h = W:DualRow(parent, y, + ButtonToggle("showDisband", "Show Disband", + "Shows the Disband button. It always asks before disbanding, but hiding it puts it out of misclick range for good."), + { type = "spacer" } + ); y = y - h + -- PULL TIMER _, h = W:SectionHeader(parent, "PULL TIMER", y); y = y - h local PULL_LABELS = { "First Timer", "Second Timer", "Third Timer" } + local PULL_TIP = "Countdown length of this pull button, in seconds. Set it to 0 to hide the button; with all three at 0 the whole pull row disappears, Stop included." local function PullSlider(i) - return { type="slider", text=PULL_LABELS[i], min=1, max=60, step=1, + return { type="slider", text=PULL_LABELS[i], min=0, max=60, step=1, + tooltip=PULL_TIP, disabled=Disabled, getValue=function() return PullGet(i) end, setValue=function(v) PullSet(i, v) end } diff --git a/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua b/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua index 20d16e60..c9cebc08 100644 --- a/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua +++ b/EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua @@ -6,6 +6,12 @@ -- placeable mid-combat) -- shown either as one combined window (default) or -- as two independently positioned windows. -- +-- Which Group & Pull buttons exist is a SETTING, not a build fact: Role +-- Check, Convert and Disband each have a switch, and a pull slot set to 0 +-- seconds drops out. Buttons are still created once, at build; the layout +-- pass (LayoutGroupContent) re-flows the survivors across the rows and is the +-- only writer of the content height the shells are sized from. +-- -- SHOW MODE (p.mode) replaces the old shared-visibility system outright: -- -- "never" -- the default. NOTHING exists: no frames, no events, no @@ -230,7 +236,9 @@ local sections = {} -- key -> shell frame local shellTitle = {} -- key -> title fontstring local groupHolder, markersHolder -- plain content holders (see header) local iconBtn -- collapsed-state square -local GROUP_CONTENT_H, MARKERS_CONTENT_H -- computed at build +-- Markers are fixed at build; the Group & Pull height follows the settings and +-- is re-computed by LayoutGroupContent on every Apply. +local GROUP_CONTENT_H, MARKERS_CONTENT_H local Apply -- forward: the event handler closes over it -- ONE representation of each secure decision, run from both paths. @@ -378,8 +386,12 @@ end local groupButtons = {} -- plain buttons, enable-gated on assist local markerButtons = {} -- secure buttons, dimmed on assist -local pullButtons = {} -- fixed set of 3; durations are re-labelled live -local convertButton +local pullButtons = {} -- fixed set of 3; only the ones above 0s show +-- Individually hideable content. Every one of these is created at build and +-- kept for the lifetime of the session; the layout pass decides which of them +-- reach the screen. Ready Check is the one action button with no switch -- a +-- raid panel without it has no reason to exist. +local readyButton, roleButton, convertButton, disbandButton, stopButton -- Both marker rows draw Blizzard's own raid target sheet -- the texture the -- rest of the suite already uses for markers, in nameplates and raid frames. @@ -419,7 +431,17 @@ local DB_DEFAULTS = { -- a security constraint -- the pull buttons are plain, only the marker -- buttons are secure. Growing the count later means growing the panel, -- nothing more. + -- + -- 0 means "no button": the slot drops out of the row and the survivors + -- share the width. All three at 0 takes the row away entirely, Stop + -- included (see LayoutGroupContent). pullTimes = { PULL_DEFAULTS[1], PULL_DEFAULTS[2], PULL_DEFAULTS[3] }, + -- Per-button switches for the three optional actions. Ready Check has + -- none on purpose. Same flow rule as the pull slots: a hidden button + -- leaves no hole, the rest close up. + showRoleCheck = true, + showConvert = true, + showDisband = true, -- Per-section: pos[key] = { point, relPoint, x, y } pos = {}, }, @@ -603,15 +625,23 @@ local function AssistSuppressed() return IsInRaid() and not HasAssist() end --- Durations are the only pull-timer setting that can change at runtime: the --- button count is fixed at build, so re-labelling is all it takes. -local function RefreshPullTimes() +-- An optional button's switch, defaulting to shown for an unset profile. +local function ButtonShown(key) + local p = P() + return not p or p[key] ~= false +end + +-- The pull durations worth a button, in slot order. 0 (and anything below it) +-- means the user turned that slot off. +local function VisiblePullTimes() local times = (P() and P().pullTimes) or {} - for i, b in ipairs(pullButtons) do - local secs = times[i] or PULL_DEFAULTS[i] - b.secs = secs - b._lbl:SetText(tostring(secs)) + local out = {} + for i = 1, PULL_SLOTS do + local secs = times[i] + if secs == nil then secs = PULL_DEFAULTS[i] end + if secs and secs > 0 then out[#out + 1] = secs end end + return out end -- GROUP_ROSTER_UPDATE is one of the chattiest events in a raid -- it bursts on @@ -813,51 +843,108 @@ local function MakeShell(key) return f end +-- Where the Group & Pull content actually lands. Re-run on every Apply, and +-- the ONLY writer of GROUP_CONTENT_H -- which button is on screen is a +-- setting, so positions, widths and the holder height all follow the profile +-- rather than the build. +-- +-- Everything it touches is a plain frame, and Apply is out-of-combat only, so +-- this is an ordinary re-point with no lockdown story. It must run BEFORE +-- ApplyLayout, which sizes the shells from GROUP_CONTENT_H. +local function LayoutGroupContent() + if not groupHolder then return end + local f = groupHolder + + -- Row plan first, geometry second: collect what is actually shown, two + -- action buttons per row in the fixed order below, so a hidden button + -- closes the gap instead of leaving a hole. A row that ends up with a + -- single button takes the full width. + local rows, pair = {}, {} + local function Add(b) + pair[#pair + 1] = b + if #pair == 2 then rows[#rows + 1] = pair; pair = {} end + end + Add(readyButton) + if ButtonShown("showRoleCheck") then Add(roleButton) end + if ButtonShown("showConvert") then Add(convertButton) end + if ButtonShown("showDisband") then Add(disbandButton) end + if #pair > 0 then rows[#rows + 1] = pair end + + -- Pull row: the slots left above 0, sharing the row with Stop. The + -- duration lives on the button (the click closure reads it back), so the + -- surviving durations simply move onto the leading buttons. + -- + -- All three at 0 drops the row entirely, Stop included: a Stop button + -- alone is a pull-timer row with no pull timer. + local times = VisiblePullTimes() + if #times > 0 then + local pull = {} + for i, secs in ipairs(times) do + local b = pullButtons[i] + b.secs = secs + b._lbl:SetText(tostring(secs)) + pull[i] = b + end + pull[#pull + 1] = stopButton + rows[#rows + 1] = pull + end + + -- Hide first, show what the plan placed: anything the switches dropped + -- stops at this line. + for _, b in ipairs(groupButtons) do b:Hide() end + + local y = 0 + for _, row in ipairs(rows) do + local n = #row + local w = (PANEL_W - PAD * 2 - ROW_GAP * (n - 1)) / n + for i, b in ipairs(row) do + b:SetWidth(w) + b:ClearAllPoints() + b:SetPoint("TOPLEFT", f, "TOPLEFT", PAD + (w + ROW_GAP) * (i - 1), y) + b:Show() + end + y = y - ROW_H - ROW_GAP + end + y = y + ROW_GAP -- the last row's trailing gap is not content + + GROUP_CONTENT_H = -y + f:SetHeight(GROUP_CONTENT_H) +end + -- Group & Pull content, in its own plain holder so one-window mode can treat --- it uniformly with the markers holder. +-- it uniformly with the markers holder. Creation only -- the buttons are born +-- unplaced at full-row width, and LayoutGroupContent puts them where the +-- settings say (MakeGroupButton runs labels through L itself). local function BuildGroupContent() groupHolder = CreateFrame("Frame", nil, sections.Group) groupHolder:SetWidth(PANEL_W) fontOwners[#fontOwners + 1] = groupHolder local f = groupHolder - local y = 0 + local full = PANEL_W - PAD * 2 - -- MakeGroupButton runs labels through L itself. - local half = (PANEL_W - PAD * 2 - ROW_GAP) / 2 - local ready = MakeGroupButton(f, "Ready Check", half, function() DoReadyCheck() end) - ready:SetPoint("TOPLEFT", f, "TOPLEFT", PAD, y) + readyButton = MakeGroupButton(f, "Ready Check", full, function() DoReadyCheck() end) + roleButton = MakeGroupButton(f, "Role Check", full, function() InitiateRolePoll() end) - local role = MakeGroupButton(f, "Role Check", half, function() InitiateRolePoll() end) - role:SetPoint("TOPLEFT", f, "TOPLEFT", PAD + half + ROW_GAP, y) - y = y - ROW_H - ROW_GAP - - convertButton = MakeGroupButton(f, "Convert to Raid", half, function() + convertButton = MakeGroupButton(f, "Convert to Raid", full, function() if IsInRaid() then C_PartyInfo.ConvertToParty() else C_PartyInfo.ConvertToRaid() end end, true) - convertButton:SetPoint("TOPLEFT", f, "TOPLEFT", PAD, y) - local disband = MakeGroupButton(f, "Disband", half, function() + disbandButton = MakeGroupButton(f, "Disband", full, function() ConfirmDisband() end, true) - disband:SetPoint("TOPLEFT", f, "TOPLEFT", PAD + half + ROW_GAP, y) - y = y - ROW_H - ROW_GAP - -- Pull timer row: three durations + Stop, sharing the holder's width. - local w = (PANEL_W - PAD * 2 - PULL_SLOTS * ROW_GAP) / (PULL_SLOTS + 1) for i = 1, PULL_SLOTS do -- The pull duration lives on the button and changes at runtime, so -- the click reads it through the closure. local b - b = MakeGroupButton(f, "", w, function() StartPull(b.secs) end) - b:SetPoint("TOPLEFT", f, "TOPLEFT", PAD + (w + ROW_GAP) * (i - 1), y) + b = MakeGroupButton(f, "", full, function() StartPull(b.secs) end) pullButtons[i] = b end - local cancel = MakeGroupButton(f, "Stop", w, StopPull) - cancel:SetPoint("TOPLEFT", f, "TOPLEFT", PAD + (w + ROW_GAP) * PULL_SLOTS, y) - y = y - ROW_H + stopButton = MakeGroupButton(f, "Stop", full, StopPull) - GROUP_CONTENT_H = -y - f:SetHeight(GROUP_CONTENT_H) + -- A height right away: BuildAll has callers (the slash command, unlock + -- mode) that reach the shells without going through Apply. + LayoutGroupContent() end -- Row order matches how they are used: unit markers first, ground markers @@ -1408,6 +1495,9 @@ function Apply() EnsureEvents() RegisterUnlock() BuildAll() + -- Before ApplyLayout: it sizes the shells from GROUP_CONTENT_H, which the + -- hidden buttons and the 0-second pull slots move. + LayoutGroupContent() ApplyLayout() -- One Window Scale for everything the feature draws. local scale = WindowScale() @@ -1418,7 +1508,6 @@ function Apply() ApplyVisibility() ApplyToggleKeybind() ApplyFonts() - RefreshPullTimes() RefreshPermissions(true) end _G._EUI_RaidTools_Apply = Apply diff --git a/Locales/deDE.lua b/Locales/deDE.lua index ea34b9d5..1decafea 100644 --- a/Locales/deDE.lua +++ b/Locales/deDE.lua @@ -5422,4 +5422,14 @@ L["Stop"] = "Stopp" -- QoL: Raid Tools -- hidden in a raid without leader or assist L["A raid control panel with ready check, pull timer and raid markers. In a raid it only shows while you are the leader or an assistant, since none of its buttons work without that; in a party it always shows."] = "Ein Kontrollfeld für Schlachtzüge mit Bereitschaftsprüfung, Pull-Timer und Schlachtzugsmarkierungen. Im Schlachtzug wird es nur angezeigt, solange Ihr Anführer oder Assistent seid, da ohne diese Rechte keine seiner Schaltflächen funktioniert; in einer Gruppe wird es immer angezeigt." -L["Raid Tools is hidden in a raid without leader or assist -- none of its buttons work there."] = "Die Raid-Tools werden im Schlachtzug ohne Anführer- oder Assistentenrechte ausgeblendet -- dort funktioniert keine ihrer Schaltflächen." \ No newline at end of file +L["Raid Tools is hidden in a raid without leader or assist -- none of its buttons work there."] = "Die Raid-Tools werden im Schlachtzug ohne Anführer- oder Assistentenrechte ausgeblendet -- dort funktioniert keine ihrer Schaltflächen." + +-- QoL: Raid Tools -- per-button switches and the 0-second pull slots +L["GROUP BUTTONS"] = "GRUPPENSCHALTFLÄCHEN" +L["Show Role Check"] = "Rollenüberprüfung anzeigen" +L["Shows the Role Check button. Turn it off and the remaining buttons close the gap."] = "Zeigt die Schaltfläche 'Rollenüberprüfung'. Ist sie ausgeschaltet, rücken die übrigen Schaltflächen nach." +L["Show Convert to Raid"] = "'In Schlachtzug umwandeln' anzeigen" +L["Shows the Convert to Raid button, which reads Convert to Party while you are in a raid."] = "Zeigt die Schaltfläche 'In Schlachtzug umwandeln', die im Schlachtzug 'In Gruppe umwandeln' heißt." +L["Show Disband"] = "'Auflösen' anzeigen" +L["Shows the Disband button. It always asks before disbanding, but hiding it puts it out of misclick range for good."] = "Zeigt die Schaltfläche 'Auflösen'. Sie fragt immer nach, bevor die Gruppe aufgelöst wird -- ausgeblendet ist sie jedoch endgültig außer Reichweite von Fehlklicks." +L["Countdown length of this pull button, in seconds. Set it to 0 to hide the button; with all three at 0 the whole pull row disappears, Stop included."] = "Countdown-Dauer dieser Pull-Schaltfläche in Sekunden. Auf 0 gesetzt wird die Schaltfläche ausgeblendet; stehen alle drei auf 0, verschwindet die gesamte Pull-Zeile samt 'Stopp'."