Tercio@23: --[[----------------------------------------------------------------------------- Tercio@23: ScrollFrame Container Tercio@23: Plain container that scrolls its content and doesn't grow in height. Tercio@23: -------------------------------------------------------------------------------]] Tercio@23: local Type, Version = "ScrollFrame", 23 Tercio@23: local AceGUI = LibStub and LibStub("AceGUI-3.0", true) Tercio@23: if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end Tercio@23: Tercio@23: -- Lua APIs Tercio@23: local pairs, assert, type = pairs, assert, type Tercio@23: local min, max, floor, abs = math.min, math.max, math.floor, math.abs Tercio@23: Tercio@23: -- WoW APIs Tercio@23: local CreateFrame, UIParent = CreateFrame, UIParent Tercio@23: Tercio@23: --[[----------------------------------------------------------------------------- Tercio@23: Support functions Tercio@23: -------------------------------------------------------------------------------]] Tercio@23: local function FixScrollOnUpdate(frame) Tercio@23: frame:SetScript("OnUpdate", nil) Tercio@23: frame.obj:FixScroll() Tercio@23: end Tercio@23: Tercio@23: --[[----------------------------------------------------------------------------- Tercio@23: Scripts Tercio@23: -------------------------------------------------------------------------------]] Tercio@23: local function ScrollFrame_OnMouseWheel(frame, value) Tercio@23: frame.obj:MoveScroll(value) Tercio@23: end Tercio@23: Tercio@23: local function ScrollFrame_OnSizeChanged(frame) Tercio@23: frame:SetScript("OnUpdate", FixScrollOnUpdate) Tercio@23: end Tercio@23: Tercio@23: local function ScrollBar_OnScrollValueChanged(frame, value) Tercio@23: frame.obj:SetScroll(value) Tercio@23: end Tercio@23: Tercio@23: --[[----------------------------------------------------------------------------- Tercio@23: Methods Tercio@23: -------------------------------------------------------------------------------]] Tercio@23: local methods = { Tercio@23: ["OnAcquire"] = function(self) Tercio@23: self:SetScroll(0) Tercio@23: self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate) Tercio@23: end, Tercio@23: Tercio@23: ["OnRelease"] = function(self) Tercio@23: self.status = nil Tercio@23: for k in pairs(self.localstatus) do Tercio@23: self.localstatus[k] = nil Tercio@23: end Tercio@23: self.scrollframe:SetPoint("BOTTOMRIGHT") Tercio@23: self.scrollbar:Hide() Tercio@23: self.scrollBarShown = nil Tercio@23: self.content.height, self.content.width = nil, nil Tercio@23: end, Tercio@23: Tercio@23: ["SetScroll"] = function(self, value) Tercio@23: local status = self.status or self.localstatus Tercio@23: local viewheight = self.scrollframe:GetHeight() Tercio@23: local height = self.content:GetHeight() Tercio@23: local offset Tercio@23: Tercio@23: if viewheight > height then Tercio@23: offset = 0 Tercio@23: else Tercio@23: offset = floor((height - viewheight) / 1000.0 * value) Tercio@23: end Tercio@23: self.content:ClearAllPoints() Tercio@23: self.content:SetPoint("TOPLEFT", 0, offset) Tercio@23: self.content:SetPoint("TOPRIGHT", 0, offset) Tercio@23: status.offset = offset Tercio@23: status.scrollvalue = value Tercio@23: end, Tercio@23: Tercio@23: ["MoveScroll"] = function(self, value) Tercio@23: local status = self.status or self.localstatus Tercio@23: local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight() Tercio@23: Tercio@23: if self.scrollBarShown then Tercio@23: local diff = height - viewheight Tercio@23: local delta = 1 Tercio@23: if value < 0 then Tercio@23: delta = -1 Tercio@23: end Tercio@23: self.scrollbar:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000)) Tercio@23: end Tercio@23: end, Tercio@23: Tercio@23: ["FixScroll"] = function(self) Tercio@23: if self.updateLock then return end Tercio@23: self.updateLock = true Tercio@23: local status = self.status or self.localstatus Tercio@23: local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight() Tercio@23: local offset = status.offset or 0 Tercio@23: local curvalue = self.scrollbar:GetValue() Tercio@23: -- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys Tercio@23: -- No-one is going to miss 2 pixels at the bottom of the frame, anyhow! Tercio@23: if viewheight < height + 2 then Tercio@23: if self.scrollBarShown then Tercio@23: self.scrollBarShown = nil Tercio@23: self.scrollbar:Hide() Tercio@23: self.scrollbar:SetValue(0) Tercio@23: self.scrollframe:SetPoint("BOTTOMRIGHT") Tercio@23: self:DoLayout() Tercio@23: end Tercio@23: else Tercio@23: if not self.scrollBarShown then Tercio@23: self.scrollBarShown = true Tercio@23: self.scrollbar:Show() Tercio@23: self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0) Tercio@23: self:DoLayout() Tercio@23: end Tercio@23: local value = (offset / (viewheight - height) * 1000) Tercio@23: if value > 1000 then value = 1000 end Tercio@23: self.scrollbar:SetValue(value) Tercio@23: self:SetScroll(value) Tercio@23: if value < 1000 then Tercio@23: self.content:ClearAllPoints() Tercio@23: self.content:SetPoint("TOPLEFT", 0, offset) Tercio@23: self.content:SetPoint("TOPRIGHT", 0, offset) Tercio@23: status.offset = offset Tercio@23: end Tercio@23: end Tercio@23: self.updateLock = nil Tercio@23: end, Tercio@23: Tercio@23: ["LayoutFinished"] = function(self, width, height) Tercio@23: self.content:SetHeight(height or 0 + 20) Tercio@23: self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate) Tercio@23: end, Tercio@23: Tercio@23: ["SetStatusTable"] = function(self, status) Tercio@23: assert(type(status) == "table") Tercio@23: self.status = status Tercio@23: if not status.scrollvalue then Tercio@23: status.scrollvalue = 0 Tercio@23: end Tercio@23: end, Tercio@23: Tercio@23: ["OnWidthSet"] = function(self, width) Tercio@23: local content = self.content Tercio@23: content.width = width Tercio@23: end, Tercio@23: Tercio@23: ["OnHeightSet"] = function(self, height) Tercio@23: local content = self.content Tercio@23: content.height = height Tercio@23: end Tercio@23: } Tercio@23: --[[----------------------------------------------------------------------------- Tercio@23: Constructor Tercio@23: -------------------------------------------------------------------------------]] Tercio@23: local function Constructor() Tercio@23: local frame = CreateFrame("Frame", nil, UIParent) Tercio@23: local num = AceGUI:GetNextWidgetNum(Type) Tercio@23: Tercio@23: local scrollframe = CreateFrame("ScrollFrame", nil, frame) Tercio@23: scrollframe:SetPoint("TOPLEFT") Tercio@23: scrollframe:SetPoint("BOTTOMRIGHT") Tercio@23: scrollframe:EnableMouseWheel(true) Tercio@23: scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel) Tercio@23: scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged) Tercio@23: Tercio@23: local scrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dScrollBar"):format(num), scrollframe, "UIPanelScrollBarTemplate") Tercio@23: scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16) Tercio@23: scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16) Tercio@23: scrollbar:SetMinMaxValues(0, 1000) Tercio@23: scrollbar:SetValueStep(1) Tercio@23: scrollbar:SetValue(0) Tercio@23: scrollbar:SetWidth(16) Tercio@23: scrollbar:Hide() Tercio@23: -- set the script as the last step, so it doesn't fire yet Tercio@23: scrollbar:SetScript("OnValueChanged", ScrollBar_OnScrollValueChanged) Tercio@23: Tercio@23: local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND") Tercio@23: scrollbg:SetAllPoints(scrollbar) Tercio@23: scrollbg:SetTexture(0, 0, 0, 0.4) Tercio@23: Tercio@23: --Container Support Tercio@23: local content = CreateFrame("Frame", nil, scrollframe) Tercio@23: content:SetPoint("TOPLEFT") Tercio@23: content:SetPoint("TOPRIGHT") Tercio@23: content:SetHeight(400) Tercio@23: scrollframe:SetScrollChild(content) Tercio@23: Tercio@23: local widget = { Tercio@23: localstatus = { scrollvalue = 0 }, Tercio@23: scrollframe = scrollframe, Tercio@23: scrollbar = scrollbar, Tercio@23: content = content, Tercio@23: frame = frame, Tercio@23: type = Type Tercio@23: } Tercio@23: for method, func in pairs(methods) do Tercio@23: widget[method] = func Tercio@23: end Tercio@23: scrollframe.obj, scrollbar.obj = widget, widget Tercio@23: Tercio@23: return AceGUI:RegisterAsContainer(widget) Tercio@23: end Tercio@23: Tercio@23: AceGUI:RegisterWidgetType(Type, Constructor, Version)