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.
DiesalLibs/DiesalGUI-2.0/Objects/ScrollingEditBox.lua

312 lines
13 KiB

---@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
-- ~~| ScrollingEditBox |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local Type = "DiesalScrollingEditBox"
local Version = 3
-- ~~| ScrollingEditBox 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 = "BACKGROUND",
color = "fffc00",
},
["scrollFrame-orange"] = {
type = "outline",
layer = "BORDER",
color = "ffd400",
},
["editBox-red"] = {
type = "outline",
layer = "ARTWORK",
color = "ff0000",
aplha = 0.5,
},
["scrollBar-blue"] = {
type = "outline",
layer = "OVERLAY",
color = "00aaff",
},
["track-green"] = {
type = "outline",
layer = "OVERLAY",
color = "55ff00",
},
}
-- ~~| ScrollingEditBox Locals |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~| ScrollingEditBox Methods |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---@class Diesal.GUI.ScrollingEditBox.Methods
local methods = {
["OnAcquire"] = function(self)
self:ApplySettings()
self:SetStylesheet(Stylesheet)
-- self:SetStylesheet(wireFrame)
self:Show()
end,
["OnRelease"] = function(self) end,
---@param self Diesal.GUI.Object.ScrollingEditBox
["ApplySettings"] = function(self)
local settings = self.settings
self.scrollFrame:SetPoint("TOPLEFT", settings.contentPadding[1], -settings.contentPadding[3])
self.scrollFrame:SetPoint("BOTTOMRIGHT", -settings.contentPadding[2], settings.contentPadding[4])
self.scrollBar:SetPoint("TOPRIGHT", 0, -settings.contentPadding[3] + 1)
self.scrollBar:SetPoint("BOTTOMRIGHT", 0, settings.contentPadding[4] - 1)
self.scrollBar:SetWidth(settings.scrollBarWidth)
self.buttonDown:SetHeight(settings.scrollBarButtonHeight)
self.buttonUp:SetHeight(settings.scrollBarButtonHeight)
self.editBox:SetJustifyH(settings.justifyH)
self.editBox:SetJustifyV(settings.justifyV)
end,
["ShowScrollBar"] = function(self, show)
if show then
self.scrollFrameContainer:SetPoint("BOTTOMRIGHT", -(self.settings.scrollBarWidth + 1), 0)
self.scrollBar:Show()
else
self.scrollBar:Hide()
self.scrollFrameContainer:SetPoint("BOTTOMRIGHT", 0, 0)
end
end,
["SetContentHeight"] = function(self, height)
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,
["SetVerticalScroll"] = function(self, scroll) -- user scrolled only
self.settings.forceScrollBottom = DiesalTools.Round(scroll) ==
DiesalTools.Round(self.scrollFrame:GetVerticalScrollRange())
self.scrollFrame:SetVerticalScroll(scroll)
end,
["SetText"] = function(self, txt)
self.settings.text = txt
self.value = txt
self.editBox:SetText(txt or "")
end,
}
---@class DiesalScrollingEditBox : Diesal.GUI.Object.ScrollingEditBox
---@class Diesal.GUI.Object.ScrollingEditBox.Settings : Diesal.GUI.Object.ScrollingEditBox.Defaults
---@field justifyH JustifyHorizontal
---@field justifyV JustifyVertical
---@field contentHeight? number
---@field text? string
-- ~~| ScrollingEditBox Constructor |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local function Constructor()
---@class Diesal.GUI.Object.ScrollingEditBox : Diesal.GUI.ObjectBase, Diesal.GUI.ScrollingEditBox.Methods
---@field scrollFrameContainer Frame
---@field scrollFrame ScrollFrame
---@field editBox EditBox
---@field scrollBar Frame
---@field buttonUp Frame
---@field buttonDown Frame
---@field track Frame
---@field grip Frame
---@field settings Diesal.GUI.Object.ScrollingEditBox.Settings
local self = DiesalGUI:Create(Type, true)
local frame = CreateFrame("Frame", nil, DiesalGUI.UIParent)
self.frame = frame
-- ~~ Default Settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---@class Diesal.GUI.Object.ScrollingEditBox.Defaults
self.defaults = {
scrollBarButtonHeight = 1,
scrollBarWidth = 4,
contentPadding = { 0, 0, 0, 0 },
justifyH = "LEFT",
justifyV = "TOP",
forceScrollBottom = true,
}
-- ~~ 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:SetVerticalScroll(max(this:GetVerticalScroll() - 50, 0))
else
self:SetVerticalScroll(min(this:GetVerticalScroll() + 50, this:GetVerticalScrollRange()))
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, xOffset, verticalScrollRange)
if verticalScrollRange < 1 then -- nothing to scroll
this:SetVerticalScroll(0)
self:ShowScrollBar(false)
return
end
if self.settings.forceScrollBottom then
this:SetVerticalScroll(verticalScrollRange)
else
this:SetVerticalScroll(min(this:GetVerticalScroll(), verticalScrollRange))
end
self:ShowScrollBar(true)
self:SetGripSize()
self:SetScrollThumbPosition()
end)
scrollFrame:SetScript("OnSizeChanged", function(this, width, height)
self.editBox:SetWidth(width)
end)
local editBox = self:CreateRegion("EditBox", "editBox", scrollFrame)
editBox:SetPoint("TOPLEFT")
editBox:SetPoint("TOPRIGHT")
editBox:SetAutoFocus(false)
editBox:SetMultiLine(true)
editBox:HookScript("OnEditFocusLost", function(this)
this:HighlightText(0, 0)
this:SetText(self.settings.text)
end)
editBox:HookScript("OnEditFocusGained", function(this)
self:FireEvent("OnEditFocusGained")
end)
editBox:HookScript("OnEscapePressed", function(this)
self:FireEvent("OnEscapePressed")
end)
editBox:HookScript("OnTabPressed", function(this)
self:FireEvent("OnTabPressed")
end)
editBox:HookScript("OnCursorChanged", function(this, ...)
self:FireEvent("OnCursorChanged", ...)
end)
editBox:HookScript("OnTextChanged", function(this)
self:FireEvent("OnTextChanged")
end)
scrollFrame:SetScrollChild(editBox)
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")
track:SetPoint("TOP", buttonUp, "BOTTOM", 0, 0)
track:SetPoint("BOTTOM", buttonDown, "TOP", 0, 0)
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()
self:SetVerticalScroll((newGripPosition / trackScrollAreaSize) * scrollFrame:GetVerticalScrollRange())
end)
end)
grip:SetScript("OnMouseUp", function(this, button)
this:SetScript("OnUpdate", function(this) end)
end)
-- ~~ Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
self:SetMethods(methods)
self:SetObj(self.frame)
--[[ for method, func in pairs(methods) do
self[method] = func
end ]]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
return self
end
DiesalGUI:RegisterObjectConstructor(Type, Constructor, Version)