local E, L, V, P, G = unpack(ElvUI) local MBG = E:NewModule("Enhanced_MinimapButtonGrabber", "AceHook-3.0", "AceTimer-3.0") local pairs, ipairs = pairs, ipairs local select = select local unpack = unpack local ceil = math.ceil local find, len, sub = string.find, string.len, string.sub local tinsert = table.insert local UIFrameFadeIn = UIFrameFadeIn local UIFrameFadeOut = UIFrameFadeOut local ignoreButtons = { ["ElvConfigToggle"] = true, ["BattlefieldMinimap"] = true, ["ButtonCollectFrame"] = true, ["GameTimeFrame"] = true, ["MiniMapBattlefieldFrame"] = true, ["MiniMapLFGFrame"] = true, ["MiniMapMailFrame"] = true, ["MiniMapPing"] = true, ["MiniMapRecordingButton"] = true, ["MiniMapTracking"] = true, ["MiniMapTrackingButton"] = true, ["MiniMapVoiceChatFrame"] = true, ["MiniMapWorldMapButton"] = true, ["Minimap"] = true, ["MinimapBackdrop"] = true, ["MinimapToggleButton"] = true, ["MinimapZoneTextButton"] = true, ["MinimapZoomIn"] = true, ["MinimapZoomOut"] = true, ["TimeManagerClockButton"] = true, } local genericIgnores = { "GuildInstance", -- GatherMate "GatherMatePin", -- Gatherer "GatherNote", -- GuildMap3 "GuildMap3Mini", -- HandyNotes "HandyNotesPin", -- LibRockConfig "LibRockConfig-1.0_MinimapButton", -- Nauticus "NauticusMiniIcon", "WestPointer", -- QuestPointer "poiMinimap", -- Spy "Spy_MapNoteList_mini", } local partialIgnores = { "Node", "Note", "Pin", } local whiteList = { "LibDBIcon", } local buttonFunctions = { "SetParent", "SetFrameStrata", "SetFrameLevel", "ClearAllPoints", "SetPoint", "SetScale", "SetSize", "SetWidth", "SetHeight" } local function OnEnter() UIFrameFadeIn(MBG.frame, 0.1, MBG.frame:GetAlpha(), MBG.maxAlpha) end local function OnLeave() UIFrameFadeOut(MBG.frame, 0.1, MBG.frame:GetAlpha(), 0) end function MBG:LockButton(button) for _, func in ipairs(buttonFunctions) do button[func] = E.noop end end function MBG:UnlockButton(button) for _, func in ipairs(buttonFunctions) do button[func] = nil end end function MBG:CheckVisibility() local updateLayout for _, button in ipairs(self.skinnedButtons) do if button:IsVisible() and button.__hidden then button.__hidden = false updateLayout = true elseif not button:IsVisible() and not button.__hidden then button.__hidden = true updateLayout = true end end return updateLayout end function MBG:GetVisibleList() local t = {} for _, button in ipairs(self.skinnedButtons) do if button:IsVisible() then tinsert(t, button) end end return t end function MBG:GrabMinimapButtons() for _, frame in ipairs(self.minimapFrames) do for i = 1, frame:GetNumChildren() do local object = select(i, frame:GetChildren()) if object and object:IsObjectType("Button") then self:SkinMinimapButton(object) end end end if AtlasButtonFrame then self:SkinMinimapButton(AtlasButton) end if FishingBuddyMinimapFrame then self:SkinMinimapButton(FishingBuddyMinimapButton) end if HealBot_MMButton then self:SkinMinimapButton(HealBot_MMButton) end if self.needUpdate or self:CheckVisibility() then self:UpdateLayout() end end function MBG:SkinMinimapButton(button) if not button or button.isSkinned then return end local name = button:GetName() if not name then return end if button:IsObjectType("Button") then local validIcon for i = 1, #whiteList do if sub(name, 1, len(whiteList[i])) == whiteList[i] then validIcon = true break end end if not validIcon then if ignoreButtons[name] then return end for i = 1, #genericIgnores do if sub(name, 1, len(genericIgnores[i])) == genericIgnores[i] then return end end for i = 1, #partialIgnores do if find(name, partialIgnores[i]) then return end end end button:SetPushedTexture(nil) button:SetHighlightTexture(nil) button:SetDisabledTexture(nil) end for i = 1, button:GetNumRegions() do local region = select(i, button:GetRegions()) if region:GetObjectType() == "Texture" then local texture = region:GetTexture() if texture and (find(texture, "Border") or find(texture, "Background") or find(texture, "AlphaMask")) then region:SetTexture(nil) else if name == "BagSync_MinimapButton" then region:SetTexture("Interface\\AddOns\\BagSync\\media\\icon") elseif name == "DBMMinimapButton" then region:SetTexture("Interface\\Icons\\INV_Helmet_87") elseif name == "OutfitterMinimapButton" then if region:GetTexture() == "Interface\\Addons\\Outfitter\\Textures\\MinimapButton" then region:SetTexture(nil) end elseif name == "SmartBuff_MiniMapButton" then region:SetTexture("Interface\\Icons\\Spell_Nature_Purge") elseif name == "VendomaticButtonFrame" then region:SetTexture("Interface\\Icons\\INV_Misc_Rabbit_2") end region:ClearAllPoints() region:SetInside() region:SetTexCoord(unpack(E.TexCoords)) button:HookScript("OnLeave", function() region:SetTexCoord(unpack(E.TexCoords)) end) region:SetDrawLayer("ARTWORK") region.SetPoint = E.noop end end end button:SetParent(self.frame) button:SetFrameLevel(self.frame:GetFrameLevel() + 5) button:SetTemplate() self:LockButton(button) button:SetScript("OnDragStart", nil) button:SetScript("OnDragStop", nil) if E.db.enhanced.minimap.buttonGrabber.mouseover then button:HookScript("OnEnter", OnEnter) button:HookScript("OnLeave", OnLeave) end button.__hidden = button:IsVisible() and true or false button.isSkinned = true tinsert(self.skinnedButtons, button) self.needUpdate = true end function MBG:UpdateLayout() if #self.skinnedButtons == 0 then return end local db = E.db.enhanced.minimap.buttonGrabber local spacing = (db.backdrop and (E.Border + db.backdropSpacing) or E.Spacing) local visibleButtons = self:GetVisibleList() if #visibleButtons == 0 then self.frame:Size(db.buttonSize + (spacing * 2)) self.frame.backdrop:Hide() return end local numButtons = #visibleButtons local buttonsPerRow = db.buttonsPerRow local numColumns = ceil(numButtons / buttonsPerRow) if buttonsPerRow > numButtons then buttonsPerRow = numButtons end local barWidth = (db.buttonSize * buttonsPerRow) + (db.buttonSpacing * (buttonsPerRow - 1)) + spacing * 2 local barHeight = (db.buttonSize * numColumns) + (db.buttonSpacing * (numColumns - 1)) + spacing * 2 self.frame:Size(barWidth, barHeight) self.frame.mover:Size(barWidth, barHeight) if db.backdrop then self.frame.backdrop:Show() else self.frame.backdrop:Hide() end local verticalGrowth = (db.growFrom == "TOPLEFT" or db.growFrom == "TOPRIGHT") and "DOWN" or "UP" local horizontalGrowth = (db.growFrom == "TOPLEFT" or db.growFrom == "BOTTOMLEFT") and "RIGHT" or "LEFT" for i, button in ipairs(visibleButtons) do self:UnlockButton(button) button:Size(db.buttonSize) button:ClearAllPoints() if i == 1 then local x, y if db.growFrom == "TOPLEFT" then x, y = spacing, -spacing elseif db.growFrom == "TOPRIGHT" then x, y = -spacing, -spacing elseif db.growFrom == "BOTTOMLEFT" then x, y = spacing, spacing else x, y = -spacing, spacing end button:Point(db.growFrom, self.frame, db.growFrom, x, y) elseif (i - 1) % buttonsPerRow == 0 then if verticalGrowth == "DOWN" then button:Point("TOP", visibleButtons[i - buttonsPerRow], "BOTTOM", 0, -db.buttonSpacing) else button:Point("BOTTOM", visibleButtons[i - buttonsPerRow], "TOP", 0, db.buttonSpacing) end elseif horizontalGrowth == "RIGHT" then button:Point("LEFT", visibleButtons[i - 1], "RIGHT", db.buttonSpacing, 0) elseif horizontalGrowth == "LEFT" then button:Point("RIGHT", visibleButtons[i - 1], "LEFT", -db.buttonSpacing, 0) end self:LockButton(button) end self.needUpdate = false end function MBG:UpdatePosition() local db = E.db.enhanced.minimap.buttonGrabber.insideMinimap if db.enable then self.frame:ClearAllPoints() self.frame:Point(db.position, Minimap, db.position, db.xOffset, db.yOffset) E:DisableMover(self.frame.mover:GetName()) else self.frame:ClearAllPoints() self.frame:SetAllPoints(self.frame.mover) E:EnableMover(self.frame.mover:GetName()) end end function MBG:UpdateAlpha() self.maxAlpha = E.db.enhanced.minimap.buttonGrabber.alpha if not E.db.enhanced.minimap.buttonGrabber.mouseover then self.frame:SetAlpha(self.maxAlpha) end end function MBG:ToggleMouseover() local mouseover = E.db.enhanced.minimap.buttonGrabber.mouseover local enter = mouseover and OnEnter or nil local leave = mouseover and OnLeave or nil self.frame:SetAlpha(mouseover and 0 or E.db.enhanced.minimap.buttonGrabber.alpha) self.frame:SetScript("OnEnter", enter) self.frame:SetScript("OnLeave", leave) if #self.skinnedButtons > 0 then for _, button in ipairs(self.skinnedButtons) do button:SetScript("OnEnter", enter) button:SetScript("OnLeave", leave) end end end local addonFixes = { ["Atlas"] = function() function AtlasButton_Toggle() if AtlasButton:IsVisible() then AtlasButton:Hide() AtlasOptions.AtlasButtonShown = false else AtlasButton:Show() AtlasOptions.AtlasButtonShown = true end AtlasOptions_Init() end end, ["DBM-Core"] = function() local button = DBMMinimapButton if not button then return end if button:GetScript("OnMouseDown") then button:SetScript("OnMouseDown", nil) button:SetScript("OnMouseUp", nil) end end, ["Enchantrix"] = function() if not Enchantrix or EnxMiniMapIcon then return end local settings = Enchantrix.Settings local oldButton = Enchantrix.MiniIcon local newButton = CreateFrame("Button", "EnxMiniMapIcon", Minimap) newButton:Size(20) newButton:SetToplevel(true) newButton:SetFrameStrata("LOW") newButton:Point("RIGHT", Minimap, "LEFT", 0,0) newButton:RegisterForClicks("LeftButtonUp", "RightButtonUp") newButton.icon = oldButton.icon newButton.icon:SetTexCoord(0.2, 0.84, 0.13, 0.87) newButton.icon:SetParent(newButton) newButton.icon:SetPoint("TOPLEFT", newButton, "TOPLEFT", 0, 0) newButton.mask = oldButton.mask newButton.mask:SetParent(newButton) newButton.mask:SetPoint("TOPLEFT", newButton, "TOPLEFT", -8, 8) newButton:SetScript("OnClick", oldButton:GetScript("OnClick")) oldButton:SetMovable(false) oldButton:SetParent(UIParent) oldButton:Point("TOPRIGHT", UIParent) oldButton:Hide() oldButton:SetScript("OnMouseDown", nil) oldButton:SetScript("OnMouseUp", nil) oldButton:SetScript("OnDragStart", nil) oldButton:SetScript("OnDragStop", nil) oldButton:SetScript("OnClick", nil) oldButton:SetScript("OnUpdate", nil) Enchantrix.MiniIcon = newButton function Enchantrix.MiniIcon.Reposition() if settings.GetSetting("miniicon.enable") then newButton:Show() else newButton:Hide() end end end } function MBG:Initialize() if not E.private.enhanced.minimapButtonGrabber then return end local db = E.db.enhanced.minimap.buttonGrabber local spacing = (db.backdrop and (E.Border + db.backdropSpacing) or E.Spacing) self.skinnedButtons = {} self.minimapFrames = {Minimap, MinimapBackdrop} self.frame = CreateFrame("Frame", "ElvUI_MinimapButtonGrabber", UIParent) self.frame:Size(db.buttonSize + (spacing * 2)) self.frame:Point("TOPRIGHT", MMHolder, "BOTTOMRIGHT", 0, 1) self.frame:SetFrameStrata("LOW") self.frame:SetClampedToScreen(true) self.frame:CreateBackdrop() self.frame.backdrop:SetPoint("TOPLEFT", self.frame, "TOPLEFT", E.Spacing, -E.Spacing) self.frame.backdrop:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMRIGHT", -E.Spacing, E.Spacing) self.frame.backdrop:Hide() E:CreateMover(self.frame, "MinimapButtonGrabberMover", L["Minimap Button Grabber"], nil, nil, nil, "ALL,GENERAL") if self.frame.mover:GetScript("OnSizeChanged") then self.frame.mover:SetScript("OnSizeChanged", nil) end self.initialized = true self:ToggleMouseover() self:UpdateAlpha() self:UpdatePosition() self:GrabMinimapButtons() self:ScheduleRepeatingTimer("GrabMinimapButtons", 5) local AddonsCompat = E:GetModule("Enhanced_AddonsCompat") for addon, func in pairs(addonFixes) do AddonsCompat:AddAddon(addon, func) end end local function InitializeCallback() MBG:Initialize() end E:RegisterModule(MBG:GetName(), InitializeCallback)