Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion EllesmereUIQoL/EUI_QoL_RaidTools_Options.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
159 changes: 124 additions & 35 deletions EllesmereUIQoL/EllesmereUIQoL_RaidTools.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 = {},
},
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -1418,7 +1508,6 @@ function Apply()
ApplyVisibility()
ApplyToggleKeybind()
ApplyFonts()
RefreshPullTimes()
RefreshPermissions(true)
end
_G._EUI_RaidTools_Apply = Apply
Expand Down
12 changes: 11 additions & 1 deletion Locales/deDE.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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."
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'."