initial commit
This commit is contained in:
488
Core/Movers.lua
Normal file
488
Core/Movers.lua
Normal file
@@ -0,0 +1,488 @@
|
||||
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
||||
local Sticky = E.Libs.SimpleSticky
|
||||
|
||||
local _G = _G
|
||||
local type, unpack, pairs, error, ipairs = type, unpack, pairs, error, ipairs
|
||||
local format, split, find, strupper = format, strsplit, strfind, strupper
|
||||
|
||||
local CreateFrame = CreateFrame
|
||||
local IsShiftKeyDown = IsShiftKeyDown
|
||||
local InCombatLockdown = InCombatLockdown
|
||||
local IsControlKeyDown = IsControlKeyDown
|
||||
local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
|
||||
local hooksecurefunc = hooksecurefunc
|
||||
|
||||
E.CreatedMovers = {}
|
||||
E.DisabledMovers = {}
|
||||
|
||||
local function SizeChanged(frame, width, height)
|
||||
if InCombatLockdown() then return end
|
||||
frame.mover:SetSize(width, height)
|
||||
end
|
||||
|
||||
local function WidthChanged(frame, width)
|
||||
if InCombatLockdown() then return end
|
||||
frame.mover:SetWidth(width)
|
||||
end
|
||||
|
||||
local function HeightChanged(frame, height)
|
||||
if InCombatLockdown() then return end
|
||||
frame.mover:SetHeight(height)
|
||||
end
|
||||
|
||||
local function GetPoint(obj)
|
||||
local point, anchor, secondaryPoint, x, y = obj:GetPoint()
|
||||
if not anchor then anchor = E.UIParent end
|
||||
|
||||
return format('%s,%s,%s,%d,%d', point, anchor:GetName(), secondaryPoint, x and E:Round(x) or 0, y and E:Round(y) or 0)
|
||||
end
|
||||
|
||||
local function GetSettingPoints(name)
|
||||
local db = E.db.movers and E.db.movers[name]
|
||||
if db then
|
||||
local delim = (find(db, '\031') and '\031') or ','
|
||||
return split(delim, db)
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateCoords(self)
|
||||
local mover = self.child
|
||||
local x, y, _, nudgePoint, nudgeInversePoint = E:CalculateMoverPoints(mover)
|
||||
local coordX, coordY = E:GetXYOffset(nudgeInversePoint, 1)
|
||||
local nudgeFrame = _G.ElvUIMoverNudgeWindow
|
||||
|
||||
nudgeFrame:ClearAllPoints()
|
||||
nudgeFrame:SetPoint(nudgePoint, mover, nudgeInversePoint, coordX, coordY)
|
||||
E:UpdateNudgeFrame(mover, x, y)
|
||||
end
|
||||
|
||||
function E:SetMoverPoints(name, parent)
|
||||
local holder = E.CreatedMovers[name]
|
||||
if not holder then return end
|
||||
|
||||
local point1, relativeTo1, relativePoint1, xOffset1, yOffset1 = unpack(holder.parentPoint)
|
||||
local point2, relativeTo2, relativePoint2, xOffset2, yOffset2 = GetSettingPoints(name)
|
||||
if not _G[relativeTo2] then -- fallback to the parents original point (on create) if the setting doesn't exist
|
||||
point2, relativeTo2, relativePoint2, xOffset2, yOffset2 = point1, relativeTo1, relativePoint1, xOffset1, yOffset1
|
||||
end
|
||||
|
||||
if point2 then
|
||||
holder.mover:ClearAllPoints()
|
||||
holder.mover:SetPoint(point2, relativeTo2, relativePoint2, xOffset2, yOffset2)
|
||||
end
|
||||
|
||||
if parent then
|
||||
parent:ClearAllPoints()
|
||||
parent:SetPoint(point1, parent.mover, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local isDragging = false
|
||||
local coordFrame = CreateFrame('Frame')
|
||||
coordFrame:SetScript('OnUpdate', UpdateCoords)
|
||||
coordFrame:Hide()
|
||||
|
||||
local function HandlePostDrag(self, event)
|
||||
if self.postdrag and type(self.postdrag) == 'function' then
|
||||
self.postdrag(self, E:GetScreenQuadrant(self))
|
||||
end
|
||||
|
||||
if event then
|
||||
self:UnregisterAllEvents()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnDragStart(self)
|
||||
if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
|
||||
|
||||
if _G.ElvUIGrid then
|
||||
E:UIFrameFadeIn(_G.ElvUIGrid, 0.75, _G.ElvUIGrid:GetAlpha(), 1)
|
||||
end
|
||||
|
||||
if E.db.general.stickyFrames then
|
||||
Sticky:StartMoving(self, E.snapBars, self.snapOffset, self.snapOffset, self.snapOffset, self.snapOffset)
|
||||
else
|
||||
self:StartMoving()
|
||||
end
|
||||
|
||||
coordFrame.child = self
|
||||
coordFrame:Show()
|
||||
isDragging = true
|
||||
end
|
||||
|
||||
local function OnDragStop(self)
|
||||
if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
|
||||
|
||||
if _G.ElvUIGrid and E.ConfigurationMode then
|
||||
E:UIFrameFadeOut(_G.ElvUIGrid, 0.75, _G.ElvUIGrid:GetAlpha(), 0.4)
|
||||
end
|
||||
|
||||
if E.db.general.stickyFrames then
|
||||
Sticky:StopMoving(self)
|
||||
else
|
||||
self:StopMovingOrSizing()
|
||||
end
|
||||
|
||||
local x2, y2, p2 = E:CalculateMoverPoints(self)
|
||||
self:ClearAllPoints()
|
||||
self:SetPoint(p2, E.UIParent, p2, x2, y2)
|
||||
|
||||
E:SaveMoverPosition(self.name)
|
||||
|
||||
coordFrame.child = nil
|
||||
coordFrame:Hide()
|
||||
isDragging = false
|
||||
|
||||
HandlePostDrag(self)
|
||||
|
||||
self:SetUserPlaced(false)
|
||||
end
|
||||
|
||||
local function OnEnter(self)
|
||||
if isDragging then return end
|
||||
|
||||
for _, frame in pairs(E.CreatedMovers) do
|
||||
local mover = frame.mover
|
||||
if mover:IsShown() and mover ~= self then
|
||||
E:UIFrameFadeOut(mover, 0.75, mover:GetAlpha(), 0.5)
|
||||
end
|
||||
end
|
||||
|
||||
E.AssignFrameToNudge(self)
|
||||
|
||||
coordFrame.child = self
|
||||
coordFrame:GetScript('OnUpdate')(coordFrame)
|
||||
|
||||
self.text:SetTextColor(1, 1, 1)
|
||||
end
|
||||
|
||||
local function OnLeave(self)
|
||||
if isDragging then return end
|
||||
|
||||
for _, frame in pairs(E.CreatedMovers) do
|
||||
local mover = frame.mover
|
||||
if mover:IsShown() and mover ~= self then
|
||||
E:UIFrameFadeIn(mover, 0.75, mover:GetAlpha(), 1)
|
||||
end
|
||||
end
|
||||
|
||||
self.text:SetTextColor(unpack(E.media.rgbvaluecolor))
|
||||
end
|
||||
|
||||
local function OnMouseUp(_, button)
|
||||
if button == 'LeftButton' and not isDragging then
|
||||
_G.ElvUIMoverNudgeWindow:SetShown(not _G.ElvUIMoverNudgeWindow:IsShown())
|
||||
end
|
||||
end
|
||||
|
||||
local function OnMouseDown(self, button)
|
||||
if isDragging then
|
||||
OnDragStop(self)
|
||||
elseif button == 'RightButton' then
|
||||
if IsControlKeyDown() and self.textString then
|
||||
E:ResetMovers(self.textString) --Allow resetting of anchor by Ctrl+RightClick
|
||||
elseif IsShiftKeyDown() then
|
||||
self:Hide() --Allow hiding a mover temporarily
|
||||
elseif self.configString then
|
||||
E:ToggleOptionsUI(self.configString) --OpenConfig
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function OnMouseWheel(_, delta)
|
||||
if IsShiftKeyDown() then
|
||||
E:NudgeMover(delta)
|
||||
else
|
||||
E:NudgeMover(nil, delta)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnShow(self, r, g, b)
|
||||
if not r then r, g, b = unpack(E.media.rgbvaluecolor) end
|
||||
|
||||
self.text:FontTemplate()
|
||||
self.text:SetTextColor(r, g, b)
|
||||
|
||||
self:SetBackdropBorderColor(r, g, b)
|
||||
self.forcedBorderColors = {r, g, b}
|
||||
end
|
||||
|
||||
local function UpdateColors()
|
||||
local r, g, b = unpack(E.media.rgbvaluecolor)
|
||||
for _, holder in pairs(E.CreatedMovers) do
|
||||
OnShow(holder.mover, r, g, b)
|
||||
end
|
||||
end
|
||||
E.valueColorUpdateFuncs[UpdateColors] = true
|
||||
|
||||
local function UpdateMover(name, parent, textString, overlay, snapOffset, postdrag, shouldDisable, configString, perferCorners, ignoreSizeChanged)
|
||||
if not (name and parent) then return end --If for some reason the parent isnt loaded yet, also require a name
|
||||
|
||||
local holder = E.CreatedMovers[name]
|
||||
if holder.Created then return end
|
||||
holder.Created = true
|
||||
|
||||
if overlay == nil then overlay = true end
|
||||
|
||||
local f = CreateFrame('Button', name, E.UIParent, 'BackdropTemplate')
|
||||
f:SetClampedToScreen(true)
|
||||
f:RegisterForDrag('LeftButton', 'RightButton')
|
||||
f:SetFrameLevel(parent:GetFrameLevel() + 1)
|
||||
f:SetFrameStrata(overlay and 'DIALOG' or 'BACKGROUND')
|
||||
f:EnableMouseWheel(true)
|
||||
f:SetMovable(true)
|
||||
f:SetTemplate('Transparent', nil, nil, true)
|
||||
f:SetSize(parent:GetSize())
|
||||
f:Hide()
|
||||
|
||||
local fs = f:CreateFontString(nil, 'OVERLAY')
|
||||
fs:FontTemplate()
|
||||
fs:SetPoint('CENTER')
|
||||
fs:SetText(textString or name)
|
||||
fs:SetJustifyH('CENTER')
|
||||
fs:SetTextColor(unpack(E.media.rgbvaluecolor))
|
||||
f:SetFontString(fs)
|
||||
|
||||
f.text = fs
|
||||
f.name = name
|
||||
f.parent = parent
|
||||
f.overlay = overlay
|
||||
f.postdrag = postdrag
|
||||
f.textString = textString or name
|
||||
f.snapOffset = snapOffset or -2
|
||||
f.shouldDisable = shouldDisable
|
||||
f.configString = configString
|
||||
f.perferCorners = perferCorners
|
||||
f.ignoreSizeChanged = ignoreSizeChanged
|
||||
|
||||
holder.mover = f
|
||||
parent.mover = f
|
||||
E.snapBars[#E.snapBars+1] = f
|
||||
|
||||
if not ignoreSizeChanged then
|
||||
hooksecurefunc(parent, 'SetSize', SizeChanged)
|
||||
hooksecurefunc(parent, 'SetWidth', WidthChanged)
|
||||
hooksecurefunc(parent, 'SetHeight', HeightChanged)
|
||||
end
|
||||
|
||||
E:SetMoverPoints(name, parent)
|
||||
|
||||
f:SetScript('OnDragStart', OnDragStart)
|
||||
f:SetScript('OnDragStop', OnDragStop)
|
||||
f:SetScript('OnEnter', OnEnter)
|
||||
f:SetScript('OnLeave', OnLeave)
|
||||
f:SetScript('OnMouseDown', OnMouseDown)
|
||||
f:SetScript('OnMouseUp', OnMouseUp)
|
||||
f:SetScript('OnMouseWheel', OnMouseWheel)
|
||||
f:SetScript('OnShow', OnShow)
|
||||
f:SetScript('OnEvent', HandlePostDrag)
|
||||
f:RegisterEvent('PLAYER_ENTERING_WORLD')
|
||||
end
|
||||
|
||||
function E:CalculateMoverPoints(mover, nudgeX, nudgeY)
|
||||
local centerX, centerY = E.UIParent:GetCenter()
|
||||
local width = E.UIParent:GetRight()
|
||||
local x, y = mover:GetCenter()
|
||||
|
||||
local point, nudgePoint, nudgeInversePoint = 'BOTTOM', 'BOTTOM', 'TOP'
|
||||
if y >= centerY then -- TOP: 1080p = 540
|
||||
point, nudgePoint, nudgeInversePoint = 'TOP', 'TOP', 'BOTTOM'
|
||||
y = -(E.UIParent:GetTop() - mover:GetTop())
|
||||
else
|
||||
y = mover:GetBottom()
|
||||
end
|
||||
|
||||
if x >= (width * 2 / 3) then -- RIGHT: 1080p = 1280
|
||||
point, nudgePoint, nudgeInversePoint = point..'RIGHT', 'RIGHT', 'LEFT'
|
||||
x = mover:GetRight() - width
|
||||
elseif x <= (width / 3) or mover.perferCorners then -- LEFT: 1080p = 640
|
||||
point, nudgePoint, nudgeInversePoint = point..'LEFT', 'LEFT', 'RIGHT'
|
||||
x = mover:GetLeft()
|
||||
else
|
||||
x = x - centerX
|
||||
end
|
||||
|
||||
--Update coordinates if nudged
|
||||
x = x + (nudgeX or 0)
|
||||
y = y + (nudgeY or 0)
|
||||
|
||||
return x, y, point, nudgePoint, nudgeInversePoint
|
||||
end
|
||||
|
||||
function E:HasMoverBeenMoved(name)
|
||||
return E.db.movers and E.db.movers[name]
|
||||
end
|
||||
|
||||
function E:SaveMoverPosition(name)
|
||||
local holder = E.CreatedMovers[name]
|
||||
if not holder then return end
|
||||
if not E.db.movers then E.db.movers = {} end
|
||||
E.db.movers[name] = GetPoint(holder.mover)
|
||||
end
|
||||
|
||||
function E:SetMoverSnapOffset(name, offset)
|
||||
local holder = E.CreatedMovers[name]
|
||||
if not holder then return end
|
||||
holder.mover.snapOffset = offset or -2
|
||||
holder.snapoffset = offset or -2
|
||||
end
|
||||
|
||||
function E:SetMoverLayoutPositionPoint(holder, name, parent)
|
||||
local layout = E.LayoutMoverPositions[E.db.layoutSetting]
|
||||
local layoutPoint = (layout and layout[name]) or E.LayoutMoverPositions.ALL[name]
|
||||
holder.layoutPoint = layoutPoint
|
||||
holder.point = layoutPoint or GetPoint(parent or holder.mover)
|
||||
|
||||
if parent then -- CreateMover call
|
||||
holder.parentPoint = {parent:GetPoint()}
|
||||
end
|
||||
end
|
||||
|
||||
function E:SaveMoverDefaultPosition(name)
|
||||
local holder = E.CreatedMovers[name]
|
||||
if not holder then return end
|
||||
|
||||
E:SetMoverLayoutPositionPoint(holder, name)
|
||||
|
||||
HandlePostDrag(holder.mover)
|
||||
end
|
||||
|
||||
function E:CreateMover(parent, name, textString, overlay, snapoffset, postdrag, types, shouldDisable, configString, perferCorners, ignoreSizeChanged)
|
||||
local holder = E.CreatedMovers[name]
|
||||
if holder == nil then
|
||||
holder = {}
|
||||
holder.types = {}
|
||||
|
||||
if types then
|
||||
for _, x in ipairs({split(',', types)}) do
|
||||
holder.types[x] = true
|
||||
end
|
||||
else
|
||||
holder.types.ALL = true
|
||||
holder.types.GENERAL = true
|
||||
end
|
||||
|
||||
E:SetMoverLayoutPositionPoint(holder, name, parent)
|
||||
E.CreatedMovers[name] = holder
|
||||
end
|
||||
|
||||
UpdateMover(name, parent, textString, overlay, snapoffset, postdrag, shouldDisable, configString, perferCorners, ignoreSizeChanged)
|
||||
end
|
||||
|
||||
function E:ToggleMovers(show, which)
|
||||
self.configMode = show
|
||||
|
||||
local upperText = strupper(which)
|
||||
for _, holder in pairs(E.CreatedMovers) do
|
||||
local isName = (holder.mover.name == which) or strupper(holder.mover.textString) == upperText
|
||||
if show and (isName or holder.types[upperText]) then
|
||||
holder.mover:Show()
|
||||
else
|
||||
holder.mover:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function E:GetMoverHolder(name)
|
||||
local created = self.CreatedMovers[name]
|
||||
local disabled = self.DisabledMovers[name]
|
||||
return created or disabled, not not disabled
|
||||
end
|
||||
|
||||
function E:DisableMover(name)
|
||||
if self.DisabledMovers[name] then return end
|
||||
|
||||
local holder = self.CreatedMovers[name]
|
||||
if not holder then
|
||||
error(format('mover %s doesnt exist', name or 'nil'))
|
||||
end
|
||||
|
||||
self.DisabledMovers[name] = {}
|
||||
for x, y in pairs(holder) do
|
||||
self.DisabledMovers[name][x] = y
|
||||
end
|
||||
|
||||
if self.configMode then
|
||||
holder.mover:Hide()
|
||||
end
|
||||
|
||||
self.CreatedMovers[name] = nil
|
||||
end
|
||||
|
||||
function E:EnableMover(name)
|
||||
if self.CreatedMovers[name] then return end
|
||||
|
||||
local holder = self.DisabledMovers[name]
|
||||
if not holder then
|
||||
error(format('mover %s doesnt exist', name or 'nil'))
|
||||
end
|
||||
|
||||
self.CreatedMovers[name] = {}
|
||||
for x, y in pairs(holder) do
|
||||
self.CreatedMovers[name][x] = y
|
||||
end
|
||||
|
||||
if self.configMode then
|
||||
holder.mover:Show()
|
||||
end
|
||||
|
||||
self.DisabledMovers[name] = nil
|
||||
end
|
||||
|
||||
function E:ResetMovers(arg)
|
||||
local all = not arg or arg == ''
|
||||
if all then self.db.movers = nil end
|
||||
|
||||
for name, holder in pairs(E.CreatedMovers) do
|
||||
if all or (holder.mover and holder.mover.textString == arg) then
|
||||
local point, anchor, secondaryPoint, x, y = split(',', holder.point)
|
||||
|
||||
local frame = holder.mover
|
||||
if point then
|
||||
frame:ClearAllPoints()
|
||||
frame:SetPoint(point, anchor, secondaryPoint, x, y)
|
||||
end
|
||||
|
||||
HandlePostDrag(frame)
|
||||
|
||||
if all then
|
||||
E:SaveMoverPosition(name)
|
||||
else
|
||||
if holder.layoutPoint then
|
||||
E:SaveMoverPosition(name)
|
||||
elseif self.db.movers then
|
||||
self.db.movers[name] = nil
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Profile Change
|
||||
function E:SetMoversPositions()
|
||||
--E:SetMoversPositions() is the first function called in E:StaggeredUpdateAll().
|
||||
--Because of that, we can allow ourselves to re-enable all disabled movers here,
|
||||
--as the subsequent updates to these elements will disable them again if needed.
|
||||
for name in pairs(E.DisabledMovers) do
|
||||
local disable = E.DisabledMovers[name].shouldDisable
|
||||
local shouldDisable = (disable and disable()) or false
|
||||
if not shouldDisable then E:EnableMover(name) end
|
||||
end
|
||||
|
||||
for name in pairs(E.CreatedMovers) do
|
||||
E:SetMoverPoints(name)
|
||||
end
|
||||
end
|
||||
|
||||
function E:SetMoversClampedToScreen(value)
|
||||
for _, holder in pairs(E.CreatedMovers) do
|
||||
holder.mover:SetClampedToScreen(value)
|
||||
end
|
||||
end
|
||||
|
||||
function E:LoadMovers()
|
||||
for n, t in pairs(E.CreatedMovers) do
|
||||
UpdateMover(n, t.parent, t.textString, t.overlay, t.snapoffset, t.postdrag, t.shouldDisable, t.configString, t.perferCorners, t.ignoreSizeChanged)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user