Skip to content

Commit f18e6ce

Browse files
authored
Merge pull request #2001 from LarryThiessen/fix-1998-macro-box-autofit
#1998 Auto-size the macro-block command box to its content
2 parents d747812 + 87e0d1d commit f18e6ce

1 file changed

Lines changed: 101 additions & 1 deletion

File tree

GSE_GUI/Editor.lua

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,99 @@ end
611611
-- Inline "X/255" indicator anchored to the top-right of the macro edit box,
612612
-- replacing the old side-panel that listed compiled output. Created on first
613613
-- call; subsequent calls just retext + recolour.
614+
-- Size the macro-commands box to its content: one row per line of macro
615+
-- text, never fewer than MACRO_BOX_MIN_LINES (short blocks keep a usable
616+
-- box), never more than MACRO_BOX_MAX_LINES (a huge block scrolls instead
617+
-- of swallowing the window). Re-fitted as the user types; only re-lays out
618+
-- when the row count actually changes so fast typing stays cheap.
619+
local MACRO_BOX_MIN_LINES = 3
620+
local MACRO_BOX_MAX_LINES = 24
621+
-- Rows the widget is BUILT at, before the first fit runs. This has to stay in
622+
-- step with macrolayout's SetHeight(108) below -- NativeUI's SetNumLines(n) is
623+
-- n * 16 + STYLE.frameContentTop (28), so 5 rows is exactly 108. The fit pushes
624+
-- the DELTA from this baseline up through the fixed-height ancestors, so a
625+
-- baseline that disagrees with the container leaves that much dead space under
626+
-- the box. It is NOT the minimum -- MACRO_BOX_MIN_LINES is, and is free to move
627+
-- on its own.
628+
local MACRO_BOX_BASE_LINES = 5
629+
-- Slack the fitted frame carries over the measured text, and the floor NativeUI
630+
-- clamps the inner editbox to (updateEditBoxSize). At a small chat font the
631+
-- min-row fit lands under that floor and the bottom row would render outside
632+
-- the visible scroll area, so the frame is never asked for less.
633+
local MACRO_BOX_CHROME_SLACK = 6
634+
local MACRO_BOX_MIN_INNER = 40
635+
-- Rows -> pixels in the box's OWN font: a row is the measured line height, and
636+
-- every row after the first also carries the editbox's line spacing.
637+
local function MacroBoxRowsHeight(rows, oneRow, spacing)
638+
return rows * oneRow + math.max(rows - 1, 0) * spacing
639+
end
640+
local function FitMacroEditBoxToContent(macroEditBox, text)
641+
if not (macroEditBox and macroEditBox.SetHeight) then return end
642+
local eb = macroEditBox.editBox or macroEditBox.editbox
643+
if not eb then return end
644+
local plain = text or ""
645+
if GSE.DecodeMacroEditorText then plain = GSE.DecodeMacroEditorText(plain) or plain end
646+
plain = tostring(plain)
647+
-- Stored macro text commonly ends with a newline; that trailing newline is
648+
-- not a row the author sees as content, so it is not measured -- EXCEPT
649+
-- while the author is typing on that last empty row (box focused, caret at
650+
-- the end), so pressing Enter at the bottom still opens the new row.
651+
local body = plain:gsub("\n+$", "")
652+
local typingOnTrailingRow = #body < #plain and eb.HasFocus and eb:HasFocus()
653+
and eb.GetCursorPosition and eb.GetText and eb:GetCursorPosition() >= #(eb:GetText() or "")
654+
655+
-- MEASURE the rendered text height with a hidden FontString in the box's
656+
-- own font (wraps included) instead of estimating rows x font size --
657+
-- estimates drifted by about a row and showed a spare empty line.
658+
local meter = macroEditBox.gseHeightMeter
659+
if not meter then
660+
meter = macroEditBox.frame:CreateFontString(nil, "ARTWORK")
661+
meter:Hide()
662+
macroEditBox.gseHeightMeter = meter
663+
end
664+
local fontPath, fontSize, fontFlags = eb:GetFont()
665+
if fontPath then meter:SetFont(fontPath, fontSize or 14, fontFlags or "") end
666+
local spacing = (eb.GetSpacing and eb:GetSpacing()) or 0
667+
if meter.SetSpacing then meter:SetSpacing(spacing) end
668+
meter:SetWordWrap(true)
669+
local width = eb:GetWidth() or 0
670+
meter:SetWidth(width > 50 and width or 600)
671+
meter:SetText("X")
672+
local oneRow = meter:GetStringHeight() or (fontSize or 14)
673+
if oneRow <= 0 then oneRow = fontSize or 14 end
674+
meter:SetText(body ~= "" and body or "X")
675+
local textHeight = meter:GetStringHeight() or oneRow
676+
if typingOnTrailingRow then textHeight = textHeight + oneRow + spacing end
677+
textHeight =
678+
math.max(
679+
MacroBoxRowsHeight(MACRO_BOX_MIN_LINES, oneRow, spacing),
680+
math.min(MacroBoxRowsHeight(MACRO_BOX_MAX_LINES, oneRow, spacing), textHeight)
681+
)
682+
textHeight = math.max(textHeight, MACRO_BOX_MIN_INNER - MACRO_BOX_CHROME_SLACK)
683+
684+
local chrome =
685+
(macroEditBox.labelHeight or 12) + (macroEditBox.verticalOffset or 2) * 3 + MACRO_BOX_CHROME_SLACK
686+
local newHeight = math.ceil(textHeight + chrome)
687+
if macroEditBox.gseFitHeight == newHeight then return end
688+
macroEditBox.gseFitHeight = newHeight
689+
local delta = newHeight - (macroEditBox.height or newHeight)
690+
macroEditBox:SetHeight(newHeight)
691+
-- The box sits under several EXPLICIT-height containers (macrolayout,
692+
-- macroFields, macroBody -- sized at draw time); auto-height ancestors
693+
-- above them only follow if those grow too. Push the delta up through
694+
-- every fixed-height ancestor, relaying out as we go.
695+
local parent = macroEditBox.parent
696+
while parent do
697+
if delta ~= 0 and parent.explicitHeight and not parent.autoAdjustHeight
698+
and parent.height and parent.SetHeight then
699+
parent:SetHeight(parent.height + delta)
700+
elseif parent.DoLayout then
701+
parent:DoLayout()
702+
end
703+
parent = parent.parent
704+
end
705+
end
706+
614707
local function SetMacroCountText(macroEditBox, lenMacro)
615708
if not (macroEditBox and macroEditBox.frame) then return end
616709

@@ -5180,6 +5273,8 @@ function GSE.CreateEditor()
51805273
local macrolayout = UI:Create("SimpleGroup")
51815274
macrolayout:SetLayout("Flow")
51825275
macrolayout:SetFullWidth(true)
5276+
-- 108 == a MACRO_BOX_BASE_LINES-row macro box (SetNumLines: rows * 16 +
5277+
-- frameContentTop); the auto-fit measures its delta from that pairing.
51835278
macrolayout:SetHeight(108)
51845279
if macrolayout.SetFlowOffset then macrolayout:SetFlowOffset(0, 4) end
51855280
if macrolayout.SetFlowPadding then macrolayout:SetFlowPadding(4, 0, 4, 0) end
@@ -5243,6 +5338,10 @@ function GSE.CreateEditor()
52435338
macroFields:AddChild(macrolayout)
52445339
macroBody:AddChild(macroRail)
52455340
macroBody:AddChild(macroFields)
5341+
-- Fit the macro box to its content now that it sits under its containers:
5342+
-- the fit pushes the height delta up through macrolayout/macroFields/
5343+
-- macroBody (all explicit-height, sized above for the 108px baseline).
5344+
FitMacroEditBoxToContent(macroeditbox, macroeditbox:GetText())
52465345
spellcontainer:AddChild(macroBody)
52475346
-- Report the COMPILED macro body length (after spell-name translation)
52485347
-- so the "X/255" indicator matches the over-limit trigger and what WoW
@@ -7296,7 +7395,7 @@ function GSE.CreateEditor()
72967395
DisableMultilineEditorColoring(macroEditBox)
72977396
macroEditBox:SetLabel(L["Macro Name or Macro Commands"])
72987397
macroEditBox:DisableButton(true)
7299-
macroEditBox:SetNumLines(5)
7398+
macroEditBox:SetNumLines(MACRO_BOX_BASE_LINES)
73007399
macroEditBox:SetRelativeWidth(0.5)
73017400
macroEditBox:SetText(spelltext)
73027401
ForwardMacroEditorMouseWheel(macroEditBox, frame)
@@ -7376,6 +7475,7 @@ function GSE.CreateEditor()
73767475
if compiledMacro.parent and compiledMacro.parent.DoLayout then compiledMacro.parent:DoLayout() end
73777476
end
73787477
SetMacroCountText(macroEditBox, GSE.GetMacroEditorTextLength(value or ""))
7478+
FitMacroEditBoxToContent(macroEditBox, value)
73797479
UpdateMacroLimitState(macroEditBox, sequence.Versions[version].Actions[keyPath].macro, editframe, version)
73807480
end
73817481
)

0 commit comments

Comments
 (0)