local mod = StarTip:NewModule("Position", "AceEvent-3.0", "AceHook-3.0") mod.name = "Positioning" local LibTimer = LibStub("LibScriptableUtilsTimer-1.0") local _G = _G local GameTooltip = _G.GameTooltip local StarTip = _G.StarTip local UIParent = _G.UIParent local self = mod local L = StarTip.L local square = {L["Left"], L["Right"], L["Top"], L["Bottom"], L["Offscreen"]} local squareDict = {[L["Left"]] = 1, [L["Right"]] = 2, [L["Top"]] = 3, [L["Bottom"]] = 4, [L["Offscreen"]] = 5} local squareNames = {"LEFT", "RIGHT", "TOP", "BOTTOM"} local defaults = { profile = { inCombat = 1, anchor = 1, unitFrames = 1, other = 1, inCombatXOffset = 10, inCombatYOffset = 0, anchorXOffset = 10, anchorYOffset = 0, unitFramesXOffset = 10, unitFramesYOffset = 0, otherXOffset = 10, otherYOffset = 0, defaultUnitTooltipPos = 5 } } local selections = {} for i, v in ipairs(StarTip.anchorText) do selections[i] = v end selections[#selections+1] = "Hide" local get = function(info) return self.db.profile[info[#info]] end local set = function(info,v) self.db.profile[info[#info]] = v end local inputGet = function(info) return tostring(self.db.profile[info[#info]] or 0) end local inputSet = function(info, v) self.db.profile[info[#info]] = tonumber(v) end local minX = -math.floor(GetScreenWidth()/5 + 0.5) * 5 local minY = -math.floor(GetScreenHeight()/5 + 0.5) * 5 local maxX = math.floor(GetScreenWidth()/5 + 0.5) * 5 local maxY = math.floor(GetScreenHeight()/5 + 0.5) * 5 local options = { anchor = { name = L["World Units"], desc = L["Where to anchor the tooltip when mousing over world characters"], type = "select", values = selections, get = get, set = set, order = 4 }, anchorXOffset = { name = format(L["X-axis offset: %d-%d"], minX, maxX), desc = L["The x-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minX and val <= maxX end, order = 5 }, anchorYOffset = { name = format(L["Y-axis offset: %d-%d"], minY, maxY), desc = L["The y-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minY and val <= maxY end, order = 6 }, --[[anchorXOffset = { name = "X-axis offset", desc = "The x-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minX, max = maxX, step = 1, bigStep = 5, get = get, set = set, order = 5 }, anchorYOffset = { name = "Y-axis offset", desc = "The y-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minY, max = maxY, step = 1, bigStep = 5, get = get, set = set, order = 6 },]] inCombatHeader = { name = "", type = "header", order = 7 }, inCombat = { name = L["In Combat"], desc = L["Where to anchor the world unit tooltip while in combat"], type = "select", values = selections, get = get, set = set, order = 8 }, inCombatXOffset = { name = format(L["X-axis offset: %d-%d"], minX, maxX), desc = L["The x-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minX and val <= maxX end, order = 9 }, inCombatYOffset = { name = format(L["Y-axis offset: %d-%d"], minY, maxY), desc = L["The y-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minY and val <= maxX end, order = 10, }, --[[inCombatXOffset = { name = "X-axis offset", desc = "The x-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minX, max = maxX, step = 1, bigStep = 5, get = get, set = set, order = 9 }, inCombatYOffset = { name = "Y-axis offset", desc = "The y-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minY, max = maxY, step = 1, bigStep = 5, get = get, set = set, order = 10 },]] unitFramesHeader = { name = "", type = "header", order = 11 }, unitFrames = { name = L["Unit Frames"], desc = L["Where to anchor the tooltip when mousing over a unit frame"], type = "select", values = selections, get = get, set = set, order = 12 }, unitFramesXOffset = { name = format(L["X-axis offset: %d-%d"], minX, maxX), desc = L["The x-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minX and val <= maxX end, order = 13 }, unitFramesYOffset = { name = format(L["Y-axis offset: %d-%d"], minY, maxY), desc = L["The y-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minY and val <= maxY end, order = 14 }, --[[unitFramesXOffset = { name = "X-axis offset", desc = "The x-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minX, max = maxX, step = 1, bigStep = 5, get = get, set = set, order = 13 }, unitFramesYOffset = { name = "Y-axis offset", desc = "The y-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minY, max = maxY, step = 1, bigStep = 5, get = get, set = set, order = 14 },]] otherHeader = { name = "", type = "header", order = 15 }, other = { name = L["Other tooltips"], desc = L["Where to anchor most other tooltips"], type = "select", values = selections, get = get, set = set, order = 16 }, otherXOffset = { name = format(L["X-axis offset: %d-%d"], minX, maxX), desc = L["The x-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minX and val <= maxX end, order = 17 }, otherYOffset = { name = format(L["Y-axis offset: %d-%d"], minY, maxY), desc = L["The y-axis offset used to position the tooltip in relationship to the anchor point"], type = "input", pattern = "%d", get = inputGet, set = inputSet, validate = function(info, val) val = tonumber(val) return val >= minY and val <= maxY end, order = 18 }, --[[otherXOffset = { name = "X-axis offset", desc = "The x-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minX, max = maxX, step = 1, bigStep = 5, get = get, set = set, order = 17 }, otherYOffset = { name = "Y-axis offset", desc = "The y-axis offset used to position the tooltip in relationship to the anchor point", type = "range", min = minY, max = maxY, step = 1, bigStep = 5, get = get, set = set, order = 18 }]] defaultUnitTooltipPos = { name = "Position UI Tooltip", type = "select", values = square, get = function() return mod.db.profile.defaultUnitTooltipPos end, set = function(info, val) mod.db.profile.defaultUnitTooltipPos = val end, order = 20 } } function mod:OnInitialize() self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults) StarTip:SetOptionsDisabled(options, true) self.timer = LibTimer:New("Position.timer ", 100, false, positionTooltip) end function mod:OnEnable() self:RegisterEvent("REGEN_DISABLED") self:RegisterEvent("REGEN_ENABLED") self:SecureHook("GameTooltip_SetDefaultAnchor") StarTip:SetOptionsDisabled(options, false) end function mod:OnDisable() self:UnregisterEvent("REGEN_DISABLED") self:UnregisterEvent("REGEN_ENABLED") self:Unhook("GameTooltip_SetDefaultAnchor") StarTip:SetOptionsDisabled(options, true) end function mod:GetOptions() return options end local getIndex = function(owner) local index if GameTooltip:GetUnit() and UnitExists(StarTip.unit) then if InCombatLockdown() then index = self.db.profile.inCombat elseif owner == UIParent then index = self.db.profile.anchor else index = self.db.profile.unitFrames end else index = self.db.profile.other end return index end local function hideGameTooltip() GameTooltip:ClearAllPoints() GameTooltip:SetClampRectInsets(10000, 0, 0, 0) GameTooltip:SetPoint("RIGHT", UIParent, "LEFT") end local isUnitTooltip local updateFrame = CreateFrame("Frame") local fakeUpdateFrame = CreateFrame("Frame") local currentAnchor = "BOTTOM" local xoffset, yoffset = 0, 0 local positionTooltip = function() local x, y = GetCursorPosition() local effScale = GameTooltip:GetEffectiveScale() if not isUnitTooltip then GameTooltip:ClearAllPoints() GameTooltip:SetPoint(currentAnchor, UIParent, "BOTTOMLEFT", (x + xoffset) / effScale, (y + yoffset) / effScale + 5) end if UnitExists(StarTip.unit or "mouseover") then if mod.db.profile.defaultUnitTooltipPos == 5 then hideGameTooltip() else local pos = squareNames[self.db.profile.defaultUnitTooltipPos] GameTooltip:ClearAllPoints() GameTooltip:SetPoint(StarTip.opposites[pos], StarTip.tooltipMain, pos) end end end local positionMainTooltip = function() local x, y = GetCursorPosition() local index = getIndex(UIParent) local currentAnchor = StarTip.opposites[StarTip.anchors[index]:sub(8)] local tooltip = StarTip.tooltipMain local effScale = tooltip:GetEffectiveScale() tooltip:ClearAllPoints() tooltip:SetPoint(currentAnchor, UIParent, "BOTTOMLEFT", (x + xoffset) / effScale, (y + yoffset) / effScale) end local setOffsets = function(owner) if owner == UIParent then if UnitExists(StarTip.unit) then if InCombatLockdown() then xoffset = self.db.profile.inCombatXOffset yoffset = self.db.profile.inCombatYOffset else xoffset = self.db.profile.anchorXOffset yoffset = self.db.profile.anchorYOffset end else xoffset = self.db.profile.otherXOffset yoffset = self.db.profile.otherYOffset end else if UnitExists(StarTip.unit) then xoffset = self.db.profile.unitFramesXOffset yoffset = self.db.profile.unitFramesYOffset else xoffset = self.db.profile.otherXOffset yoffset = self.db.profile.otherYOffset end end end local currentOwner local currentThis local delayFrame = CreateFrame("Frame") local function delayAnchor() delayFrame:SetScript("OnUpdate", nil) local this = currentThis local owner = currentOwner setOffsets(owner) local index = getIndex(owner) if index == #selections then this:Hide() return elseif StarTip.anchors[index]:find("^CURSOR_") then currentAnchor = StarTip.opposites[StarTip.anchors[index]:sub(8)] isUnitTooltip = false if GameTooltip:GetUnit() then isUnitTooltip = true fakeUpdateFrame:SetScript("OnUpdate", positionMainTooltip) positionMainTooltip() end updateFrame:SetScript("OnUpdate", positionTooltip) positionTooltip() elseif GameTooltip:GetUnit() then updateFrame:SetScript("OnUpdate", nil) fakeUpdateFrame:SetScript("OnUpdate", nil) StarTip.tooltipMain:ClearAllPoints() StarTip.tooltipMain:SetPoint(StarTip.anchors[index], UIParent, StarTip.anchors[index], xoffset, yoffset) else updateFrame:SetScript("OnUpdate", nil) fakeUpdateFrame:SetScript("OnUpdate", nil) GameTooltip:ClearAllPoints() GameTooltip:SetPoint(StarTip.anchors[index], UIParent, StarTip.anchors[index], xoffset, yoffset) end end function mod:GameTooltip_SetDefaultAnchor(this, owner) currentOwner = owner currentThis = this local index = getIndex(owner) local ownername = owner:GetName() if owner == MainMenuMicroButton then -- This one is troublesome, so single it out and anchor right away. delayAnchor() else delayFrame:SetScript("OnUpdate", delayAnchor) end end function mod:REGEN_DISABLED() if not currentOwner then return end updateFrame:SetScript("OnUpdate", nil) self:GameTooltip_SetDefaultAnchor(GameTooltip, currentOwner) end mod.REGEN_ENABLED = mod.REGEN_DISABLED function mod:OnHide() updateFrame:SetScript("OnUpdate", nil) delayFrame:SetScript("OnUpdate", nil) fakeUpdateFrame:SetScript("OnUpdate", nil) end function mod:SetSpell() local index = getIndex(currentOwner) if StarTip.anchors[index]:find("^CURSOR_") then updateFrame:SetScript("OnUpdate", nil) positionTooltip() else GameTooltip:ClearAllPoints() GameTooltip:SetPoint(StarTip.anchors[index], UIParent, StarTip.anchors[index], xoffset, yoffset) end end function mod:SetItem() local index = getIndex(currentOwner) if StarTip.anchors[index]:find("^CURSOR_") then updateFrame:SetScript("OnUpdate", nil) positionTooltip() else GameTooltip:ClearAllPoints() GameTooltip:SetPoint(StarTip.anchors[index], UIParent, StarTip.anchors[index], xoffset, yoffset) end end function mod:SetUnit() local index = getIndex(currentOwner) if not StarTip.anchors[index]:find("^CURSOR_") then hideGameTooltip() end end