527 lines
14 KiB
Lua
527 lines
14 KiB
Lua
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
|
local Sticky = E.Libs.SimpleSticky
|
|
|
|
--Lua functions
|
|
local _G = _G
|
|
local type, unpack, pairs, error = type, unpack, pairs, error
|
|
local format, split, find = format, strsplit, strfind
|
|
--WoW API / Variables
|
|
local CreateFrame = CreateFrame
|
|
local InCombatLockdown = InCombatLockdown
|
|
local IsControlKeyDown = IsControlKeyDown
|
|
local IsShiftKeyDown = IsShiftKeyDown
|
|
local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
|
|
|
|
E.CreatedMovers = {}
|
|
E.DisabledMovers = {}
|
|
|
|
local function SizeChanged(frame)
|
|
if InCombatLockdown() then return end
|
|
|
|
if frame.dirtyWidth and frame.dirtyHeight then
|
|
frame.mover:Size(frame.dirtyWidth, frame.dirtyHeight)
|
|
else
|
|
frame.mover:Size(frame:GetSize())
|
|
end
|
|
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, E:Round(x), E:Round(y))
|
|
end
|
|
|
|
local function UpdateCoords(self)
|
|
local mover = self.child
|
|
local x, y, _, nudgePoint, nudgeInversePoint = E:CalculateMoverPoints(mover)
|
|
|
|
local coordX, coordY = E:GetXYOffset(nudgeInversePoint, 1)
|
|
ElvUIMoverNudgeWindow:ClearAllPoints()
|
|
ElvUIMoverNudgeWindow:Point(nudgePoint, mover, nudgeInversePoint, coordX, coordY)
|
|
E:UpdateNudgeFrame(mover, x, y)
|
|
end
|
|
|
|
local isDragging = false
|
|
local coordFrame = CreateFrame("Frame")
|
|
coordFrame:SetScript("OnUpdate", UpdateCoords)
|
|
coordFrame:Hide()
|
|
|
|
local function CreateMover(parent, name, text, overlay, snapOffset, postdrag, shouldDisable, configString)
|
|
if not parent then return end --If for some reason the parent isnt loaded yet
|
|
if E.CreatedMovers[name].Created then return end
|
|
|
|
if overlay == nil then overlay = true end
|
|
local point, anchor, secondaryPoint, x, y = split(",", GetPoint(parent))
|
|
|
|
--Use dirtyWidth / dirtyHeight to set initial size if possible
|
|
local width = parent.dirtyWidth or parent:GetWidth()
|
|
local height = parent.dirtyHeight or parent:GetHeight()
|
|
|
|
local f = CreateFrame("Button", name, E.UIParent)
|
|
f:SetClampedToScreen(true)
|
|
f:RegisterForDrag("LeftButton", "RightButton")
|
|
f:EnableMouseWheel(true)
|
|
f:SetMovable(true)
|
|
f:Width(width)
|
|
f:Height(height)
|
|
f:SetTemplate("Transparent", nil, nil, true)
|
|
f:Hide()
|
|
f.parent = parent
|
|
f.name = name
|
|
f.textString = text
|
|
f.postdrag = postdrag
|
|
f.overlay = overlay
|
|
f.snapOffset = snapOffset or -2
|
|
f.shouldDisable = shouldDisable
|
|
f.configString = configString
|
|
|
|
f:SetFrameLevel(parent:GetFrameLevel() + 1)
|
|
if overlay == true then
|
|
f:SetFrameStrata("DIALOG")
|
|
else
|
|
f:SetFrameStrata("BACKGROUND")
|
|
end
|
|
|
|
E.CreatedMovers[name].mover = f
|
|
E.snapBars[#E.snapBars + 1] = f
|
|
|
|
local fs = f:CreateFontString(nil, "OVERLAY")
|
|
fs:FontTemplate()
|
|
fs:SetJustifyH("CENTER")
|
|
fs:Point("CENTER")
|
|
fs:SetText(text or name)
|
|
fs:SetTextColor(unpack(E.media.rgbvaluecolor))
|
|
f:SetFontString(fs)
|
|
f.text = fs
|
|
|
|
if E.db.movers and E.db.movers[name] then
|
|
if type(E.db.movers[name]) == "table" then
|
|
f:Point(E.db.movers[name].p, E.UIParent, E.db.movers[name].p2, E.db.movers[name].p3, E.db.movers[name].p4)
|
|
E.db.movers[name] = GetPoint(f)
|
|
f:ClearAllPoints()
|
|
end
|
|
|
|
--Backward compatibility
|
|
local delim
|
|
local anchorString = E.db.movers[name]
|
|
if find(anchorString, "\031") then
|
|
delim = "\031"
|
|
elseif find(anchorString, ",") then
|
|
delim = ","
|
|
end
|
|
|
|
local point1, anchor1, secondaryPoint1, x1, y1 = split(delim, anchorString)
|
|
f:Point(point1, anchor1, secondaryPoint1, x1, y1)
|
|
f.anchor = anchor
|
|
else
|
|
f:Point(point, anchor, secondaryPoint, x, y)
|
|
end
|
|
|
|
local function OnDragStart(self)
|
|
if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
|
|
|
|
if E.db.general.stickyFrames then
|
|
Sticky:StartMoving(self, E.snapBars, f.snapOffset, f.snapOffset, f.snapOffset, f.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
|
|
isDragging = false
|
|
if E.db.general.stickyFrames then
|
|
Sticky:StopMoving(self)
|
|
else
|
|
self:StopMovingOrSizing()
|
|
end
|
|
|
|
local x2, y2, point2 = E:CalculateMoverPoints(self)
|
|
self:ClearAllPoints()
|
|
local overridePoint
|
|
if self.positionOverride then
|
|
if self.positionOverride == "BOTTOM" or self.positionOverride == "TOP" then
|
|
overridePoint = "BOTTOM"
|
|
else
|
|
overridePoint = "BOTTOMLEFT"
|
|
end
|
|
end
|
|
|
|
self:Point(self.positionOverride or point2, E.UIParent, overridePoint and overridePoint or point2, x2, y2)
|
|
if self.positionOverride then
|
|
self.parent:ClearAllPoints()
|
|
self.parent:Point(self.positionOverride, self, self.positionOverride)
|
|
end
|
|
|
|
E:SaveMoverPosition(name)
|
|
|
|
if ElvUIMoverNudgeWindow then
|
|
E:UpdateNudgeFrame(self, x, y)
|
|
end
|
|
|
|
coordFrame.child = nil
|
|
coordFrame:Hide()
|
|
|
|
if postdrag ~= nil and (type(postdrag) == "function") then
|
|
postdrag(self, E:GetScreenQuadrant(self))
|
|
end
|
|
|
|
self:SetUserPlaced(false)
|
|
end
|
|
|
|
local function OnEnter(self)
|
|
if isDragging then return end
|
|
|
|
self.text:SetTextColor(1, 1, 1)
|
|
E.AssignFrameToNudge(self)
|
|
coordFrame.child = self
|
|
coordFrame:GetScript("OnUpdate")(coordFrame)
|
|
end
|
|
|
|
local function OnMouseDown(self, button)
|
|
if button == "LeftButton" and not isDragging then
|
|
if ElvUIMoverNudgeWindow:IsShown() then
|
|
ElvUIMoverNudgeWindow:Hide()
|
|
else
|
|
ElvUIMoverNudgeWindow:Show()
|
|
end
|
|
elseif button == "RightButton" then
|
|
isDragging = false
|
|
if E.db.general.stickyFrames then
|
|
Sticky:StopMoving(self)
|
|
else
|
|
self:StopMovingOrSizing()
|
|
end
|
|
|
|
--Allow resetting of anchor by Ctrl+RightClick
|
|
if IsControlKeyDown() and self.textString then
|
|
E:ResetMovers(self.textString)
|
|
elseif IsShiftKeyDown() then --Allow hiding a mover temporarily
|
|
self:Hide()
|
|
elseif self.configString then --OpenConfig
|
|
E:ToggleOptionsUI(self.configString)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function OnLeave(self)
|
|
if isDragging then return end
|
|
self.text:SetTextColor(unpack(E.media.rgbvaluecolor))
|
|
end
|
|
|
|
local function OnShow(self)
|
|
self:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
|
|
end
|
|
|
|
local function OnMouseWheel(_, delta)
|
|
if IsShiftKeyDown() then
|
|
E:NudgeMover(delta)
|
|
else
|
|
E:NudgeMover(nil, delta)
|
|
end
|
|
end
|
|
|
|
f:SetScript("OnDragStart", OnDragStart)
|
|
f:SetScript("OnMouseUp", E.AssignFrameToNudge)
|
|
f:SetScript("OnDragStop", OnDragStop)
|
|
f:SetScript("OnEnter", OnEnter)
|
|
f:SetScript("OnMouseDown", OnMouseDown)
|
|
f:SetScript("OnLeave", OnLeave)
|
|
f:SetScript("OnShow", OnShow)
|
|
f:SetScript("OnMouseWheel", OnMouseWheel)
|
|
|
|
parent:SetScript("OnSizeChanged", SizeChanged)
|
|
parent.mover = f
|
|
|
|
parent:ClearAllPoints()
|
|
parent:Point(point, f, 0, 0)
|
|
|
|
if postdrag ~= nil and type(postdrag) == "function" then
|
|
f:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
f:SetScript("OnEvent", function(self)
|
|
postdrag(f, E:GetScreenQuadrant(f))
|
|
self:UnregisterAllEvents()
|
|
end)
|
|
end
|
|
|
|
E.CreatedMovers[name].Created = true
|
|
end
|
|
|
|
function E:CalculateMoverPoints(mover, nudgeX, nudgeY)
|
|
local screenWidth, screenHeight, screenCenter = E.UIParent:GetRight(), E.UIParent:GetTop(), E.UIParent:GetCenter()
|
|
local x, y = mover:GetCenter()
|
|
|
|
local LEFT = screenWidth / 3
|
|
local RIGHT = screenWidth * 2 / 3
|
|
local TOP = screenHeight / 2
|
|
local point, nudgePoint, nudgeInversePoint
|
|
|
|
if y >= TOP then
|
|
point = "TOP"
|
|
nudgePoint = "TOP"
|
|
nudgeInversePoint = "BOTTOM"
|
|
y = -(screenHeight - mover:GetTop())
|
|
else
|
|
point = "BOTTOM"
|
|
nudgePoint = "BOTTOM"
|
|
nudgeInversePoint = "TOP"
|
|
y = mover:GetBottom()
|
|
end
|
|
|
|
if x >= RIGHT then
|
|
point = point.."RIGHT"
|
|
nudgePoint = "RIGHT"
|
|
nudgeInversePoint = "LEFT"
|
|
x = mover:GetRight() - screenWidth
|
|
elseif x <= LEFT then
|
|
point = point.."LEFT"
|
|
nudgePoint = "LEFT"
|
|
nudgeInversePoint = "RIGHT"
|
|
x = mover:GetLeft()
|
|
else
|
|
x = x - screenCenter
|
|
end
|
|
|
|
if mover.positionOverride and (E.diffGetLeft and E.diffGetRight and E.diffGetTop and E.diffGetBottom) then
|
|
if mover.positionOverride == "TOPLEFT" then
|
|
x = mover:GetLeft() - E.diffGetLeft
|
|
y = mover:GetTop() - E.diffGetTop
|
|
elseif mover.positionOverride == "TOPRIGHT" then
|
|
x = mover:GetRight() - E.diffGetRight
|
|
y = mover:GetTop() - E.diffGetTop
|
|
elseif mover.positionOverride == "BOTTOMLEFT" then
|
|
x = mover:GetLeft() - E.diffGetLeft
|
|
y = mover:GetBottom() - E.diffGetBottom
|
|
elseif mover.positionOverride == "BOTTOMRIGHT" then
|
|
x = mover:GetRight() - E.diffGetRight
|
|
y = mover:GetBottom() - E.diffGetBottom
|
|
elseif mover.positionOverride == "BOTTOM" then
|
|
x = mover:GetCenter() - screenCenter
|
|
y = mover:GetBottom() - E.diffGetBottom
|
|
elseif mover.positionOverride == "TOP" then
|
|
x = mover:GetCenter() - screenCenter
|
|
y = mover:GetTop() - E.diffGetTop
|
|
end
|
|
end
|
|
|
|
--Update coordinates if nudged
|
|
x = x + (nudgeX or 0)
|
|
y = y + (nudgeY or 0)
|
|
|
|
return x, y, point, nudgePoint, nudgeInversePoint
|
|
end
|
|
|
|
function E:UpdatePositionOverride(name)
|
|
local frame = _G[name]
|
|
local OnDragStop = frame and frame.GetScript and frame:GetScript("OnDragStop")
|
|
if OnDragStop then OnDragStop(frame) end
|
|
end
|
|
|
|
function E:HasMoverBeenMoved(name)
|
|
if E.db.movers and E.db.movers[name] then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function E:SaveMoverPosition(name)
|
|
if not _G[name] then return end
|
|
if not E.db.movers then E.db.movers = {} end
|
|
|
|
local mover = _G[name]
|
|
local _, anchor = mover:GetPoint()
|
|
mover.anchor = anchor:GetName()
|
|
|
|
E.db.movers[name] = GetPoint(mover)
|
|
end
|
|
|
|
function E:SetMoverSnapOffset(name, offset)
|
|
if not _G[name] or not E.CreatedMovers[name] then return end
|
|
E.CreatedMovers[name].mover.snapOffset = offset or -2
|
|
E.CreatedMovers[name].snapoffset = offset or -2
|
|
end
|
|
|
|
function E:SaveMoverDefaultPosition(name)
|
|
if not _G[name] then return end
|
|
|
|
E.CreatedMovers[name].point = GetPoint(_G[name])
|
|
E.CreatedMovers[name].postdrag(_G[name], E:GetScreenQuadrant(_G[name]))
|
|
end
|
|
|
|
function E:CreateMover(parent, name, text, overlay, snapoffset, postdrag, moverTypes, shouldDisable, configString)
|
|
if not moverTypes then moverTypes = "ALL,GENERAL" end
|
|
|
|
if E.CreatedMovers[name] == nil then
|
|
E.CreatedMovers[name] = {}
|
|
E.CreatedMovers[name].parent = parent
|
|
E.CreatedMovers[name].text = text
|
|
E.CreatedMovers[name].overlay = overlay
|
|
E.CreatedMovers[name].postdrag = postdrag
|
|
E.CreatedMovers[name].snapoffset = snapoffset
|
|
E.CreatedMovers[name].point = GetPoint(parent)
|
|
E.CreatedMovers[name].shouldDisable = shouldDisable
|
|
E.CreatedMovers[name].configString = configString
|
|
|
|
E.CreatedMovers[name].type = {}
|
|
local types = {split(",", moverTypes)}
|
|
for i = 1, #types do
|
|
local moverType = types[i]
|
|
E.CreatedMovers[name].type[moverType] = true
|
|
end
|
|
end
|
|
|
|
CreateMover(parent, name, text, overlay, snapoffset, postdrag, shouldDisable, configString)
|
|
end
|
|
|
|
function E:ToggleMovers(show, moverType)
|
|
self.configMode = show
|
|
|
|
for name in pairs(E.CreatedMovers) do
|
|
if not show then
|
|
_G[name]:Hide()
|
|
else
|
|
if E.CreatedMovers[name].type[moverType] then
|
|
_G[name]:Show()
|
|
else
|
|
_G[name]:Hide()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function E:DisableMover(name)
|
|
if self.DisabledMovers[name] then return end
|
|
|
|
if not self.CreatedMovers[name] then
|
|
error("mover doesn't exist")
|
|
end
|
|
|
|
self.DisabledMovers[name] = {}
|
|
for x, y in pairs(self.CreatedMovers[name]) do
|
|
self.DisabledMovers[name][x] = y
|
|
end
|
|
|
|
if self.configMode then
|
|
_G[name]:Hide()
|
|
end
|
|
|
|
self.CreatedMovers[name] = nil
|
|
end
|
|
|
|
function E:EnableMover(name)
|
|
if self.CreatedMovers[name] then return end
|
|
|
|
if not self.DisabledMovers[name] then
|
|
error("mover doesn't exist")
|
|
end
|
|
|
|
self.CreatedMovers[name] = {}
|
|
for x, y in pairs(self.DisabledMovers[name]) do
|
|
self.CreatedMovers[name][x] = y
|
|
end
|
|
|
|
--Make sure we add anchor information from a potential profile switch
|
|
--Commented out, as it created an issue with trying to reset a mover after having used EnableMover on it. Not sure if this code is even needed anymore.
|
|
-- if E.db.movers and E.db.movers[name] and type(E.db.movers[name]) == 'string' then
|
|
-- self.CreatedMovers[name].point = E.db.movers[name]
|
|
-- end
|
|
|
|
if self.configMode then
|
|
_G[name]:Show()
|
|
end
|
|
|
|
self.DisabledMovers[name] = nil
|
|
end
|
|
|
|
function E:ResetMovers(arg)
|
|
if arg == "" or arg == nil then
|
|
for name in pairs(E.CreatedMovers) do
|
|
local f = _G[name]
|
|
local point, anchor, secondaryPoint, x, y = split(",", E.CreatedMovers[name].point)
|
|
f:ClearAllPoints()
|
|
f:Point(point, anchor, secondaryPoint, x, y)
|
|
|
|
for key, value in pairs(E.CreatedMovers[name]) do
|
|
if key == "postdrag" and type(value) == "function" then
|
|
value(f, E:GetScreenQuadrant(f))
|
|
end
|
|
end
|
|
end
|
|
self.db.movers = nil
|
|
else
|
|
for name in pairs(E.CreatedMovers) do
|
|
for key, value in pairs(E.CreatedMovers[name]) do
|
|
if key == "text" then
|
|
if arg == value then
|
|
local f = _G[name]
|
|
local point, anchor, secondaryPoint, x, y = split(",", E.CreatedMovers[name].point)
|
|
f:ClearAllPoints()
|
|
f:Point(point, anchor, secondaryPoint, x, y)
|
|
|
|
if self.db.movers then
|
|
self.db.movers[name] = nil
|
|
end
|
|
|
|
if E.CreatedMovers[name].postdrag ~= nil and type(E.CreatedMovers[name].postdrag) == "function" then
|
|
E.CreatedMovers[name].postdrag(f, E:GetScreenQuadrant(f))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--Profile Change
|
|
function E:SetMoversPositions()
|
|
--E:SetMoversPositions() is the first function called in E:UpdateAll().
|
|
--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 shouldDisable = ((E.DisabledMovers[name].shouldDisable and E.DisabledMovers[name].shouldDisable()) or false)
|
|
if not shouldDisable then
|
|
E:EnableMover(name)
|
|
end
|
|
end
|
|
|
|
for name in pairs(E.CreatedMovers) do
|
|
local f = _G[name]
|
|
local point, anchor, secondaryPoint, x, y
|
|
if E.db.movers and E.db.movers[name] and type(E.db.movers[name]) == "string" then
|
|
--Backward compatibility
|
|
local delim
|
|
local anchorString = E.db.movers[name]
|
|
if find(anchorString, "\031") then
|
|
delim = "\031"
|
|
elseif find(anchorString, ",") then
|
|
delim = ","
|
|
end
|
|
point, anchor, secondaryPoint, x, y = split(delim, anchorString)
|
|
f:ClearAllPoints()
|
|
f:Point(point, anchor, secondaryPoint, x, y)
|
|
elseif f then
|
|
point, anchor, secondaryPoint, x, y = split(",", E.CreatedMovers[name].point)
|
|
f:ClearAllPoints()
|
|
f:Point(point, anchor, secondaryPoint, x, y)
|
|
end
|
|
end
|
|
end
|
|
|
|
function E:SetMoversClampedToScreen(value)
|
|
for name in pairs(E.CreatedMovers) do
|
|
_G[name]:SetClampedToScreen(value)
|
|
end
|
|
end
|
|
|
|
--Called from core.lua
|
|
function E:LoadMovers()
|
|
for name, t in pairs(E.CreatedMovers) do
|
|
CreateMover(t.parent, name, t.text, t.overlay, t.snapoffset, t.postdrag, t.shouldDisable, t.configString)
|
|
end
|
|
end |