038931fcfb
Match the layout convention used by every other multi-addon-shape fork in Exiles/ (Bagnon/, Kui_Nameplates/, ShadowedUnitFrames/, etc.) — the addon's own files live in a subfolder named after the addon, with only the repo-level README files at the root. All moves are pure git renames (history preserved). Toc references are relative to the toc location so nothing inside the addon changes.
216 lines
6.7 KiB
Lua
216 lines
6.7 KiB
Lua
--[[-----------------------------------------------------------------------------
|
|
ScrollFrame Container
|
|
Plain container that scrolls its content and doesn't grow in height.
|
|
-------------------------------------------------------------------------------]]
|
|
local Type, Version = "ScrollFrame", 26
|
|
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
|
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
|
|
|
-- Lua APIs
|
|
local pairs, assert, type = pairs, assert, type
|
|
local min, max, floor = math.min, math.max, math.floor
|
|
|
|
-- WoW APIs
|
|
local CreateFrame, UIParent = CreateFrame, UIParent
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Support functions
|
|
-------------------------------------------------------------------------------]]
|
|
local function FixScrollOnUpdate(frame)
|
|
frame:SetScript("OnUpdate", nil)
|
|
frame.obj:FixScroll()
|
|
end
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Scripts
|
|
-------------------------------------------------------------------------------]]
|
|
local function ScrollFrame_OnMouseWheel(frame, value)
|
|
frame.obj:MoveScroll(value)
|
|
end
|
|
|
|
local function ScrollFrame_OnSizeChanged(frame)
|
|
frame:SetScript("OnUpdate", FixScrollOnUpdate)
|
|
end
|
|
|
|
local function ScrollBar_OnScrollValueChanged(frame, value)
|
|
frame.obj:SetScroll(value)
|
|
end
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Methods
|
|
-------------------------------------------------------------------------------]]
|
|
local methods = {
|
|
["OnAcquire"] = function(self)
|
|
self:SetScroll(0)
|
|
self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
|
|
end,
|
|
|
|
["OnRelease"] = function(self)
|
|
self.status = nil
|
|
for k in pairs(self.localstatus) do
|
|
self.localstatus[k] = nil
|
|
end
|
|
self.scrollframe:SetPoint("BOTTOMRIGHT")
|
|
self.scrollbar:Hide()
|
|
self.scrollBarShown = nil
|
|
self.content.height, self.content.width, self.content.original_width = nil, nil, nil
|
|
end,
|
|
|
|
["SetScroll"] = function(self, value)
|
|
local status = self.status or self.localstatus
|
|
local viewheight = self.scrollframe:GetHeight()
|
|
local height = self.content:GetHeight()
|
|
local offset
|
|
|
|
if viewheight > height then
|
|
offset = 0
|
|
else
|
|
offset = floor((height - viewheight) / 1000.0 * value)
|
|
end
|
|
self.content:ClearAllPoints()
|
|
self.content:SetPoint("TOPLEFT", 0, offset)
|
|
self.content:SetPoint("TOPRIGHT", 0, offset)
|
|
status.offset = offset
|
|
status.scrollvalue = value
|
|
end,
|
|
|
|
["MoveScroll"] = function(self, value)
|
|
local status = self.status or self.localstatus
|
|
local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
|
|
|
|
if self.scrollBarShown then
|
|
local diff = height - viewheight
|
|
local delta = 1
|
|
if value < 0 then
|
|
delta = -1
|
|
end
|
|
self.scrollbar:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
|
|
end
|
|
end,
|
|
|
|
["FixScroll"] = function(self)
|
|
if self.updateLock then return end
|
|
self.updateLock = true
|
|
local status = self.status or self.localstatus
|
|
local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
|
|
local offset = status.offset or 0
|
|
-- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys
|
|
-- No-one is going to miss 2 pixels at the bottom of the frame, anyhow!
|
|
if viewheight < height + 2 then
|
|
if self.scrollBarShown then
|
|
self.scrollBarShown = nil
|
|
self.scrollbar:Hide()
|
|
self.scrollbar:SetValue(0)
|
|
self.scrollframe:SetPoint("BOTTOMRIGHT")
|
|
if self.content.original_width then
|
|
self.content.width = self.content.original_width
|
|
end
|
|
self:DoLayout()
|
|
end
|
|
else
|
|
if not self.scrollBarShown then
|
|
self.scrollBarShown = true
|
|
self.scrollbar:Show()
|
|
self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
|
|
if self.content.original_width then
|
|
self.content.width = self.content.original_width - 20
|
|
end
|
|
self:DoLayout()
|
|
end
|
|
local value = (offset / (viewheight - height) * 1000)
|
|
if value > 1000 then value = 1000 end
|
|
self.scrollbar:SetValue(value)
|
|
self:SetScroll(value)
|
|
if value < 1000 then
|
|
self.content:ClearAllPoints()
|
|
self.content:SetPoint("TOPLEFT", 0, offset)
|
|
self.content:SetPoint("TOPRIGHT", 0, offset)
|
|
status.offset = offset
|
|
end
|
|
end
|
|
self.updateLock = nil
|
|
end,
|
|
|
|
["LayoutFinished"] = function(self, width, height)
|
|
self.content:SetHeight(height or 0 + 20)
|
|
|
|
-- update the scrollframe
|
|
self:FixScroll()
|
|
|
|
-- schedule another update when everything has "settled"
|
|
self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
|
|
end,
|
|
|
|
["SetStatusTable"] = function(self, status)
|
|
assert(type(status) == "table")
|
|
self.status = status
|
|
if not status.scrollvalue then
|
|
status.scrollvalue = 0
|
|
end
|
|
end,
|
|
|
|
["OnWidthSet"] = function(self, width)
|
|
local content = self.content
|
|
content.width = width - (self.scrollBarShown and 20 or 0)
|
|
content.original_width = width
|
|
end,
|
|
|
|
["OnHeightSet"] = function(self, height)
|
|
local content = self.content
|
|
content.height = height
|
|
end
|
|
}
|
|
--[[-----------------------------------------------------------------------------
|
|
Constructor
|
|
-------------------------------------------------------------------------------]]
|
|
local function Constructor()
|
|
local frame = CreateFrame("Frame", nil, UIParent)
|
|
local num = AceGUI:GetNextWidgetNum(Type)
|
|
|
|
local scrollframe = CreateFrame("ScrollFrame", nil, frame)
|
|
scrollframe:SetPoint("TOPLEFT")
|
|
scrollframe:SetPoint("BOTTOMRIGHT")
|
|
scrollframe:EnableMouseWheel(true)
|
|
scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
|
|
scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
|
|
|
|
local scrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dScrollBar"):format(num), scrollframe, "UIPanelScrollBarTemplate")
|
|
scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
|
|
scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16)
|
|
scrollbar:SetMinMaxValues(0, 1000)
|
|
scrollbar:SetValueStep(1)
|
|
scrollbar:SetValue(0)
|
|
scrollbar:SetWidth(16)
|
|
scrollbar:Hide()
|
|
-- set the script as the last step, so it doesn't fire yet
|
|
scrollbar:SetScript("OnValueChanged", ScrollBar_OnScrollValueChanged)
|
|
|
|
local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
|
|
scrollbg:SetAllPoints(scrollbar)
|
|
scrollbg:SetColorTexture(0, 0, 0, 0.4)
|
|
|
|
--Container Support
|
|
local content = CreateFrame("Frame", nil, scrollframe)
|
|
content:SetPoint("TOPLEFT")
|
|
content:SetPoint("TOPRIGHT")
|
|
content:SetHeight(400)
|
|
scrollframe:SetScrollChild(content)
|
|
|
|
local widget = {
|
|
localstatus = { scrollvalue = 0 },
|
|
scrollframe = scrollframe,
|
|
scrollbar = scrollbar,
|
|
content = content,
|
|
frame = frame,
|
|
type = Type
|
|
}
|
|
for method, func in pairs(methods) do
|
|
widget[method] = func
|
|
end
|
|
scrollframe.obj, scrollbar.obj = widget, widget
|
|
|
|
return AceGUI:RegisterAsContainer(widget)
|
|
end
|
|
|
|
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|