local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB local Sticky = LibStub("LibSimpleSticky-1.0"); --Cache global variables --Lua functions local _G = _G local type, unpack, pairs = type, unpack, pairs local format, split, find = string.format, string.split, string.find --WoW API / Variables local CreateFrame = CreateFrame E.CreatedMovers = {} E.DisabledMovers = {} local function SizeChanged(self) E:Size(self.mover, self.dirtyWidth and self.dirtyWidth or self:GetWidth(), self.dirtyHeight and self.dirtyHeight or self:GetHeight()) end local function GetPoint(obj) local point, anchor, secondaryPoint, x, y = obj:GetPoint() if not anchor then anchor = ElvUIParent 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 or self local x, y, _, nudgePoint, nudgeInversePoint = E:CalculateMoverPoints(mover) local coordX, coordY = E:GetXYOffset(nudgeInversePoint, 1) ElvUIMoverNudgeWindow:ClearAllPoints() E:Point(ElvUIMoverNudgeWindow, nudgePoint, mover, nudgeInversePoint, coordX, coordY) E:UpdateNudgeFrame(mover, x, y) end local isDragging = false local coordFrame = CreateFrame("Frame") coordFrame:SetScript("OnUpdate", function() UpdateCoords(this) end) coordFrame:Hide() local function CreateMover(parent, name, text, overlay, snapOffset, postdrag, shouldDisable) 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)) 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) E:Size(f, width) E:SetTemplate(f, "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:SetFrameLevel(parent:GetFrameLevel() + 1) if overlay == true then f:SetFrameStrata("DIALOG") else f:SetFrameStrata("BACKGROUND") end E.CreatedMovers[name].mover = f E["snapBars"][getn(E["snapBars"]) + 1] = f local fs = f:CreateFontString(nil, "OVERLAY") E:FontTemplate(fs) fs:SetJustifyH("CENTER") E:Point(fs, "CENTER", f) 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 E:Point(f, 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 local delim local anchorString = E.db["movers"][name] if find(anchorString, "\031") then delim = "\031" elseif find(anchorString, ",") then delim = "," end local point, anchor, secondaryPoint, x, y = split(delim, anchorString) E:Point(f, point, anchor, secondaryPoint, x, y) else E:Point(f, point, anchor, secondaryPoint, x, y) end local function OnDragStart(self) 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) isDragging = false if E.db["general"].stickyFrames then Sticky:StopMoving(self) else self:StopMovingOrSizing() end local x, y, point = 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 E:Point(self, self.positionOverride or point, E.UIParent, overridePoint and overridePoint or point, x, y) if self.positionOverride then self.parent:ClearAllPoints() E:Point(self.parent, 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() if isDragging then return end this.text:SetTextColor(1, 1, 1) ElvUIMoverNudgeWindow:Show() E.AssignFrameToNudge(this) coordFrame.child = this UpdateCoords(coordFrame) coordFrame:GetScript("OnUpdate")(coordFrame) end local function OnMouseDown(button) if button == "RightButton" then isDragging = false if E.db["general"].stickyFrames then Sticky:StopMoving(this) else this:StopMovingOrSizing() end if IsControlKeyDown() and this.textString then E:ResetMovers(this.textString) elseif IsShiftKeyDown() then this:Hide() end end end local function OnLeave(self) if isDragging then return end this.text:SetTextColor(unpack(E["media"].rgbvaluecolor)) end local function OnShow(self) this: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", function() OnDragStart(f) end) f:SetScript("OnMouseUp", E.AssignFrameToNudge) f:SetScript("OnDragStop", function() OnDragStop(f) end) f:SetScript("OnEnter", OnEnter) f:SetScript("OnMouseDown", OnMouseDown) f:SetScript("OnLeave", OnLeave) f:SetScript("OnShow", OnShow) f:SetScript("OnMouseWheel", OnMouseWheel) parent:SetScript("OnSizeChanged", function() SizeChanged(parent) end) parent.mover = f parent:ClearAllPoints() E:Point(parent, point, f, 0, 0) if postdrag ~= nil and type(postdrag) == "function" then f:RegisterEvent("PLAYER_ENTERING_WORLD") f:SetScript("OnEvent", function() postdrag(f, E:GetScreenQuadrant(f)) this: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) 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 x = x + (nudgeX or 0) y = y + (nudgeY or 0) return x, y, point, nudgePoint, nudgeInversePoint end function E:UpdatePositionOverride(name) if _G[name] and _G[name]:GetScript("OnDragStop") then _G[name]:GetScript("OnDragStop")(_G[name]) 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 E.db.movers[name] = GetPoint(_G[name]) 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) 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]["type"] = {} local types = {split(",", moverTypes)} for i = 1, getn(types) do local moverType = types[i] E.CreatedMovers[name]["type"][moverType] = true end end CreateMover(parent, name, text, overlay, snapoffset, postdrag, shouldDisable) 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 --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() E:Point(f, 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() E:Point(f, 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() 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 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() E:Point(f, point, anchor, secondaryPoint, x, y) elseif f then point, anchor, secondaryPoint, x, y = split(",", E.CreatedMovers[name]["point"]) f:ClearAllPoints() E:Point(f, point, anchor, secondaryPoint, x, y) end end end --Called from core.lua function E:LoadMovers() for n, _ in pairs(E.CreatedMovers) do local p, t, o, so, pd for key, value in pairs(E.CreatedMovers[n]) do if key == "parent" then p = value elseif key == "text" then t = value elseif key == "overlay" then o = value elseif key == "snapoffset" then so = value elseif key == "postdrag" then pd = value end end CreateMover(p, n, t, o, so, pd) end end