6 Commits
Author SHA1 Message Date
Brues 76efd5b490 Pass every AddMessage argument through the chat hook
The hook forwarded the text and seventeen named arguments. It takes them
as ... now, which ClassicAPI rewrites to unpack(arg) with arg.n, so every
argument reaches the frame's AddMessage, nils included. GetMessageInfo
returns all of them, and a hook that drops some loses them for every
frame after it.
2026-10-30 01:25:36 -05:00
Brues 393b37b8c3 Add an option to show timestamps in chat copy
"Show Timestamps In Chat Copy" (chat text settings, on by default) is read
each time chat copy opens. With it off, chat copy takes each line through
pfUI.chat.StripTimestamp, which removes the exact timestamp AddMessage
prepends: the configured color and brackets, so other bracketed text
stays.

Whispers are now recolored before the timestamp goes on, not after. The
recolor turned the stamp's closing "|r " into "|r" plus the whisper color,
so whisper lines did not match. The shown text and the saved history come
out the same.
2026-10-30 01:25:36 -05:00
Brues 7928db33bf Show the equipment manager's lists in ClassicAPI ScrollBoxes
The set list, the unused-items grid and the trigger list each drew a
fixed number of slots and moved them with a mouse-wheel offset. All three
are pfUIScrollBoxListTemplate lists now, with a scroll bar.

The set list's rows are the sets and then the "New Set" entry, set up by
one initializer. Refresh rebuilds them only when the sets change and
otherwise reinitializes the shown rows, so a row keeps its frame between
the two clicks of the native OnDoubleClick that now equips a set, in
place of the hand-timed double click. PickupEquipmentSet is called
without a presence check.

The row's gear passes mouse motion on to the row, so moving onto it no
longer leaves the row and the MouseIsOverHitRect workaround is gone. The
gear rests at half alpha and lights up on hover with an additive copy of
itself, instead of the blue square highlight.

The unused items are a grid view that keeps its scroll position on
refresh. The trigger list scrolls to a new trigger with ScrollToEnd.
2026-10-30 01:07:22 -05:00
Brues 5d8314b2d4 Scroll the config panels with ClassicAPI's scroll bar
pfUIScrollFrameTemplate (api/ui-widgets.xml) is a ScrollFrame with
pfUIScrollBarTemplate inside its right edge and a Content scroll child,
driven by ScrollUtil.InitScrollFrameWithScrollBar. The panels keep a
ScrollFrame because the engine measures its range from the shown frames
inside the content, which the hand-placed config rows rely on. The bar
follows OnScrollRangeChanged instead of an OnUpdate poll per panel.

A panel measures its range once its rows are built, and the search
results measure theirs with UpdateScrollChildRect instead of hiding,
re-attaching and scrolling a frame later. Clearing the search measures
again too.

CreateScrollFrame and CreateScrollChild have no users left, and nothing
called CreateTabFrame or CreateTabChild; all four are gone. pfQuest's
compat layer brings its own copies of the scroll helpers.
2026-10-30 00:51:16 -05:00
Brues 3987cfb8a0 Show loot history and the icon picker in ClassicAPI ScrollBoxes
pfUIScrollBoxListTemplate (api/ui-widgets.xml) is a WowScrollBoxList with
pfUIScrollBarTemplate beside it, 5px inside the frame, so a list's
backdrop goes on the frame itself. The addon list moves onto it and drops
the sibling backdrop frame.

Loot history builds a flat list of item rows and, under an expanded item,
player rows; the view sizes and indents them. The item frame array, the
player pool, the hand-placed rows and the scroll child re-attach are gone,
and the scroll position holds across roll updates.

The icon picker's FauxScrollFrame and 80 fixed buttons become a grid view
over the provider's icon indices. Picking an icon reinitializes the shown
buttons instead of redrawing the grid, and closing the popup drops the
grid's entries along with the provider.
2026-10-30 00:47:07 -05:00
Brues 796f20eadf 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.
2026-10-30 00:38:54 -05:00
11 changed files with 489 additions and 758 deletions
+1
View File
@@ -825,6 +825,7 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("chat", "text", "timeformat", "%H:%M:%S")
pfUI:UpdateConfig("chat", "text", "timebracket", "[]")
pfUI:UpdateConfig("chat", "text", "timecolor", ".8,.8,.8,1")
pfUI:UpdateConfig("chat", "text", "copytime", "1")
pfUI:UpdateConfig("chat", "text", "tintunknown", "1")
pfUI:UpdateConfig("chat", "text", "unknowncolor", ".7,.7,.7,1")
pfUI:UpdateConfig("chat", "text", "channelnumonly", "1")
+81 -249
View File
@@ -316,186 +316,28 @@ do -- dropdown
end
end
function pfUI.api.CreateTabChild(self, title, bwidth, bheight, bottom, static)
-- create tab button
local b = CreateFrame("Button", "pfConfig" .. title .. "Button", self, "UIPanelButtonTemplate")
b:SetText(title)
-- [ pfUIScrollingEditBoxTemplate ]
-- Mixin of the template in ui-widgets.xml: ClassicAPI's scrolling edit box
-- with pfUI's scroll bar beside it.
_G.pfUIScrollingEditBoxMixin = {}
-- setup env
local childcount = table.getn(self.childs) + 1
local button_width = bwidth
local button_height = bheight or 20
local border = 4
if not button_width then
button_width = 150
elseif button_width == true then
button_width = _G["pfConfig" .. title .. "ButtonText"]:GetStringWidth() + 4 * border
end
-- set dimensions
b:SetSize(button_width, button_height)
b:SetID(childcount)
if not self.align or self.align == "LEFT" then
local outside = self.outside and -2 * border - button_width or 0
if bottom then
b:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", border + outside, (self.bottomcount-1) * (button_height) + (self.bottomcount * border) )
else
b:SetPoint("TOPLEFT", self, "TOPLEFT", border + outside, -(childcount-1) * (button_height) - (childcount * border) )
end
elseif self.align == "TOP" then
local outside = self.outside and 2 * border + button_height or 0
local prev_button = self.buttons[getn(self.buttons)]
if prev_button then
b:SetPoint("TOPLEFT", prev_button, "TOPRIGHT", border, 0)
else
b:SetPoint("TOPLEFT", self, "TOPLEFT", border + (self.outside and -border), -border + outside )
end
end
SkinButton(b,.2,1,.8)
if childcount ~= 1 then
b:SetTextColor(.5,.5,.5)
else
b:SetTextColor(.2,1,.8)
end
b:SetScript("OnClick", function()
for k,v in pairs(self.childs) do
v:Hide()
end
self.childs[this:GetID()]:Show()
for k,v in pairs(self.buttons) do
v.active = false
v:SetTextColor(.5,.5,.5)
end
self.buttons[this:GetID()]:SetTextColor(.2,1,.8)
end)
self.buttons[childcount] = b
self.bottomcount = bottom and self.bottomcount + 1 or self.bottomcount
-- create child frame
local child, scrollchild = nil, nil
if not static then
child = CreateScrollFrame("pfConfig" .. title .. "Frame", self)
scrollchild = CreateScrollChild("pfConfig" .. title .. "ScrollChild", child)
else
child = CreateFrame("Frame", "pfConfig" .. title .. "Frame", self)
end
if childcount ~= 1 then child:Hide() end
if not self.align or self.align == "LEFT" then
child:SetPoint("TOPLEFT", self, "TOPLEFT", button_width + 2*border + 5, -border -5)
child:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -border -5 , border + 5)
elseif self.align == "TOP" then
if self.outside then
child:SetPoint("TOPLEFT", self, "TOPLEFT", 5, -5)
child:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -5, 5)
end
end
CreateBackdrop(child)
SetAllPointsOffset(child.backdrop, child, -5,5)
local ret = scrollchild or child
ret.button = b
table.insert(self.childs, child)
return ret
function pfUIScrollingEditBoxMixin:InitScrollBar()
local scrollBox = self:GetScrollBox()
scrollBox:ClearAllPoints()
scrollBox:SetPoint("TOPLEFT")
scrollBox:SetPoint("BOTTOMRIGHT", self.ScrollBar, "BOTTOMLEFT")
ScrollUtil.RegisterScrollBoxWithScrollBar(scrollBox, self.ScrollBar)
end
function pfUI.api.CreateTabFrame(parent, align, outside)
local f = CreateFrame("Frame", nil, parent)
f:SetPoint("TOPLEFT", parent, "TOPLEFT", -5, 5)
f:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", 5, -5)
-- setup env
f.childs = { }
f.buttons = { }
f.align = align
f.outside = outside
f.bottomcount = 1
-- Create Child Frame
f.CreateTabChild = pfUI.api.CreateTabChild
return f
end
function pfUI.api.CreateScrollFrame(name, parent)
local f = CreateFrame("ScrollFrame", name, parent)
-- create slider
f.slider = CreateFrame("Slider", nil, f)
f.slider:SetOrientation('VERTICAL')
f.slider:SetPoint("TOPLEFT", f, "TOPRIGHT", -7, 0)
f.slider:SetPoint("BOTTOMRIGHT", 0, 0)
f.slider:SetThumbTexture(pfUI.media["img:col"])
f.slider.thumb = f.slider:GetThumbTexture()
f.slider.thumb:SetHeight(50)
f.slider.thumb:SetTexture(.3,1,.8,.5)
f.slider:SetScript("OnValueChanged", function()
f:SetVerticalScroll(this:GetValue())
f.UpdateScrollState()
end)
f.UpdateScrollState = function()
f.slider:SetMinMaxValues(0, f:GetVerticalScrollRange())
f.slider:SetValue(f:GetVerticalScroll())
local m = f:GetHeight()+f:GetVerticalScrollRange()
local v = f:GetHeight()
local ratio = v / m
if ratio < 1 then
local size = math.floor(v * ratio)
f.slider.thumb:SetHeight(size)
f.slider:Show()
else
f.slider:Hide()
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
f.Scroll = function(self, step)
local step = step or 0
local current = f:GetVerticalScroll()
local max = f:GetVerticalScrollRange()
local new = current - step
f:SetVerticalScroll(Clamp(new, 0, max))
f:UpdateScrollState()
end
f:EnableMouseWheel(1)
f:SetScript("OnMouseWheel", function()
this:Scroll(arg1*10)
end)
return f
end
function pfUI.api.CreateScrollChild(name, parent)
local f = CreateFrame("Frame", name, parent)
-- dummy values required
f:SetSize(1, 1)
f:SetAllPoints(parent)
parent:SetScrollChild(f)
f:SetScript("OnUpdate", function()
this:GetParent():UpdateScrollState()
end)
return f
self.font:SetFont(font, size, flags)
self:SetFontObject(self.font)
end
-- [ CreateTextBox ]
@@ -1228,7 +1070,7 @@ end
-- survives filter changes -- a spell icon you picked still saves after you
-- switch the filter to "Items" and it drops out of the visible grid.
--
-- name global-name prefix for the scroll frame and editboxes
-- name global-name prefix for the icon grid and editboxes
-- parent the popup frame to attach the widgets to
-- extraType IconDataProviderExtraType.* seed (Spellbook / Equipment)
-- nameLabelText header shown above the name field
@@ -1298,17 +1140,13 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText)
parent.iconLabel:SetPoint("TOPLEFT", parent, "TOPLEFT", 14, -86)
parent.iconLabel:SetText(MACRO_POPUP_CHOOSE_ICON)
-- Icon grid + scroll
local iconScroll = CreateFrame("ScrollFrame", name.."Scroll", parent, "FauxScrollFrameTemplate")
iconScroll:SetPoint("TOPLEFT", parent, "TOPLEFT", 14, -116)
iconScroll:SetWidth(ICON_GRID_COLS * (ICON_BTN_SIZE + ICON_BTN_PAD) - ICON_BTN_PAD)
iconScroll:SetHeight(ICON_GRID_ROWS * (ICON_BTN_SIZE + ICON_BTN_PAD) - ICON_BTN_PAD)
local scrollbar = _G[name.."ScrollScrollBar"]
scrollbar:ClearAllPoints()
scrollbar:SetPoint("TOPLEFT", iconScroll, "TOPRIGHT", 8, -16)
scrollbar:SetPoint("BOTTOMLEFT", iconScroll, "BOTTOMRIGHT", 8, 16)
SkinScrollbar(scrollbar)
-- Icon grid: the template keeps 5px around the grid and its 7px scroll bar,
-- and the grid leaves 4px before the bar
local gridWidth = ICON_GRID_COLS * (ICON_BTN_SIZE + ICON_BTN_PAD) - ICON_BTN_PAD
local gridHeight = ICON_GRID_ROWS * (ICON_BTN_SIZE + ICON_BTN_PAD) - ICON_BTN_PAD
local grid = CreateFrame("Frame", name.."Icons", parent, "pfUIScrollBoxListTemplate")
grid:SetPoint("TOPLEFT", parent, "TOPLEFT", 9, -111)
grid:SetSize(gridWidth + 4 + 7 + 10, gridHeight + 10)
-- Filter dropdown: All / Spells / Items
local filterDropdown = CreateFrame("Frame", name.."Filter", parent, "UIDropDownMenuTemplate")
@@ -1343,38 +1181,54 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText)
UIDropDownMenu_SetSelectedValue(filterDropdown, "all")
SkinDropDown(filterDropdown)
local iconButtons = {}
for r = 1, ICON_GRID_ROWS do
for c = 1, ICON_GRID_COLS do
local i = (r - 1) * ICON_GRID_COLS + c
local btn = CreateFrame("Button", nil, parent)
btn:SetSize(ICON_BTN_SIZE, ICON_BTN_SIZE)
btn:SetPoint("TOPLEFT", iconScroll, "TOPLEFT", (c-1) * (ICON_BTN_SIZE + ICON_BTN_PAD), -(r-1) * (ICON_BTN_SIZE + ICON_BTN_PAD))
-- the selected icon gets a gold border in the grid and shows in the preview
local function UpdateSelection()
grid.ScrollBox:ReinitializeFrames()
parent.selectedPreview.tex:SetTexture(selectedIconPath)
end
local function IconOnClick()
local path = provider:GetIconByIndex(this.iconIndex)
if path then selectedIconPath = path end
UpdateSelection()
end
local function IconOnEnter()
local path = provider:GetIconByIndex(this.iconIndex)
if type(path) == "string" then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText(IconKey(path), 1, 1, 1)
GameTooltip:Show()
end
end
local function InitIconButton(btn, icon)
-- one-time setup of a pooled button
if not btn.texture then
CreateBackdrop(btn)
btn.texture = btn:CreateTexture(nil, "ARTWORK")
btn.texture:SetAllPoints(btn)
btn.texture:SetTexCoord(.08, .92, .08, .92)
btn:SetScript("OnClick", function()
if this.iconIndex and provider then
local path = provider:GetIconByIndex(this.iconIndex)
if path then selectedIconPath = path end
RefreshIconGrid()
end
end)
btn:SetScript("OnEnter", function()
if not this.iconIndex or not provider then return end
local path = provider:GetIconByIndex(this.iconIndex)
if type(path) == "string" then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText(IconKey(path), 1, 1, 1)
GameTooltip:Show()
end
end)
btn:SetScript("OnClick", IconOnClick)
btn:SetScript("OnEnter", IconOnEnter)
btn:SetScript("OnLeave", GameTooltip_Hide)
iconButtons[i] = btn
end
btn.iconIndex = icon.index
local path = provider:GetIconByIndex(icon.index)
btn.texture:SetTexture(path)
if IconKey(path) == IconKey(selectedIconPath) then
btn.backdrop:SetBackdropBorderColor(1, 0.82, 0, 1)
else
btn.backdrop:SetBackdropBorderColor(pfUI.cache.er, pfUI.cache.eg, pfUI.cache.eb, pfUI.cache.ea)
end
end
local view = CreateScrollBoxListGridView(ICON_GRID_COLS, 0, 0, 0, 4, ICON_BTN_PAD, ICON_BTN_PAD)
view:SetElementSize(ICON_BTN_SIZE, ICON_BTN_SIZE)
view:SetElementInitializer("Button", InitIconButton)
ScrollUtil.InitScrollBoxListWithScrollBar(grid.ScrollBox, grid.ScrollBar, view)
-- Rebuild the search-filtered index list (provider indices whose icon
-- basename contains the search text); nil when the search box is empty.
function RebuildFilter()
@@ -1392,38 +1246,17 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText)
end
end
-- one grid entry per provider index the filter lets through, scrolled to the top
function RefreshIconGrid()
EnsureProvider()
local numIcons = filtered and table.getn(filtered) or provider:GetNumIcons()
local numRows = math.ceil(numIcons / ICON_GRID_COLS)
FauxScrollFrame_Update(iconScroll, numRows, ICON_GRID_ROWS, ICON_BTN_SIZE + ICON_BTN_PAD)
local offset = FauxScrollFrame_GetOffset(iconScroll)
for i = 1, ICON_GRID_ROWS * ICON_GRID_COLS do
local listIdx = i + offset * ICON_GRID_COLS
local btn = iconButtons[i]
if listIdx <= numIcons then
btn:Show()
local providerIdx = filtered and filtered[listIdx] or listIdx
btn.iconIndex = providerIdx
local path = provider:GetIconByIndex(providerIdx)
btn.texture:SetTexture(path)
if IconKey(path) == IconKey(selectedIconPath) then
btn.backdrop:SetBackdropBorderColor(1, 0.82, 0, 1)
else
btn.backdrop:SetBackdropBorderColor(pfUI.cache.er, pfUI.cache.eg, pfUI.cache.eb, pfUI.cache.ea)
end
else
btn:Hide()
btn.iconIndex = nil
end
if filtered then
grid.ScrollBox:SetDataProvider(CreateDataProviderWithAssignedKey(filtered, "index"))
else
grid.ScrollBox:SetDataProvider(CreateDataProviderByIndexCount(provider:GetNumIcons()))
end
parent.selectedPreview.tex:SetTexture(selectedIconPath)
end
iconScroll:SetScript("OnVerticalScroll", function()
FauxScrollFrame_OnVerticalScroll(ICON_BTN_SIZE + ICON_BTN_PAD, function() RefreshIconGrid() end)
end)
-- Search box (bottom-left) filters the grid by icon name.
parent.searchLabel = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
parent.searchLabel:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 16, 18)
@@ -1438,13 +1271,14 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText)
parent.search:SetScript("OnTextChanged", function()
searchText = strupper(strtrim(this:GetText()))
RebuildFilter()
scrollbar:SetValue(0)
RefreshIconGrid()
end)
-- Release the provider when the popup closes so its icon cache GCs.
-- Release the provider when the popup closes so its icon cache GCs, and
-- the grid's entries that index into it.
parent:HookScript("OnHide", function()
if provider then provider:Release(); provider = nil end
grid.ScrollBox:RemoveDataProvider()
end)
local handle = { editbox = parent.editbox, search = parent.search }
@@ -1452,15 +1286,13 @@ function pfUI.api.CreateIconPicker(name, parent, extraType, nameLabelText)
function handle.SetIcon(path) selectedIconPath = path or QUESTION_MARK end
function handle.Refresh() RefreshIconGrid() end
function handle.SetIconAreaShown(shown)
local method = shown and "Show" or "Hide"
iconScroll[method](iconScroll)
for _, b in ipairs(iconButtons) do b[method](b) end
parent.iconLabel[method](parent.iconLabel)
parent.selectedLabel[method](parent.selectedLabel)
parent.selectedPreview[method](parent.selectedPreview)
filterDropdown[method](filterDropdown)
parent.searchLabel[method](parent.searchLabel)
parent.search[method](parent.search)
grid:SetShown(shown)
parent.iconLabel:SetShown(shown)
parent.selectedLabel:SetShown(shown)
parent.selectedPreview:SetShown(shown)
filterDropdown:SetShown(shown)
parent.searchLabel:SetShown(shown)
parent.search:SetShown(shown)
end
return handle
end
+74
View File
@@ -28,4 +28,78 @@
<EventButton parentKey="Forward" hidden="true"/>
</Frames>
</EventFrame>
<!--
A ScrollFrame for free-form content, with pfUIScrollBarTemplate inside its
right edge. Put the content in frame.Content, which spans the frame: the
engine measures the scroll range from the shown frames inside it, so the
content needs no height. Changes inside it are not measured until
frame:UpdateScrollChildRect().
-->
<ScrollFrame name="pfUIScrollFrameTemplate" virtual="true">
<Frames>
<EventFrame parentKey="ScrollBar" inherits="pfUIScrollBarTemplate">
<Anchors>
<Anchor point="TOPRIGHT"/>
<Anchor point="BOTTOMRIGHT"/>
</Anchors>
</EventFrame>
</Frames>
<ScrollChild>
<Frame parentKey="Content">
<Size x="1" y="1"/>
</Frame>
</ScrollChild>
<Scripts>
<OnLoad>
self.Content:SetAllPoints()
self:EnableMouseWheel(true)
ScrollUtil.InitScrollFrameWithScrollBar(self, self.ScrollBar)
</OnLoad>
</Scripts>
</ScrollFrame>
<!--
A WowScrollBoxList with pfUIScrollBarTemplate beside it, both 5px inside the
frame so CreateBackdrop(frame, nil, true) can frame them. Fill it with
ScrollUtil.InitScrollBoxListWithScrollBar(frame.ScrollBox, frame.ScrollBar, view).
-->
<Frame name="pfUIScrollBoxListTemplate" virtual="true">
<Frames>
<EventFrame parentKey="ScrollBar" inherits="pfUIScrollBarTemplate">
<Anchors>
<Anchor point="TOPRIGHT" x="-5" y="-5"/>
<Anchor point="BOTTOMRIGHT" x="-5" y="5"/>
</Anchors>
</EventFrame>
<Frame parentKey="ScrollBox" inherits="WowScrollBoxList">
<Anchors>
<Anchor point="TOPLEFT" x="5" y="-5"/>
<Anchor point="BOTTOMRIGHT" relativeKey="$parent.ScrollBar" relativePoint="BOTTOMLEFT"/>
</Anchors>
</Frame>
</Frames>
</Frame>
<!--
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>
+11 -20
View File
@@ -133,7 +133,7 @@ pfUI:RegisterModule("addons", function ()
end
end
pfUI.addons.scroll:ReinitializeFrames()
pfUI.addons.list.ScrollBox:ReinitializeFrames()
end
-- addon profiles
@@ -305,30 +305,21 @@ pfUI:RegisterModule("addons", function ()
end
-- addon list: a ScrollBox keeps rows only for the addons in view
pfUI.addons.scroll = CreateFrame("Frame", "pfAddonListScroll", pfUI.addons, "WowScrollBoxList")
pfUI.addons.scroll:SetSize(360, 410)
pfUI.addons.scroll:SetPoint("BOTTOM", 0, 10)
pfUI.addons.list = CreateFrame("Frame", "pfAddonList", pfUI.addons, "pfUIScrollBoxListTemplate")
pfUI.addons.list:SetSize(370, 420)
pfUI.addons.list:SetPoint("BOTTOM", 0, 5)
CreateBackdrop(pfUI.addons.list, nil, true)
-- the ScrollBox clips its children, so the backdrop is a sibling
pfUI.addons.scroll.backdrop = CreateFrame("Frame", nil, pfUI.addons)
pfUI.addons.scroll.backdrop:SetPoint("TOPLEFT", pfUI.addons.scroll, "TOPLEFT", -5, 5)
pfUI.addons.scroll.backdrop:SetPoint("BOTTOMRIGHT", pfUI.addons.scroll, "BOTTOMRIGHT", 5, -5)
CreateBackdrop(pfUI.addons.scroll.backdrop, nil, true)
local scrollbar = CreateFrame("EventFrame", nil, pfUI.addons, "pfUIScrollBarTemplate")
scrollbar:SetPoint("TOPRIGHT", pfUI.addons.scroll, "TOPRIGHT")
scrollbar:SetPoint("BOTTOMRIGHT", pfUI.addons.scroll, "BOTTOMRIGHT")
local view = CreateScrollBoxListLinearView(5, 5, 5, 15)
local view = CreateScrollBoxListLinearView(5, 5, 5, 8)
view:SetElementExtent(25)
view:SetElementInitializer("Button", InitRow)
ScrollUtil.InitScrollBoxListWithScrollBar(pfUI.addons.scroll, scrollbar, view)
pfUI.addons.scroll:SetDataProvider(CreateDataProvider(addons))
ScrollUtil.InitScrollBoxListWithScrollBar(pfUI.addons.list.ScrollBox, pfUI.addons.list.ScrollBar, view)
pfUI.addons.list.ScrollBox:SetDataProvider(CreateDataProvider(addons))
-- a load-on-demand addon that loads brightens its row
pfUI.addons.scroll:RegisterEvent("ADDON_LOADED")
pfUI.addons.scroll:SetScript("OnEvent", function(self)
self:ReinitializeFrames()
pfUI.addons.list:RegisterEvent("ADDON_LOADED")
pfUI.addons.list:SetScript("OnEvent", function(self)
self.ScrollBox:ReinitializeFrames()
end)
end)
+27 -10
View File
@@ -779,6 +779,20 @@ pfUI:RegisterModule("chat", function ()
local r,g,b,a = GetStringColor(C.chat.text.timecolor)
local timecolorhex = rgbhex(r,g,b,a)
-- AddMessage puts the time between these at the start of each line
local timestampStart = timecolorhex .. tleft
local timestampEnd = tright .. "|r "
-- [ StripTimestamp ]
-- Returns a chat line without the timestamp AddMessage put before it.
function pfUI.chat.StripTimestamp(text)
if C.chat.text.time ~= "1" or text:sub(1, #timestampStart) ~= timestampStart then
return text
end
local _, last = text:find(timestampEnd, #timestampStart + 1, true)
return last and text:sub(last + 1) or text
end
local r,g,b = GetStringColor(C.chat.text.unknowncolor)
local unknowncolorhex = rgbhex(r,g,b)
@@ -788,12 +802,14 @@ pfUI:RegisterModule("chat", function ()
return pfUI_playerDB[name].level
end
local function AddMessage(frame, text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
-- Passes every argument after the text on: GetMessageInfo returns them all,
-- and a hook that drops some loses them for every frame after it.
local function AddMessage(frame, text, ...)
if not text then return end
-- skip chat parsing on combat log
if frame.pfCombatLog then
return frame:HookAddMessage(text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
return frame:HookAddMessage(text, ...)
end
-- payload of the CHAT_MSG event printing this line; nil for lines
@@ -879,24 +895,25 @@ pfUI:RegisterModule("chat", function ()
-- pushes the whisper colour code off position 1 and the find below fails
local isWhisper = C.chat.global.whispermod == "1" and string.find(text, wcol, 1) == 1
if isWhisper then
-- patch incoming whisper string to match the colors, before the
-- timestamp so it keeps the form StripTimestamp looks for
text = string.gsub(text, "|r", "|r" .. wcol)
end
-- show timestamp in chat
if C.chat.text.time == "1" then
text = timecolorhex .. tleft .. date(C.chat.text.timeformat) .. tright .. "|r " .. text
text = timestampStart .. date(C.chat.text.timeformat) .. timestampEnd .. text
end
-- save chat history
if isWhisper then
SaveChatHistory(frame:GetID(), string.gsub(text, wcol, ""), cr, cg, cb)
else
SaveChatHistory(frame:GetID(), text, a1, a2, a3)
SaveChatHistory(frame:GetID(), text, ...)
end
if isWhisper then
-- patch incoming whisper string to match the colors
text = string.gsub(text, "|r", "|r" .. wcol)
end
frame:HookAddMessage(text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
frame:HookAddMessage(text, ...)
end
for i=1,NUM_CHAT_WINDOWS do
+50 -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,42 @@ 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)
if C.chat.text.copytime == "0" then
text = pfUI.chat.StripTimestamp(text)
end
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()
+154 -238
View File
@@ -270,39 +270,20 @@ pfUI:RegisterModule("equipmentmanager", function()
-- ============================================================
local LIST_VISIBLE_ROWS = 7
local LIST_ROW_STRIDE = SET_ROW_HEIGHT + 2
local listFrame = CreateFrame("Frame", nil, frame)
-- The template keeps 5px around the rows, which sit 2px apart.
local listFrame = CreateFrame("Frame", nil, frame, "pfUIScrollBoxListTemplate")
listFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -58)
-- Height fits N rows + (N-1) inter-row gaps + 3px top/bottom padding.
listFrame:SetSize(180, LIST_VISIBLE_ROWS * LIST_ROW_STRIDE + 4)
listFrame:SetSize(180, LIST_VISIBLE_ROWS * (SET_ROW_HEIGHT + 2) - 2 + 10)
CreateBackdrop(listFrame, nil, nil, .75)
-- Mouse-wheel scroll: list of [sets..., newSetRow] is virtualized
-- through LIST_VISIBLE_ROWS slots. Refresh() consumes listFrame.offset
-- and the wheel handler clamps + bumps it.
listFrame.offset = 0
listFrame:EnableMouseWheel(true)
listFrame:SetScript("OnMouseWheel", function()
listFrame.offset = listFrame.offset - (arg1 or 0)
pfUI.equipmentmanager.Refresh()
end)
local setRows = {}
local function CreateSetRow()
local row = CreateFrame("Button", nil, listFrame)
row:SetSize(170, SET_ROW_HEIGHT)
-- Position is set per-Refresh based on the row's visible slot;
-- start anchored to avoid uninitialized geometry before first Refresh.
row:SetPoint("TOPLEFT", listFrame, "TOPLEFT", 5, -3)
-- One-time setup of a pooled row. A row shows a set or, last in the
-- list, the "New Set" entry; InitSetRow sets what differs.
local function SetupSetRow(row)
row.icon = row:CreateTexture(nil, "ARTWORK")
row.icon:SetSize(30, 30)
row.icon:SetPoint("LEFT", row, "LEFT", 2, 0)
row.icon:SetTexCoord(.08, .92, .08, .92)
row.icon:SetPoint("CENTER", row, "LEFT", 17, 0)
row.text = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
row.text:SetPoint("LEFT", row.icon, "RIGHT", 6, 0)
row.text:SetPoint("RIGHT", row, "RIGHT", -22, 0)
row.text:SetPoint("LEFT", row, "LEFT", 38, 0)
row.text:SetJustifyH("LEFT")
row.highlight = row:CreateTexture(nil, "BACKGROUND")
@@ -316,7 +297,11 @@ pfUI:RegisterModule("equipmentmanager", function()
row.gear.tex = row.gear:CreateTexture(nil, "ARTWORK")
row.gear.tex:SetAllPoints(row.gear)
row.gear.tex:SetTexture(pfUI.path.."\\img\\Gear_64Grey")
row.gear:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
row.gear.tex:SetAlpha(.5)
-- the gear drawn again additively lights up the gear itself
row.gear:SetHighlightTexture(pfUI.path.."\\img\\Gear_64Grey", "ADD")
-- moving onto the gear does not leave the row
row.gear:SetPropagateMouseMotion(true)
row.gear:Hide()
row.gear:SetScript("OnClick", function()
if not row.setID then return end
@@ -335,39 +320,30 @@ pfUI:RegisterModule("equipmentmanager", function()
end)
row:SetScript("OnClick", function()
selectedSetID = row.setID
-- Detect double-click manually; vanilla Button has no native event.
local now = GetTime()
if row.lastClick and (now - row.lastClick) < 0.4 then
row.lastClick = nil
EquipSet(row.setID)
if row.setID then
selectedSetID = row.setID
pfUI.equipmentmanager.Refresh()
else
row.lastClick = now
OpenNamePopup("new")
end
pfUI.equipmentmanager.Refresh()
end)
row:SetScript("OnDoubleClick", function()
if row.setID then EquipSet(row.setID) end
end)
-- Drag a set onto an action bar. PickupEquipmentSet is newer than
-- the rest of C_EquipmentSet, so dragging stays inert on ClassicAPI
-- builds that don't ship it yet.
if C_EquipmentSet.PickupEquipmentSet then
row:RegisterForDrag("LeftButton")
row:SetScript("OnDragStart", function()
if row.setID then C_EquipmentSet.PickupEquipmentSet(row.setID) end
end)
end
-- Drag a set onto an action bar.
row:RegisterForDrag("LeftButton")
row:SetScript("OnDragStart", function()
if row.setID then C_EquipmentSet.PickupEquipmentSet(row.setID) end
end)
-- Show the gear and tooltip while the cursor is over the row or its
-- gear child. The gear sits inside the row's rectangle, so a single
-- MouseIsOverHitRect(row) check covers both. OnLeave on the row and the
-- gear catches every exit path, so no OnUpdate poll is needed.
local function HideRowHover()
if MouseIsOverHitRect(row) then return end
GameTooltip:Hide()
row.gear:Hide()
end
-- A set row shows its gear and tooltip while the cursor is over it;
-- the "New Set" row lights up.
row:SetScript("OnEnter", function()
if not row.setID then return end
if not row.setID then
row.highlight:Show()
return
end
local name = C_EquipmentSet.GetEquipmentSetInfo(row.setID)
if name then
GameTooltip:SetOwner(row, "ANCHOR_RIGHT")
@@ -376,40 +352,50 @@ pfUI:RegisterModule("equipmentmanager", function()
end
row.gear:Show()
end)
row:SetScript("OnLeave", HideRowHover)
row.gear:SetScript("OnLeave", HideRowHover)
return row
row:SetScript("OnLeave", function()
GameTooltip:Hide()
row.gear:Hide()
if not row.setID then row.highlight:Hide() end
end)
end
-- Rows are allocated lazily in Refresh — ClassicAPI no longer caps
-- the number of equipment sets, so we grow the pool to numSets on
-- demand. The set list is wheel-scrolled, so only LIST_VISIBLE_ROWS
-- are ever positioned in-frame at a time, but each row is bound to a
-- specific set index (row[i] always shows ids[i]).
local function InitSetRow(row, entry)
if not row.text then SetupSetRow(row) end
local newSetRow = CreateFrame("Button", nil, listFrame)
newSetRow:SetSize(170, SET_ROW_HEIGHT);
row.setID = entry.setID
row.gear:Hide()
newSetRow.icon = newSetRow:CreateTexture(nil, "ARTWORK")
newSetRow.icon:SetSize(24, 24);
newSetRow.icon:SetPoint("LEFT", newSetRow, "LEFT", 5, 0)
newSetRow.icon:SetTexture(pfUI.path.."\\img\\Character-Plus")
if not entry.setID then
row.icon:SetSize(24, 24)
row.icon:SetTexCoord(0, 1, 0, 1)
row.icon:SetTexture(pfUI.path.."\\img\\Character-Plus")
row.text:SetPoint("RIGHT", row, "RIGHT", -4, 0)
row.text:SetText(PAPERDOLL_NEWEQUIPMENTSET)
row.text:SetTextColor(0.2, 1, 0.2)
row.highlight:Hide()
return
end
newSetRow.text = newSetRow:CreateFontString(nil, "OVERLAY", "GameFontNormal")
newSetRow.text:SetPoint("LEFT", newSetRow.icon, "RIGHT", 8, 0)
newSetRow.text:SetPoint("RIGHT", newSetRow, "RIGHT", -4, 0)
newSetRow.text:SetJustifyH("LEFT")
newSetRow.text:SetText(PAPERDOLL_NEWEQUIPMENTSET)
newSetRow.text:SetTextColor(0.2, 1, 0.2)
local name, icon, _, isEquipped, _, _, _, numMissing = C_EquipmentSet.GetEquipmentSetInfo(entry.setID)
row.icon:SetSize(30, 30)
row.icon:SetTexCoord(.08, .92, .08, .92)
if icon then
row.icon:SetTexture(string.find(icon, "\\") and icon or ("Interface\\Icons\\" .. icon))
else
row.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
end
-- Color precedence: missing items (red) > equipped (green) > normal (white).
local color = (numMissing and numMissing > 0) and "|cffff5555"
or isEquipped and "|cff33ff33" or "|cffffffff"
row.text:SetPoint("RIGHT", row, "RIGHT", -22, 0)
row.text:SetText(color .. (name or "?") .. "|r")
row.highlight:SetShown(entry.setID == selectedSetID)
end
newSetRow.highlight = newSetRow:CreateTexture(nil, "BACKGROUND")
newSetRow.highlight:SetAllPoints(newSetRow)
newSetRow.highlight:SetTexture(.3, .3, .3, .4)
newSetRow.highlight:Hide()
newSetRow:SetScript("OnEnter", function() newSetRow.highlight:Show() end)
newSetRow:SetScript("OnLeave", function() newSetRow.highlight:Hide() end)
newSetRow:SetScript("OnClick", function() OpenNamePopup("new") end)
local setView = CreateScrollBoxListLinearView(0, 0, 0, 2, 2)
setView:SetElementExtent(SET_ROW_HEIGHT)
setView:SetElementInitializer("Button", InitSetRow)
ScrollUtil.InitScrollBoxListWithScrollBar(listFrame.ScrollBox, listFrame.ScrollBar, setView)
local function MakeButton(name, label, parent, anchor, ax, ay, width)
local b = CreateFrame("Button", name, parent, "UIPanelButtonTemplate")
@@ -863,60 +849,21 @@ pfUI:RegisterModule("equipmentmanager", function()
selectedSetID = nil
end
-- Virtual list = sets ++ newSetRow. Clamp the current scroll
-- offset against the visible window before laying out rows so
-- deleting sets snaps the list back into view.
local totalItems = numSets + 1
local maxOffset = math.max(0, totalItems - LIST_VISIBLE_ROWS)
if listFrame.offset > maxOffset then listFrame.offset = maxOffset end
if listFrame.offset < 0 then listFrame.offset = 0 end
local off = listFrame.offset
-- Set rows: lazy-grow the pool to numSets, then position visible
-- ones into slots and hide the rest. Each row stays bound to a
-- specific set index (row[i] always shows ids[i]).
for i = 1, numSets do
if not setRows[i] then setRows[i] = CreateSetRow() end
local row = setRows[i]
local slot = i - off
if slot >= 1 and slot <= LIST_VISIBLE_ROWS then
local setID = ids[i]
local name, icon, _, isEquipped, _, _, _, numMissing = C_EquipmentSet.GetEquipmentSetInfo(setID)
row.setID = setID
-- Color precedence: missing items (red) > equipped (green) > normal (white).
local color = (numMissing and numMissing > 0) and "|cffff5555"
or isEquipped and "|cff33ff33" or "|cffffffff"
row.text:SetText(color .. (name or "?") .. "|r")
if icon then
local full = string.find(icon, "\\") and icon or ("Interface\\Icons\\" .. icon)
row.icon:SetTexture(full)
else
row.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
end
if setID == selectedSetID then row.highlight:Show() else row.highlight:Hide() end
row:ClearAllPoints()
row:SetPoint("TOPLEFT", listFrame, "TOPLEFT", 5, -3 - (slot - 1) * LIST_ROW_STRIDE)
row:Show()
else
row:Hide()
row.setID = nil
-- The rows are the sets, then the "New Set" entry. They are rebuilt
-- only when the sets change; otherwise the shown rows refresh in
-- place, so the row under the cursor stays the same frame and a
-- double-click reaches it.
local setsKey = table.concat(ids, ",")
if setsKey ~= listFrame.setsKey then
listFrame.setsKey = setsKey
local entries = {}
for _, setID in ipairs(ids) do
table.insert(entries, { setID = setID })
end
end
-- Hide pool entries past the current set count (left over from a
-- previous Refresh with more sets — e.g. just deleted one).
for i = numSets + 1, table.getn(setRows) do
setRows[i]:Hide()
setRows[i].setID = nil
end
-- "+ New Set" row occupies virtual index numSets+1.
local newSlot = (numSets + 1) - off
if newSlot >= 1 and newSlot <= LIST_VISIBLE_ROWS then
newSetRow:ClearAllPoints()
newSetRow:SetPoint("TOPLEFT", listFrame, "TOPLEFT", 5, -3 - (newSlot - 1) * LIST_ROW_STRIDE)
newSetRow:Show()
table.insert(entries, { newSet = true })
listFrame.ScrollBox:SetDataProvider(CreateDataProvider(entries), ScrollBoxConstants.RetainScrollPosition)
else
newSetRow:Hide()
listFrame.ScrollBox:ReinitializeFrames()
end
-- Update the ignored-overlay textures attached to each paperdoll
@@ -1102,11 +1049,14 @@ pfUI:RegisterModule("equipmentmanager", function()
local UNUSED_COLS, UNUSED_ROWS = 7, 8
local UNUSED_SIZE, UNUSED_GAP = 30, 4
local UNUSED_STRIDE = UNUSED_SIZE + UNUSED_GAP
-- The grid's list template keeps 5px around the buttons and a 7px scroll
-- bar 2px right of them.
local UNUSED_GRID_W = UNUSED_COLS * (UNUSED_SIZE + UNUSED_GAP) - UNUSED_GAP + 2 + 7 + 10
local UNUSED_GRID_H = UNUSED_ROWS * (UNUSED_SIZE + UNUSED_GAP) - UNUSED_GAP + 10
local unusedPanel = CreateSubPanel("pfEqMgrUnusedFrame",
UNUSED_COLS * UNUSED_STRIDE + 24, frame:GetHeight(), T["Items Not In Any Set"])
unusedPanel.offset = 0 -- first visible row
UNUSED_GRID_W + 22, frame:GetHeight(), T["Items Not In Any Set"])
unusedPanel.info = unusedPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
unusedPanel.info:SetPoint("TOPLEFT", unusedPanel, "TOPLEFT", 14, -34)
@@ -1118,14 +1068,13 @@ pfUI:RegisterModule("equipmentmanager", function()
unusedPanel.showIgnored.label:SetPoint("RIGHT", unusedPanel.showIgnored, "LEFT", -4, 0)
unusedPanel.showIgnored.label:SetText(T["Show Ignored"])
local unusedGrid = CreateFrame("Frame", nil, unusedPanel)
unusedGrid:SetPoint("TOPLEFT", unusedPanel, "TOPLEFT", 12 + UNUSED_GAP/2, -54)
unusedGrid:SetSize(UNUSED_COLS * UNUSED_STRIDE, UNUSED_ROWS * UNUSED_STRIDE)
unusedGrid:EnableMouseWheel(true)
local unusedGrid = CreateFrame("Frame", nil, unusedPanel, "pfUIScrollBoxListTemplate")
unusedGrid:SetPoint("TOPLEFT", unusedPanel, "TOPLEFT", 11, -51)
unusedGrid:SetSize(UNUSED_GRID_W, UNUSED_GRID_H)
unusedPanel.empty = unusedPanel:CreateFontString(nil, "OVERLAY", "GameFontDisable")
unusedPanel.empty:SetPoint("CENTER", unusedGrid, "CENTER", 0, 0)
unusedPanel.empty:SetWidth(UNUSED_COLS * UNUSED_STRIDE - 10)
unusedPanel.empty:SetWidth(UNUSED_GRID_W - 20)
unusedPanel.empty:SetText(T["Every equippable item is part of a set."])
unusedPanel.hint = unusedPanel:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
@@ -1135,7 +1084,6 @@ pfUI:RegisterModule("equipmentmanager", function()
unusedPanel.hint:SetText(T["Shift-Click: Link Ctrl-Click: Preview\nRight-Click: Ignore / Unignore"])
local RefreshUnusedPanel -- forward decl
local unusedButtons = {}
-- Bag highlight: while the panel is open, items of the list glow in
-- pfUI's bag and bank frames and every other item is dimmed.
@@ -1203,12 +1151,8 @@ pfUI:RegisterModule("equipmentmanager", function()
local WHERE_TAG = { equipped = "|cff33ff33E|r", bags = "", bank = "|cff66aaffB|r" }
local WHERE_TEXT = { equipped = T["Equipped"], bags = T["In Bags"], bank = T["In Bank"] }
local function CreateUnusedButton(i)
local b = CreateFrame("Button", nil, unusedGrid)
b:SetSize(UNUSED_SIZE, UNUSED_SIZE)
local col = math.mod(i - 1, UNUSED_COLS)
local row = math.floor((i - 1) / UNUSED_COLS)
b:SetPoint("TOPLEFT", unusedGrid, "TOPLEFT", col * UNUSED_STRIDE + UNUSED_GAP/2, -row * UNUSED_STRIDE - UNUSED_GAP/2)
-- one-time setup of a pooled grid button
local function SetupUnusedButton(b)
CreateBackdrop(b)
b:RegisterForClicks("LeftButtonUp", "RightButtonUp")
@@ -1252,14 +1196,24 @@ pfUI:RegisterModule("equipmentmanager", function()
DressUpItemLink(e.link)
end
end)
return b
end
unusedGrid:SetScript("OnMouseWheel", function()
unusedPanel.offset = unusedPanel.offset - (arg1 or 0)
RefreshUnusedPanel()
end)
local function InitUnusedButton(b, e)
if not b.icon then SetupUnusedButton(b) end
b.entry = e
b.icon:SetTexture(e.icon or "Interface\\Icons\\INV_Misc_QuestionMark")
b.icon:SetDesaturated(e.ignored and true or false)
b.icon:SetAlpha(e.ignored and .5 or 1)
b.tag:SetText(WHERE_TAG[e.where] or "")
local r, g, bl = GetItemQualityColor(e.quality or 1)
b.backdrop:SetBackdropBorderColor(r, g, bl, 1)
end
local unusedView = CreateScrollBoxListGridView(UNUSED_COLS, 0, 0, 0, 2, UNUSED_GAP, UNUSED_GAP)
unusedView:SetElementSize(UNUSED_SIZE, UNUSED_SIZE)
unusedView:SetElementInitializer("Button", InitUnusedButton)
ScrollUtil.InitScrollBoxListWithScrollBar(unusedGrid.ScrollBox, unusedGrid.ScrollBar, unusedView)
function RefreshUnusedPanel()
local list, numIgnored = ScanUnusedItems(unusedPanel.showIgnored:GetChecked() and true or nil)
@@ -1267,33 +1221,7 @@ pfUI:RegisterModule("equipmentmanager", function()
local numShownIgnored = unusedPanel.showIgnored:GetChecked() and numIgnored or 0
unusedPanel.info:SetText(string.format(T["%d items, %d ignored"], total - numShownIgnored, numIgnored))
local totalRows = math.ceil(total / UNUSED_COLS)
local maxOffset = math.max(0, totalRows - UNUSED_ROWS)
if unusedPanel.offset > maxOffset then unusedPanel.offset = maxOffset end
if unusedPanel.offset < 0 then unusedPanel.offset = 0 end
local first = unusedPanel.offset * UNUSED_COLS
for i = 1, UNUSED_COLS * UNUSED_ROWS do
local e = list[first + i]
local b = unusedButtons[i]
if e then
if not b then
b = CreateUnusedButton(i)
unusedButtons[i] = b
end
b.entry = e
b.icon:SetTexture(e.icon or "Interface\\Icons\\INV_Misc_QuestionMark")
b.icon:SetDesaturated(e.ignored and true or false)
b.icon:SetAlpha(e.ignored and .5 or 1)
b.tag:SetText(WHERE_TAG[e.where] or "")
local r, g, bl = GetItemQualityColor(e.quality or 1)
if b.backdrop then b.backdrop:SetBackdropBorderColor(r, g, bl, 1) end
b:Show()
elseif b then
b.entry = nil
b:Hide()
end
end
unusedGrid.ScrollBox:SetDataProvider(CreateDataProvider(list), ScrollBoxConstants.RetainScrollPosition)
if total == 0 then unusedPanel.empty:Show() else unusedPanel.empty:Hide() end
@@ -1690,10 +1618,8 @@ pfUI:RegisterModule("equipmentmanager", function()
-- ============================================================
local TRIGGER_ROWS, TRIGGER_ROW_H = 5, 24
local TRIGGER_STRIDE = TRIGGER_ROW_H + 2
local triggerPanel = CreateSubPanel("pfEqMgrTriggerFrame", 310, 404, T["Automatic Set Switching"])
local selectedTriggerID = nil
triggerPanel.offset = 0
local cbAuto = CreateCheckbox(triggerPanel, T["Enable Automatic Set Switching"])
cbAuto:SetPoint("TOPLEFT", triggerPanel, "TOPLEFT", 12, -30)
@@ -1702,15 +1628,11 @@ pfUI:RegisterModule("equipmentmanager", function()
UpdateEngine()
end)
local triggerList = CreateFrame("Frame", nil, triggerPanel)
-- The template keeps 5px around the rows, which sit 2px apart.
local triggerList = CreateFrame("Frame", nil, triggerPanel, "pfUIScrollBoxListTemplate")
triggerList:SetPoint("TOPLEFT", triggerPanel, "TOPLEFT", 14, -56)
triggerList:SetSize(282, TRIGGER_ROWS * TRIGGER_STRIDE + 4)
triggerList:SetSize(282, TRIGGER_ROWS * (TRIGGER_ROW_H + 2) - 2 + 10)
CreateBackdrop(triggerList, nil, nil, .75)
triggerList:EnableMouseWheel(true)
triggerList:SetScript("OnMouseWheel", function()
triggerPanel.offset = triggerPanel.offset - (arg1 or 0)
RefreshTriggerPanel()
end)
triggerList.empty = triggerList:CreateFontString(nil, "OVERLAY", "GameFontDisable")
triggerList.empty:SetPoint("CENTER", triggerList, "CENTER", 0, 0)
@@ -1725,12 +1647,8 @@ pfUI:RegisterModule("equipmentmanager", function()
RefreshTriggerPanel()
end
local triggerRows = {}
for i = 1, TRIGGER_ROWS do
local row = CreateFrame("Button", nil, triggerList)
row:SetSize(272, TRIGGER_ROW_H)
row:SetPoint("TOPLEFT", triggerList, "TOPLEFT", 5, -3 - (i - 1) * TRIGGER_STRIDE)
-- one-time setup of a pooled trigger row
local function SetupTriggerRow(row)
row.highlight = row:CreateTexture(nil, "BACKGROUND")
row.highlight:SetAllPoints(row)
row.highlight:SetTexture(.3, .3, .3, .4)
@@ -1792,10 +1710,39 @@ pfUI:RegisterModule("equipmentmanager", function()
GameTooltip:Show()
end)
row:SetScript("OnLeave", function() GameTooltip:Hide() end)
triggerRows[i] = row
end
local function InitTriggerRow(row, entry)
if not row.check then SetupTriggerRow(row) end
local t, index = entry.trigger, entry.index
row.trigger = t
row.index = index
row.check:SetChecked(t.enabled)
local color = "|cffffffff"
if not t.enabled then
color = "|cff808080"
elseif not SetExists(t.setID) then
color = "|cffff5555"
elseif db.applied == t.id then
color = "|cff33ff33"
elseif ConditionActive(t) then
color = "|cffffd100"
end
local target = SetExists(t.setID) and SetName(t.setID) or T["No set selected"]
row.text:SetText(color .. DescribeTrigger(t) .. "|r |cffaaaaaa>|r " .. color .. target .. "|r")
row.highlight:SetShown(t.id == selectedTriggerID)
row.up:SetEnabled(index > 1)
row.down:SetEnabled(index < table.getn(db.triggers))
end
local triggerView = CreateScrollBoxListLinearView(0, 0, 0, 2, 2)
triggerView:SetElementExtent(TRIGGER_ROW_H)
triggerView:SetElementInitializer("Button", InitTriggerRow)
ScrollUtil.InitScrollBoxListWithScrollBar(triggerList.ScrollBox, triggerList.ScrollBar, triggerView)
local btnNewTrigger = CreateFrame("Button", nil, triggerPanel, "UIPanelButtonTemplate")
btnNewTrigger:SetSize(110, 22)
btnNewTrigger:SetPoint("TOPLEFT", triggerList, "BOTTOMLEFT", 0, -6)
@@ -1813,10 +1760,10 @@ pfUI:RegisterModule("equipmentmanager", function()
db.nextID = db.nextID + 1
table.insert(db.triggers, t)
selectedTriggerID = t.id
-- Scroll so the new trigger is visible.
triggerPanel.offset = math.max(0, table.getn(db.triggers) - TRIGGER_ROWS)
UpdateEngine()
RefreshTriggerPanel()
-- the new trigger is the last row
triggerList.ScrollBox:ScrollToEnd()
end)
-- Editor for the selected trigger
@@ -2016,43 +1963,12 @@ pfUI:RegisterModule("equipmentmanager", function()
local function RefreshTriggerRows()
cbAuto:SetChecked(C.equipmentmanager.autoswitch == "1")
local num = table.getn(db.triggers)
local maxOffset = math.max(0, num - TRIGGER_ROWS)
if triggerPanel.offset > maxOffset then triggerPanel.offset = maxOffset end
if triggerPanel.offset < 0 then triggerPanel.offset = 0 end
for i, row in ipairs(triggerRows) do
local index = i + triggerPanel.offset
local t = db.triggers[index]
if t then
row.trigger = t
row.index = index
row.check:SetChecked(t.enabled)
local color = "|cffffffff"
if not t.enabled then
color = "|cff808080"
elseif not SetExists(t.setID) then
color = "|cffff5555"
elseif db.applied == t.id then
color = "|cff33ff33"
elseif ConditionActive(t) then
color = "|cffffd100"
end
local target = SetExists(t.setID) and SetName(t.setID) or T["No set selected"]
row.text:SetText(color .. DescribeTrigger(t) .. "|r |cffaaaaaa>|r " .. color .. target .. "|r")
if t.id == selectedTriggerID then row.highlight:Show() else row.highlight:Hide() end
if index > 1 then row.up:Enable() else row.up:Disable() end
if index < num then row.down:Enable() else row.down:Disable() end
row:Show()
else
row.trigger = nil
row.index = nil
row:Hide()
end
local entries = {}
for index, t in ipairs(db.triggers) do
table.insert(entries, { trigger = t, index = index })
end
if num == 0 then triggerList.empty:Show() else triggerList.empty:Hide() end
triggerList.ScrollBox:SetDataProvider(CreateDataProvider(entries), ScrollBoxConstants.RetainScrollPosition)
triggerList.empty:SetShown(table.getn(entries) == 0)
end
function RefreshTriggerPanel()
+12 -13
View File
@@ -515,14 +515,15 @@ pfUI:RegisterModule("gui", function ()
-- are we a frame with contents?
if func then
f.scroll = CreateScrollFrame(nil, f)
f.scroll = CreateFrame("ScrollFrame", nil, f, "pfUIScrollFrameTemplate")
SetAllPointsOffset(f.scroll, f, 2)
f.scroll.content = CreateScrollChild(nil, f.scroll)
f.scroll.content = f.scroll.Content
f.scroll.content.parent = f.scroll
f.scroll.content:SetScript("OnShow", function()
if not this.setup then
func()
this.setup = true
this.parent:UpdateScrollChildRect()
end
end)
end
@@ -774,7 +775,10 @@ pfUI:RegisterModule("gui", function ()
end
end
if strlen(this:GetText()) < 1 then return end
if strlen(this:GetText()) < 1 then
parent:UpdateScrollChildRect()
return
end
local i = 1
local search = strlower(this:GetText())
@@ -798,16 +802,9 @@ pfUI:RegisterModule("gui", function ()
end
end
-- reload scroll frames
scroll:Hide()
scroll:SetHeight(i * 25 )
scroll:Show()
parent:SetScrollChild(scroll)
QueueFunction(function()
parent:SetVerticalScroll(0)
parent:UpdateScrollState()
parent:Scroll()
end)
-- measure the new results and start at the top
parent:UpdateScrollChildRect()
parent:SetVerticalScroll(0)
end)
pfUI.gui.search:SetScript("OnEditFocusGained", function(self)
@@ -2895,6 +2892,8 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Timestamp Format"], C.chat.text, "timeformat", nil, nil, nil, nil, "STRING")
CreateConfig(nil, T["Timestamp Brackets"], C.chat.text, "timebracket", nil, nil, nil, nil, "STRING")
CreateConfig(nil, T["Timestamp Color"], C.chat.text, "timecolor", "color")
-- read each time chat copy opens, so no reload
CreateConfig(function() end, T["Show Timestamps In Chat Copy"], C.chat.text, "copytime", "checkbox")
CreateConfig(nil, T["Hide Channel Names"], C.chat.text, "channelnumonly", "checkbox")
CreateConfig(nil, T["Generate Playerlinks"], C.chat.text, "playerlinks", "checkbox")
CreateConfig(nil, T["Enable URL Detection"], C.chat.text, "detecturl", "checkbox")
+61 -88
View File
@@ -1,9 +1,9 @@
pfUI:RegisterModule("loothistory", function ()
local rawborder, border = GetBorderSize()
-- Layout
local ITEM_H, PLAYER_H = 24, 18
local ITEM_W, PLAYER_W = 350, 330
-- Layout (rows are 2px apart)
local ITEM_H, PLAYER_H = 24, 16
local PLAYER_INDENT = 18
-- rollType constants returned by C_LootHistory.GetPlayerInfo (0/1/2; vanilla
-- has no disenchant roll).
@@ -86,30 +86,24 @@ pfUI:RegisterModule("loothistory", function ()
pfUI.loothistory.clear:SetText(T["Clear"])
pfUI.loothistory.clear:SetScript("OnClick", function() C_LootHistory.Clear() end)
-- scroll frame
pfUI.loothistory.scroll = CreateScrollFrame("pfLootHistoryScroll", pfUI.loothistory)
pfUI.loothistory.scroll:SetSize(360, 440)
pfUI.loothistory.scroll:SetPoint("BOTTOM", 0, 10)
pfUI.loothistory.scroll.backdrop = CreateFrame("Frame", nil, pfUI.loothistory.scroll)
pfUI.loothistory.scroll.backdrop:SetFrameLevel(1)
pfUI.loothistory.scroll.backdrop:SetPoint("TOPLEFT", pfUI.loothistory.scroll, "TOPLEFT", -5, 5)
pfUI.loothistory.scroll.backdrop:SetPoint("BOTTOMRIGHT", pfUI.loothistory.scroll, "BOTTOMRIGHT", 5, -5)
CreateBackdrop(pfUI.loothistory.scroll.backdrop, nil, true)
local list = CreateScrollChild("pfLootHistoryList", pfUI.loothistory.scroll)
-- ==========================================================================
-- List: a row per item and, under an expanded item, a row per player
-- ==========================================================================
local list = CreateFrame("Frame", "pfLootHistoryList", pfUI.loothistory, "pfUIScrollBoxListTemplate")
list:SetSize(370, 450)
list:SetPoint("BOTTOM", 0, 5)
CreateBackdrop(list, nil, true)
pfUI.loothistory.list = list
-- ==========================================================================
-- Frame pools
-- ==========================================================================
local itemFrames = {}
local FullUpdate -- forward declaration (toggle handlers call it)
local function CreateItemFrame()
local f = CreateFrame("Button", nil, list)
f:SetSize(ITEM_W, ITEM_H)
local function ToggleExpanded(f)
local id = f.rollID
if id then expanded[id] = not expanded[id]; FullUpdate() end
end
-- one-time setup of a pooled item row
local function SetupItemRow(f)
f:SetBackdrop(pfUI.backdrop_hover)
f:SetBackdropBorderColor(1, 1, 1, .04)
f:EnableMouse(1)
@@ -118,10 +112,7 @@ pfUI:RegisterModule("loothistory", function ()
f.toggle = CreateFrame("Button", nil, f)
f.toggle:SetSize(14, 14)
f.toggle:SetPoint("LEFT", 4, 0)
f.toggle:SetScript("OnClick", function()
local id = f.rollID
if id then expanded[id] = not expanded[id]; FullUpdate() end
end)
f.toggle:SetScript("OnClick", function() ToggleExpanded(f) end)
-- icon + quality-colored border
f.iconbg = CreateFrame("Frame", nil, f)
@@ -138,18 +129,18 @@ pfUI:RegisterModule("loothistory", function ()
f.winicon:SetSize(14, 14)
f.winicon:SetPoint("RIGHT", f, "RIGHT", -6, 0)
f.winroll = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.winroll = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
f.winroll:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.winroll:SetPoint("RIGHT", f.winicon, "LEFT", -2, 0)
f.winroll:SetTextColor(1, 1, 1, 1)
f.winname = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.winname = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
f.winname:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.winname:SetPoint("RIGHT", f.winroll, "LEFT", -4, 0)
f.winname:SetJustifyH("RIGHT")
-- item name (leaves room on the right for the winner block)
f.name = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.name = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
f.name:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.name:SetPoint("LEFT", f.iconbg, "RIGHT", 5, 0)
f.name:SetPoint("RIGHT", f, "RIGHT", -100, 0)
@@ -167,20 +158,13 @@ pfUI:RegisterModule("loothistory", function ()
this:SetBackdropBorderColor(1, 1, 1, .04)
GameTooltip:Hide()
end)
f:SetScript("OnClick", function()
local id = this.rollID
if id then expanded[id] = not expanded[id]; FullUpdate() end
end)
return f
f:SetScript("OnClick", function() ToggleExpanded(f) end)
end
local function CreatePlayerFrame()
local f = CreateFrame("Frame", nil, list)
f:SetSize(PLAYER_W, PLAYER_H)
-- one-time setup of a pooled player row
local function SetupPlayerRow(f)
-- name is indented to leave room for the winner checkmark on its left
f.name = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.name = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
f.name:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.name:SetPoint("LEFT", 20, 0)
f.name:SetJustifyH("LEFT")
@@ -189,7 +173,7 @@ pfUI:RegisterModule("loothistory", function ()
f.rollicon:SetSize(16, 16)
f.rollicon:SetPoint("RIGHT", -4, 0)
f.rolltext = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.rolltext = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
f.rolltext:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.rolltext:SetPoint("RIGHT", f.rollicon, "LEFT", -3, 0)
f.rolltext:SetTextColor(1, 1, 1, 1)
@@ -199,15 +183,8 @@ pfUI:RegisterModule("loothistory", function ()
f.winmark:SetSize(16, 16)
f.winmark:SetTexture(WINMARK)
f.winmark:SetPoint("RIGHT", f.name, "LEFT", -1, 0)
return f
end
local playerPool = CreateObjectPool(CreatePlayerFrame, function(_, pf)
pf:Hide()
pf:ClearAllPoints()
end)
local function SetToggleTexture(toggle, isExpanded)
if isExpanded then
toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up")
@@ -221,13 +198,13 @@ pfUI:RegisterModule("loothistory", function ()
-- ==========================================================================
-- Rendering
-- ==========================================================================
local function UpdateItemFrame(f, i)
local rollID, itemLink, numPlayers, isDone, winnerIdx = C_LootHistory.GetItem(i)
local function InitItemRow(f, row)
if not f.toggle then SetupItemRow(f) end
local i = row.item
local rollID, itemLink, _, isDone, winnerIdx = C_LootHistory.GetItem(i)
f.rollID = rollID
f.itemIdx = i
f.itemLink = itemLink
f.numPlayers = numPlayers or 0
f.isDone = isDone
local isExpanded = rollID and expanded[rollID]
SetToggleTexture(f.toggle, isExpanded)
@@ -279,7 +256,10 @@ pfUI:RegisterModule("loothistory", function ()
end
end
local function RenderPlayerFrame(pf, name, class, rollType, roll, isWinner)
local function InitPlayerRow(pf, row)
if not pf.name then SetupPlayerRow(pf) end
local name, class, rollType, roll, isWinner = C_LootHistory.GetPlayerInfo(row.item, row.player)
pf.name:SetText(name or UNKNOWN)
pf.name:SetTextColor(PFUI_CLASS_COLORS[class]:GetRGB())
@@ -289,6 +269,22 @@ pfUI:RegisterModule("loothistory", function ()
if isWinner then pf.winmark:Show() else pf.winmark:Hide() end
end
local view = CreateScrollBoxListLinearView(2, 2, 4, 4, 2)
view:SetElementFactory(function(factory, row)
if row.player then
factory("Frame", InitPlayerRow)
else
factory("Button", InitItemRow)
end
end)
view:SetElementExtentCalculator(function(_, row)
return row.player and PLAYER_H or ITEM_H
end)
view:SetElementIndentCalculator(function(row)
return row.player and PLAYER_INDENT or 0
end)
ScrollUtil.InitScrollBoxListWithScrollBar(list.ScrollBox, list.ScrollBar, view)
-- A player row is worth showing while the roll is undecided (see everyone),
-- or afterwards only if they actually rolled or it's you (hide the passers'
-- noise on a decided roll) — mirrors Blizzard's ShouldDisplayPlayer.
@@ -298,46 +294,23 @@ pfUI:RegisterModule("loothistory", function ()
function FullUpdate()
if not pfUI.loothistory:IsShown() then return end
playerPool:ReleaseAll()
local num = C_LootHistory.GetNumItems()
local y = -2
local rows = {}
for i = 1, C_LootHistory.GetNumItems() do
local rollID, _, numPlayers, isDone = C_LootHistory.GetItem(i)
table.insert(rows, { item = i })
for i = 1, num do
local f = itemFrames[i] or CreateItemFrame()
itemFrames[i] = f
UpdateItemFrame(f, i)
f:ClearAllPoints()
f:SetPoint("TOPLEFT", list, "TOPLEFT", 4, y)
f:Show()
y = y - ITEM_H - 2
if f.rollID and expanded[f.rollID] then
for p = 1, f.numPlayers do
local name, class, rollType, roll, isWinner, isMe = C_LootHistory.GetPlayerInfo(i, p)
if ShouldDisplayPlayer(f.isDone, roll, isMe) then
local pf = playerPool:Acquire()
RenderPlayerFrame(pf, name, class, rollType, roll, isWinner)
pf:ClearAllPoints()
pf:SetPoint("TOPLEFT", list, "TOPLEFT", 22, y)
pf:Show()
y = y - PLAYER_H
if rollID and expanded[rollID] then
for p = 1, numPlayers or 0 do
local _, _, _, roll, _, isMe = C_LootHistory.GetPlayerInfo(i, p)
if ShouldDisplayPlayer(isDone, roll, isMe) then
table.insert(rows, { item = i, player = p })
end
end
y = y - 2
end
end
for i = num + 1, table.getn(itemFrames) do
itemFrames[i]:Hide()
end
-- Resize the scroll child and re-attach it: SetHeight alone on a
-- SetAllPoints'd child doesn't make the ScrollFrame recompute its scroll
-- range, so a dynamically-grown list wouldn't scroll until a /reload.
list:SetHeight(math.max(1, -y + 2))
pfUI.loothistory.scroll:SetScrollChild(list)
pfUI.loothistory.scroll:UpdateScrollState()
list.ScrollBox:SetDataProvider(CreateDataProvider(rows), ScrollBoxConstants.RetainScrollPosition)
end
pfUI.loothistory:SetScript("OnShow", function() FullUpdate() end)
+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