489 lines
13 KiB
Lua
489 lines
13 KiB
Lua
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
|