Show chat copy and the share box in ClassicAPI's scrolling edit box

pfUIScrollingEditBoxTemplate (api/ui-widgets.xml) is ScrollingEditBoxTemplate
with pfUIScrollBarTemplate beside the text. Its mixin's SetFont gives the
box a font object of its own, since the edit box sets its font by object on
every SetText and pfUI fonts are paths. ui-widgets.lua now loads before the
XML, which needs the mixin.

The share box no longer recomputes its scroll child on every text change.

Chat copy reads each chat frame's messages with ClassicAPI's
GetMessageInfo when it opens, so the AddMessage hook, its 100-line copy of
the history and the skip of combat frames are gone. It shows every line
the frame keeps, lines from before login included. It puts the caret at
the end to scroll to the newest line instead of three OnUpdate passes, and
Escape now leaves copy mode on every chat frame.
This commit is contained in:
Brues
2026-10-30 00:38:54 -05:00
parent 26c55bddb0
commit 796f20eadf
5 changed files with 111 additions and 140 deletions
+24
View File
@@ -427,6 +427,30 @@ function pfUI.api.CreateTabFrame(parent, align, outside)
return f
end
-- [ pfUIScrollingEditBoxTemplate ]
-- Mixin of the template in ui-widgets.xml: ClassicAPI's scrolling edit box
-- with pfUI's scroll bar beside it.
_G.pfUIScrollingEditBoxMixin = {}
function pfUIScrollingEditBoxMixin:InitScrollBar()
local scrollBox = self:GetScrollBox()
scrollBox:ClearAllPoints()
scrollBox:SetPoint("TOPLEFT")
scrollBox:SetPoint("BOTTOMRIGHT", self.ScrollBar, "BOTTOMLEFT")
ScrollUtil.RegisterScrollBoxWithScrollBar(scrollBox, self.ScrollBar)
end
-- The edit box takes its font from a font object and sets that object again
-- on every SetText, so a font path goes through a font object of the frame's own.
function pfUIScrollingEditBoxMixin:SetFont(font, size, flags)
if not self.font then
self.font = CreateFont(self:GetName() .. "Font")
self:GetEditBox().fontName = self.font
end
self.font:SetFont(font, size, flags)
self:SetFontObject(self.font)
end
function pfUI.api.CreateScrollFrame(name, parent)
local f = CreateFrame("ScrollFrame", name, parent)
+22
View File
@@ -28,4 +28,26 @@
<EventButton parentKey="Forward" hidden="true"/>
</Frames>
</EventFrame>
<!--
ClassicAPI's ScrollingEditBoxTemplate with pfUIScrollBarTemplate beside the
text. The frame needs a name: SetFont(font, size, flags) names its font
object after it.
-->
<Frame name="pfUIScrollingEditBoxTemplate" inherits="ScrollingEditBoxTemplate" mixin="pfUIScrollingEditBoxMixin" virtual="true">
<KeyValues>
<KeyValue key="maxLetters" value="0" type="number"/>
</KeyValues>
<Frames>
<EventFrame parentKey="ScrollBar" inherits="pfUIScrollBarTemplate">
<Anchors>
<Anchor point="TOPRIGHT"/>
<Anchor point="BOTTOMRIGHT"/>
</Anchors>
</EventFrame>
</Frames>
<Scripts>
<OnLoad method="InitScrollBar" inherit="prepend"/>
</Scripts>
</Frame>
</Ui>
+1 -1
View File
@@ -1,7 +1,7 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="..\api\api.lua"/>
<Include file="..\api\config.lua"/>
<Include file="..\api\ui-widgets.xml"/>
<Include file="..\api\ui-widgets.lua"/>
<Include file="..\api\ui-widgets.xml"/>
<Include file="..\api\unitframes.lua"/>
</Ui>
+47 -106
View File
@@ -1,5 +1,4 @@
pfUI:RegisterModule("chatcopy", function ()
local limit = 100
local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:SetScript("OnEvent", function()
@@ -15,26 +14,27 @@ pfUI:RegisterModule("chatcopy", function ()
button.icon:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Disabled")
button.icon:SetAllPoints()
-- show or hide the copy box of every chat frame
local function SetCopyMode(state)
button.state = state
for i=1, _G.NUM_CHAT_WINDOWS do
local scroll = _G["ChatFrame"..i].scroll
if scroll then
scroll:SetShown(state)
end
end
if state then
button.icon:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Up")
else
button.icon:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Disabled")
end
end
button:SetScript("OnClick", function()
if arg1 == "LeftButton" then
this.state = not this.state
for i=1, _G.NUM_CHAT_WINDOWS do
local frame = _G["ChatFrame"..i]
local scroll = frame.scroll
if scroll and this.state then
scroll:Show()
elseif scroll then
scroll:Hide()
end
end
if this.state then
button.icon:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Up")
else
button.icon:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Disabled")
end
SetCopyMode(not this.state)
elseif arg1 == "RightButton" then
if ChatMenu:IsShown() then
ChatMenu:Hide()
@@ -56,98 +56,39 @@ pfUI:RegisterModule("chatcopy", function ()
for i=1, _G.NUM_CHAT_WINDOWS do
local frame = _G["ChatFrame"..i]
local name = frame:GetName()
local combat = 0
for i, msg in pairs(frame.messageTypeList) do
if strfind(msg, "SPELL", 1) or strfind(msg, "COMBAT", 1) then
combat = combat + 1
-- the chat frame's messages in an edit box to copy from
local scroll = CreateFrame("Frame", "pfChatCopy" .. i, frame, "pfUIScrollingEditBoxTemplate")
scroll:SetAllPoints(frame)
scroll.tex = scroll:CreateTexture(nil, "BACKGROUND")
scroll.tex:SetTexture(0,0,0,.95)
scroll.tex:SetPoint("TOPLEFT", -3, 3)
scroll.tex:SetPoint("BOTTOMRIGHT", 3, -3)
scroll:Hide()
scroll:RegisterCallback("OnEscapePressed", function()
SetCopyMode(false)
end, scroll)
scroll:HookScript("OnShow", function()
-- each line in its own color, which also replaces the |r resets inside it
local lines = {}
for index=1, frame:GetNumMessages() do
local text, r, g, b = frame:GetMessageInfo(index)
local color = rgbhex(r, g, b)
table.insert(lines, color .. text:gsub("|r", color))
end
end
local text = table.concat(lines, "\n")
if combat < 5 then
-- initialize message cache
local history = {}
local AddMessage = frame.AddMessage
frame.AddMessage = function(self,msg,r,g,b)
if msg and r and g and b then
local col = rgbhex(r,g,b)
table.insert(history, 1, col..string.gsub(msg, "|r", col))
elseif msg then
table.insert(history, 1, "|cffffffff"..msg)
end
scroll:SetFont(frame:GetFont())
scroll:SetText(text)
if history[limit] then
table.remove(history, limit)
end
AddMessage(self,msg,r,g,b)
end
-- the cursor at the end scrolls the box to the newest line
scroll:SetFocus()
scroll:SetCursorPosition(#text)
end)
-- read chat defaults
local font, size, flags = frame:GetFont()
-- build the frames
local scroll = CreateScrollFrame("ChatFrameScroll"..i, frame)
scroll:SetAllPoints(frame)
scroll.tex = scroll:CreateTexture(nil, "BACKGROUND")
scroll.tex:SetTexture(0,0,0,.95)
scroll.tex:SetPoint("TOPLEFT", -3, 3)
scroll.tex:SetPoint("BOTTOMRIGHT", 3, -3)
scroll:Hide()
local editbox = CreateFrame("EditBox", "pfChatCopyBox" .. i, scroll)
editbox:SetSize(frame:GetSize())
editbox:SetAllPoints(scroll)
editbox:SetTextColor(1,1,1,1)
editbox:SetFontObject(ChatFontNormal)
editbox:SetFont(font, size, flags)
editbox:SetAutoFocus(true)
editbox:SetMultiLine(true)
editbox:SetMaxLetters(0)
editbox:SetScript("OnMouseDown", function()
editbox.hasFocus = true
end)
editbox:SetScript("OnEscapePressed", function()
if editbox.hasFocus then
editbox:HighlightText(0, 0)
editbox:ClearFocus()
editbox.hasFocus = false
else
editbox:GetParent():Hide()
pfChatCopyButton.icon:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Disabled")
pfChatCopyButton.state = false
end
end)
scroll:SetScrollChild(editbox)
scroll:SetScript("OnShow", function()
editbox:SetText("")
for i=limit,0,-1 do
if history[i] then
editbox:Insert("\n" .. history[i])
end
end
editbox:SetScript("OnUpdate", function()
if not this.count then this.count = 0 end
scroll:UpdateScrollChildRect()
scroll:SetVerticalScroll(scroll:GetVerticalScrollRange())
scroll:Scroll()
this.count = this.count + 1
-- the scroll frame takes a while to update
if this.count >= 3 then
this:SetScript("OnUpdate", nil)
this.count = 0
end
end)
end)
frame.scroll = scroll
end
frame.scroll = scroll
end
this:UnregisterAllEvents()
+17 -33
View File
@@ -205,36 +205,23 @@ pfUI:RegisterModule("share", function ()
table.insert(UISpecialFrames, "pfShare")
do -- Edit Box
f.scroll = pfUI.api.CreateScrollFrame("pfShareScroll", f)
f.scroll = CreateFrame("Frame", "pfShareScroll", f, "pfUIScrollingEditBoxTemplate")
f.scroll:SetPoint("TOPLEFT", f, "TOPLEFT", 10, -30)
f.scroll:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -10, 50)
f.scroll:SetWidth(560)
f.scroll:SetHeight(400)
f.scroll:SetFont(pfUI.media["font:RobotoMono.ttf"], 9)
f.scroll:SetTextInsets(15,15,15,15)
f.scroll.backdrop = CreateFrame("Frame", "pfShareScrollBackdrop", f.scroll)
f.scroll.backdrop:SetFrameLevel(1)
-- the ScrollBox clips its children, so the backdrop is a sibling
f.scroll.backdrop = CreateFrame("Frame", "pfShareScrollBackdrop", f)
f.scroll.backdrop:SetPoint("TOPLEFT", f.scroll, "TOPLEFT", -5, 5)
f.scroll.backdrop:SetPoint("BOTTOMRIGHT", f.scroll, "BOTTOMRIGHT", 5, -5)
pfUI.api.CreateBackdrop(f.scroll.backdrop, nil, true)
f.scroll.backdrop.tint = f.scroll.backdrop:CreateTexture(nil, "ARTWORK")
f.scroll.backdrop.tint:SetAllPoints(f.scroll)
f.scroll.backdrop.tint:SetTexture(1,1,1,.05)
f.scroll.text = CreateFrame("EditBox", "pfShareEditBox", f.scroll)
f.scroll.text.bg = f.scroll.text:CreateTexture(nil, "OVERLAY")
f.scroll.text.bg:SetAllPoints(f.scroll.text)
f.scroll.text.bg:SetTexture(1,1,1,.05)
f.scroll.text:SetMultiLine(true)
f.scroll.text:SetWidth(560)
f.scroll.text:SetHeight(400)
f.scroll.text:SetAllPoints(f.scroll)
f.scroll.text:SetTextInsets(15,15,15,15)
f.scroll.text:SetFont(pfUI.media["font:RobotoMono.ttf"], 9)
f.scroll.text:SetAutoFocus(false)
f.scroll.text:SetJustifyH("LEFT")
f.scroll.text:SetScript("OnEscapePressed", function() this:ClearFocus() end)
f.scroll.text:SetScript("OnTextChanged", function()
this:GetParent():UpdateScrollChildRect()
this:GetParent():UpdateScrollState()
local text = this:GetText()
f.scroll:RegisterCallback("OnTextChanged", function()
local text = f.scroll:GetText()
local blob = Decode(text)
local json = not blob and DecodeJSON(text) or nil
local legacy = not blob and not json and DecodeLegacy(text) or nil
@@ -253,27 +240,26 @@ pfUI:RegisterModule("share", function ()
f.readButton:Enable()
f.readButton.text:SetText(T["Decode"])
f.readButton.func = function()
local current = f.scroll.text:GetText()
local current = f.scroll:GetText()
local config = Decode(current) or DecodeLegacy(current)
if config then
f.scroll.text:SetText(C_EncodingUtil.SerializeJSON(config))
f.scroll:SetText(C_EncodingUtil.SerializeJSON(config))
end
end
elseif json then
f.readButton:Enable()
f.readButton.text:SetText(T["Encode"])
f.readButton.func = function()
local config = DecodeJSON(f.scroll.text:GetText())
local config = DecodeJSON(f.scroll:GetText())
if config then
f.scroll.text:SetText(Encode(config))
f.scroll:SetText(Encode(config))
end
end
else
f.readButton:Disable()
f.readButton.text:SetText(T["N/A"])
end
end)
f.scroll:SetScrollChild(f.scroll.text)
end, f)
end
do -- button: close
@@ -322,7 +308,7 @@ pfUI:RegisterModule("share", function ()
f.loadButton.text:SetFont(pfUI.font_default, pfUI_config.global.font_size, "OUTLINE")
f.loadButton.text:SetText(T["Import"])
f.loadButton:SetScript("OnClick", function()
local text = f.scroll.text:GetText()
local text = f.scroll:GetText()
local config = Decode(text) or DecodeJSON(text) or DecodeLegacy(text)
if not config then return end
@@ -383,9 +369,7 @@ pfUI:RegisterModule("share", function ()
ignored["disabled"] = f.ignorePosition:GetChecked()
local encoded = Encode(DiffConfig(myconfig, defconfig, ignored) or {})
f.scroll.text:SetText(encoded)
f.scroll.text.value = encoded
f.scroll:SetVerticalScroll(0)
f.scroll:SetText(encoded)
end)
end