You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
8.7 KiB

local Type, Version = "WITScrollFrame", 24
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, abs = math.min, math.max, math.floor, math.abs
-- 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 VScrollbar_OnScrollValueChanged(frame, value)
frame.obj:SetScroll(value, frame.obj.hScrollbar:GetValue())
end
local function HScrollbar_OnScrollValueChanged(frame, value)
frame.obj:SetScroll(frame.obj.vScrollbar:GetValue(), value)
end
--[[-----------------------------------------------------------------------------
Methods
-------------------------------------------------------------------------------]]
local methods = {
["OnAcquire"] = function(self)
self:SetScroll(0, 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.vScrollbar:Hide()
self.vScrollbarShown = nil
self.hScrollbar:Hide()
self.hScrollbarShown = nil
self.content.height, self.content.width = nil, nil
end,
["SetScroll"] = function(self, vvalue, hvalue)
local status = self.status or self.localstatus
local viewheight = self.scrollframe:GetHeight()
local viewwidth = self.scrollframe:GetWidth()
local height = self.content:GetHeight()
local width = self.content:GetWidth()
local voffset, hoffset
if viewheight > height then
voffset = 0
else
voffset = floor((height - viewheight) / 1000.0 * vvalue)
end
if viewwidth > width then
hoffset = 0
else
hoffset = floor((width - viewwidth) / 1000.0 * hvalue)
end
self.content:ClearAllPoints()
self.content:SetPoint("TOPLEFT", -hoffset, voffset)
--self.content:SetPoint("TOPRIGHT", -hoffset, voffset)
status.voffset = voffset
status.hoffset = hoffset
status.vscrollvalue = vvalue
status.hscrollvalue = hvalue
end,
["MoveScroll"] = function(self, value)
local status = self.status or self.localstatus
local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
if self.vScrollbarShown then
local diff = height - viewheight
local delta = 1
if value < 0 then
delta = -1
end
self.vScrollbar:SetValue(min(max(status.vscrollvalue + 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 width, viewwidth = self.scrollframe:GetWidth(), self.content:GetWidth()
local voffset = status.voffset or 0
local hoffset = status.hoffset or 0
local curvaluev = self.vScrollbar:GetValue()
local curvalueh = self.hScrollbar:GetValue()
local showVScrollbar = false
local showHScrollbar = false
local refreshLayout = false
if viewheight >= height + ((viewwidth >= width + 2) and not self.hScrollbarShown and 22 or 2) then
showVScrollbar = true
end
if viewwidth >= width + (showVScrollbar and not self.vScrollbarShown and 22 or 2) then
showHScrollbar = true
end
if (self.vScrollbarShown ~= showVScrollbar) or (self.hScrollbarShown ~= showHScrollbar) then
self.vScrollbarShown = showVScrollbar
self.vScrollbar:SetShown(showVScrollbar)
if not showVScrollbar then
self.vScrollbar:SetValue(0)
end
self.hScrollbarShown = showHScrollbar
self.hScrollbar:SetShown(showHScrollbar)
if not showHScrollbar then
self.hScrollbar:SetValue(0)
end
self.scrollframe:SetPoint("BOTTOMRIGHT", showVScrollbar and -20 or 0, showHScrollbar and 20 or 0)
self:DoLayout()
end
if showVScrollbar or showHScrollbar then
local vvalue = 0
local hvalue = 0
if showVScrollbar then
vvalue = (voffset / (viewheight - height) * 1000)
if vvalue > 1000 then vvalue = 1000 end
end
if showHScrollbar then
hvalue = (hoffset / (viewwidth - width) * 1000)
if hvalue > 1000 then hvalue = 1000 end
end
self.vScrollbar:SetValue(vvalue)
self.hScrollbar:SetValue(hvalue)
self:SetScroll(vvalue, hvalue)
end
self.updateLock = nil
end,
["LayoutFinished"] = function(self, width, height)
self.content:SetWidth(width or 0 + 20)
self.content:SetHeight(height or 0 + 20)
self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
end,
["SetStatusTable"] = function(self, status)
assert(type(status) == "table")
self.status = status
status.vscrollvalue = status.vscrollvalue or 0
status.hscrollvalue = status.hscrollvalue or 0
end,
["OnWidthSet"] = function(self, width)
local content = self.content
content.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 vScrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dVScrollbar"):format(num), scrollframe)
vScrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, 0)
vScrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 0)
vScrollbar:SetMinMaxValues(0, 1000)
vScrollbar:SetValueStep(1)
vScrollbar:SetValue(0)
vScrollbar:SetWidth(16)
vScrollbar:Hide()
-- set the script as the last step, so it doesn't fire yet
vScrollbar:SetScript("OnValueChanged", VScrollbar_OnScrollValueChanged)
local scrollbgtv = vScrollbar:CreateTexture(nil, "BACKGROUND")
scrollbgtv:SetTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
vScrollbar:SetThumbTexture(scrollbgtv)
local scrollbg = vScrollbar:CreateTexture(nil, "BACKGROUND")
scrollbg:SetAllPoints(vScrollbar)
scrollbg:SetColorTexture(0, 0, 0, 0.4)
local hScrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dHScrollbar"):format(num), scrollframe)
hScrollbar:SetOrientation('HORIZONTAL')
hScrollbar:SetPoint("TOPLEFT", scrollframe, "BOTTOMLEFT", 0, -4)
hScrollbar:SetPoint("TOPRIGHT", scrollframe, "BOTTOMRIGHT", 0, -4)
hScrollbar:SetMinMaxValues(0, 1000)
hScrollbar:SetValueStep(1)
hScrollbar:SetValue(0)
hScrollbar:SetHeight(16)
hScrollbar:Hide()
-- set the script as the last step, so it doesn't fire yet
hScrollbar:SetScript("OnValueChanged", HScrollbar_OnScrollValueChanged)
local scrollbgth = hScrollbar:CreateTexture(nil, "BACKGROUND")
scrollbgth:SetTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
hScrollbar:SetThumbTexture(scrollbgth)
local scrollbgh = hScrollbar:CreateTexture(nil, "BACKGROUND")
scrollbgh:SetAllPoints(hScrollbar)
scrollbgh:SetColorTexture(0, 0, 0, 0.4)
--Container Support
local content = CreateFrame("Frame", nil, scrollframe)
content:SetPoint("TOPLEFT")
content:SetWidth(100)
content:SetHeight(400)
scrollframe:SetScrollChild(content)
local widget = {
localstatus = { vscrollvalue = 0, hscrollvalue = 0 },
scrollframe = scrollframe,
vScrollbar = vScrollbar,
hScrollbar = hScrollbar,
content = content,
frame = frame,
type = Type
}
for method, func in pairs(methods) do
widget[method] = func
end
scrollframe.obj, vScrollbar.obj, hScrollbar.obj = widget, widget, widget
return AceGUI:RegisterAsContainer(widget)
end
AceGUI:RegisterWidgetType(Type, Constructor, Version)