---@type Diesal.GUI local DiesalGUI = LibStub("DiesalGUI-2.0") ---@type Diesal.Tools local DiesalTools = LibStub("DiesalTools-2.0") ---@type Diesal.Style local DiesalStyle = LibStub("DiesalStyle-2.0") -- ~~| Diesal Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Colors = DiesalStyle.Colors local HSL, ShadeColor, TintColor = DiesalTools.HSL, DiesalTools.ShadeColor, DiesalTools.TintColor -- ~~| Lua Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local type, select, pairs, tonumber = type, select, pairs, tonumber local setmetatable, getmetatable, next = setmetatable, getmetatable, next local sub, format, lower, upper = string.sub, string.format, string.lower, string.upper local floor, ceil, min, max, abs, modf = math.floor, math.ceil, math.min, math.max, math.abs, math.modf -- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local GetCursorPosition = GetCursorPosition -- ~~| ScrollFrame |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Type = "DiesalScrollFrame" local Version = 3 -- ~~| ScrollFrame Stylesheets |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local Stylesheet = { ["track-background"] = { type = "texture", layer = "BACKGROUND", color = "000000", alpha = 0.3, }, ["grip-background"] = { type = "texture", layer = "BACKGROUND", color = Colors.UI_400, }, ["grip-inline"] = { type = "outline", layer = "BORDER", color = "FFFFFF", alpha = 0.02, }, } local wireFrame = { ["frame-white"] = { type = "outline", layer = "OVERLAY", color = "ffffff", }, ["scrollFrameContainer-yellow"] = { type = "outline", layer = "OVERLAY", color = "ffff00", }, ["scrollFrame-orange"] = { type = "outline", layer = "OVERLAY", color = "ff7f00", }, ["scrollBar-blue"] = { type = "outline", layer = "OVERLAY", color = "0080ff", }, ["track-green"] = { type = "outline", layer = "OVERLAY", color = "00ff00", }, ["grip-purple"] = { type = "outline", layer = "OVERLAY", color = "a800ff", }, } -- ~~| ScrollFrame Locals |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local internal ---@class DiesalScrollFrame : Diesal.GUI.Object.ScrollFrame -- ~~| ScrollFrame Methods |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---@class Diesal.GUI.ScrollFrame.Methods local methods = { ["OnAcquire"] = function(self) self:ApplySettings() self:SetStylesheet(Stylesheet) --self:SetStylesheet(wireFrame) self:Show() end, ["OnRelease"] = function(self) end, ["ApplySettings"] = function(self) local settings = self.settings local scrollFrame = self.scrollFrame scrollFrame:SetPoint("TOPLEFT", settings.contentPadding[1], -settings.contentPadding[3]) scrollFrame:SetPoint("BOTTOMRIGHT", -settings.contentPadding[2], settings.contentPadding[4]) self.scrollBar:SetWidth(settings.scrollBarWidth) self.scrollBar:SetPoint("TOPRIGHT", -settings.scrollBarPadding[2], -settings.scrollBarPadding[3]) self.scrollBar:SetPoint("BOTTOMRIGHT", -settings.scrollBarPadding[2], settings.scrollBarPadding[4]) if settings.scrollBarButtons then self.track:SetPoint("TOP", 0, -settings.scrollBarButtonHeight) self.track:SetPoint("BOTTOM", 0, settings.scrollBarButtonHeight) self.buttonDown:SetHeight(settings.scrollBarButtonHeight) self.buttonUp:SetHeight(settings.scrollBarButtonHeight) self.buttonUp:Show() self.buttonDown:Show() else self.track:SetPoint("TOP", 0, 0) self.track:SetPoint("BOTTOM", 0, 0) self.buttonUp:Hide() self.buttonDown:Hide() end self.content:SetHeight(settings.contentHeight) end, ---@param height number ["SetContentHeight"] = function(self, height) height = height < 1 and 1 or height -- height of 0 wont hide scrollbar self.settings.contentHeight = height self.content:SetHeight(height) end, ["SetGripSize"] = function(self) local contentSize = self.scrollFrame:GetVerticalScrollRange() + self.scrollFrame:GetHeight() local windowSize = self.scrollFrame:GetHeight() local trackSize = self.track:GetHeight() local windowContentRatio = windowSize / contentSize local gripSize = DiesalTools.Round(trackSize * windowContentRatio) gripSize = max(gripSize, 10) -- might give this a setting? gripSize = min(gripSize, trackSize) self.grip:SetHeight(gripSize) end, ["SetScrollThumbPosition"] = function(self) local verticalScrollRange = self.scrollFrame:GetVerticalScrollRange() -- windowScrollAreaSize (rounded no need to round) if verticalScrollRange < 1 then self.grip:SetPoint("TOP", 0, 0) return end local verticalScroll = self.scrollFrame:GetVerticalScroll() -- windowPosition local trackSize = self.track:GetHeight() local gripSize = self.grip:GetHeight() local windowPositionRatio = verticalScroll / verticalScrollRange local trackScrollAreaSize = trackSize - gripSize local gripPositionOnTrack = DiesalTools.Round(trackScrollAreaSize * windowPositionRatio) self.grip:SetPoint("TOP", 0, -gripPositionOnTrack) end, ---@param show? boolean ["ShowScrollBar"] = function(self, show) if show then self.scrollFrameContainer:SetPoint("BOTTOMRIGHT", -(self.settings.scrollBarWidth + self.settings.scrollBarPadding[1] + self.settings.scrollBarPadding[2]), 0) self.scrollBar:Show() else self.scrollBar:Hide() self.scrollFrameContainer:SetPoint("BOTTOMRIGHT", 0, 0) end end, ["ScrollToBottom"] = function(self) local scrollRange = self.scrollFrame:GetVerticalScrollRange() if scrollRange > 0 and scrollRange ~= self.scrollFrame:GetVerticalScroll() then self.scrollFrame:SetVerticalScroll(scrollRange) end end, ---@param num number ["SetVerticalScroll"] = function(self, num) self.scrollFrame:SetVerticalScroll(num) end, ["GetVerticalScroll"] = function(self) return self.scrollFrame:GetVerticalScroll() end, ["GetVerticalScrollRange"] = function(self) return self.scrollFrame:GetVerticalScrollRange() end, ---@param num number ["VerticallyScroll"] = function(self, num) if num < 0 then self.scrollFrame:SetVerticalScroll(max(self.scrollFrame:GetVerticalScroll() + num, 0)) else self.scrollFrame:SetVerticalScroll(min(self.scrollFrame:GetVerticalScroll() + num, self.scrollFrame:GetVerticalScrollRange())) end end, } -- ~~| ScrollFrame Constructor |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ local function Constructor() ---@class Diesal.GUI.Object.ScrollFrame : Diesal.GUI.ObjectBase, Diesal.GUI.ScrollFrame.Methods ---@field scrollFrameContainer Frame ---@field scrollFrame ScrollFrame ---@field content Frame ---@field scrollBar Frame ---@field buttonUp Frame ---@field buttonDown Frame ---@field track Frame ---@field grip Frame ---@field parent Diesal.GUI.Object.Window local self = DiesalGUI:Create(Type, true) self.isContainer = true local frame = CreateFrame("Frame", nil, DiesalGUI.UIParent) self.frame = frame -- ~~ Default Settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ self.defaults = { height = 300, width = 500, scrollBarButtonHeight = 4, scrollBarWidth = 4, scrollBarButtons = false, scrollBarPadding = { 0, 0, 0, 0 }, contentPadding = { 0, 0, 0, 0 }, contentHeight = 1, } -- ~~ Events ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- OnAcquire, OnRelease, OnHeightSet, OnWidthSet -- OnHide -- ~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ frame:SetScript("OnHide", function(this) self:FireEvent("OnHide") end) local scrollFrameContainer = self:CreateRegion("Frame", "scrollFrameContainer", frame) scrollFrameContainer:SetAllPoints() local scrollFrame = self:CreateRegion("ScrollFrame", "scrollFrame", scrollFrameContainer) scrollFrame:EnableMouseWheel(true) scrollFrame:SetScript("OnMouseWheel", function(this, delta) DiesalGUI:OnMouse(this, "MouseWheel") if delta > 0 then self:VerticallyScroll(-25) else self:VerticallyScroll(25) end end) scrollFrame:SetScript("OnVerticalScroll", function(this, offset) -- self.scrollFrame:GetVerticalScrollRange() windowScrollAreaSize if this:GetVerticalScrollRange() < 1 then -- nothing to scroll self:ShowScrollBar(false) else self:ShowScrollBar(true) end self:SetScrollThumbPosition() end) scrollFrame:SetScript("OnScrollRangeChanged", function(this, horizontalScrollRange, verticalScrollRange) if verticalScrollRange < 1 then -- nothing to scroll this:SetVerticalScroll(0) self:ShowScrollBar(false) return end this:SetVerticalScroll(min(this:GetVerticalScroll(), verticalScrollRange)) self:ShowScrollBar(true) self:SetGripSize() self:SetScrollThumbPosition() end) scrollFrame:SetScript("OnSizeChanged", function(this, width, height) self.content:SetWidth(width) end) scrollFrame:SetScrollChild(self:CreateRegion("Frame", "content", scrollFrame)) scrollFrame:RegisterForDrag("LeftButton") scrollFrame:SetScript("OnDragStart", function(this, ...) self:FireEvent("OnDragStart", ...) end) local scrollBar = self:CreateRegion("Frame", "scrollBar", frame) scrollBar:Hide() local buttonUp = self:CreateRegion("Frame", "buttonUp", scrollBar) buttonUp:SetPoint("TOPLEFT") buttonUp:SetPoint("TOPRIGHT") local buttonDown = self:CreateRegion("Frame", "buttonDown", scrollBar) buttonDown:SetPoint("BOTTOMLEFT") buttonDown:SetPoint("BOTTOMRIGHT") local track = self:CreateRegion("Frame", "track", scrollBar) track:SetPoint("LEFT") track:SetPoint("RIGHT") local grip = self:CreateRegion("Frame", "grip", track) grip:SetPoint("LEFT") grip:SetPoint("RIGHT") grip:SetPoint("TOP") grip:EnableMouse(true) grip:SetScript("OnMouseDown", function(this, button) DiesalGUI:OnMouse(this, button) if button ~= "LeftButton" then return end local MouseY = select(2, GetCursorPosition()) / this:GetEffectiveScale() local effectiveScale = this:GetEffectiveScale() local trackScrollAreaSize = track:GetHeight() - this:GetHeight() local gripPositionOnTrack = abs(select(5, this:GetPoint(1))) this:SetScript("OnUpdate", function(this) local newGripPosition = gripPositionOnTrack + (MouseY - (select(2, GetCursorPosition()) / effectiveScale)) newGripPosition = min(max(newGripPosition, 0), trackScrollAreaSize) -- local newGripPositionRatio = newGripPosition / trackScrollAreaSize -- local windowPosition = newGripPositionRatio * scrollArea:GetVerticalScrollRange() scrollFrame:SetVerticalScroll((newGripPosition / trackScrollAreaSize) * scrollFrame:GetVerticalScrollRange()) end) end) grip:SetScript("OnMouseUp", function(this, button) this:SetScript("OnUpdate", function(this) end) end) -- ~~ Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ self:SetMethods(methods) --[[ for method, func in pairs(methods) do self[method] = func end ]] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ return self end DiesalGUI:RegisterObjectConstructor(Type, Constructor, Version)