local Grid2 = Grid2 local SecureButton_GetModifiedUnit = SecureButton_GetModifiedUnit local UnitFrame_OnEnter = UnitFrame_OnEnter local UnitFrame_OnLeave = UnitFrame_OnLeave local next = next local Grid2Frame --{{{ Registered unit frames tracking local frames_of_unit = setmetatable({}, {__index = function(self, key) local result = {} self[key] = result return result end}) local unit_of_frame = {} function Grid2:SetFrameUnit(frame, unit) local prev_unit = unit_of_frame[frame] if prev_unit then frames_of_unit[prev_unit][frame] = nil end if unit then frames_of_unit[unit][frame] = true end unit_of_frame[frame] = unit end function Grid2:GetUnitFrames(unit) return frames_of_unit[unit] end --}}} --{{{ Dropdown menu management local ToggleUnitMenu do local frame, unit = CreateFrame("Frame", "Grid2_UnitFrame_DropDown", UIParent, "UIDropDownMenuTemplate") UIDropDownMenu_Initialize(frame, function() if unit then local menu, raid if UnitIsUnit(unit, "player") then menu = "SELF" elseif UnitIsUnit(unit, "pet") then menu = "PET" elseif Grid2:UnitIsPet(unit) then menu = "RAID_TARGET_ICON" elseif Grid2:UnitIsParty(unit) then menu = "PARTY" elseif Grid2:UnitIsRaid(unit) then menu, raid = "RAID_PLAYER", UnitInRaid(unit) else return end frame:SetScript("OnUpdate", Grid2.UnitPopup_OnUpdate) Grid2:UnitPopup_ShowMenu(frame, menu, unit, nil, raid) end end, "MENU") ToggleUnitMenu = function(self) unit = self.unit ToggleDropDownMenu(1, nil, frame, "cursor") end end --}}} -- {{ Precalculated backdrop table, shared by all frames local frameBackdrop -- }} --{{{ Grid2Frame script handlers local GridFrameEvents = {} function GridFrameEvents:OnShow() Grid2Frame:SendMessage("Grid_UpdateLayoutSize") end function GridFrameEvents:OnHide() Grid2Frame:SendMessage("Grid_UpdateLayoutSize") end function GridFrameEvents:OnAttributeChanged(name, value) if name == "unit" then if value then local unit = SecureButton_GetModifiedUnit(self) if self.unit ~= unit then Grid2Frame:Debug("updated", self:GetName(), name, value, unit) self.unit = unit self:UpdateIndicators() Grid2:SetFrameUnit(self, unit) end elseif self.unit then Grid2Frame:Debug("removed", self:GetName(), name, self.unit) self.unit = nil Grid2:SetFrameUnit(self, nil) end end end function GridFrameEvents:OnEnter() Grid2Frame:OnFrameEnter(self) end function GridFrameEvents:OnLeave() Grid2Frame:OnFrameLeave(self) end --}}} --{{{ GridFramePrototype local pairs = pairs local GridFramePrototype = {} local function GridFrame_Init(frame, width, height) for name, value in pairs(GridFramePrototype) do frame[name] = value end for event, handler in pairs(GridFrameEvents) do frame:SetScript(event, handler) end if frame:CanChangeAttribute() then frame:SetAttribute("initial-width", width) frame:SetAttribute("initial-height", height) end frame.menu = ToggleUnitMenu frame.container = frame:CreateTexture() frame:CreateIndicators() frame:Layout() ClickCastFrames = ClickCastFrames or {} ClickCastFrames[frame] = true end function GridFramePrototype:Layout() local dbx = Grid2Frame.db.profile local w = dbx.frameWidth local h = dbx.frameHeight -- external border controlled by the border indicator local r, g, b, a = self:GetBackdropBorderColor() self:SetBackdrop(frameBackdrop) self:SetBackdropBorderColor(r, g, b, a) -- inner border color (sure that is the inner border) local cf = dbx.frameColor self:SetBackdropColor(cf.r, cf.g, cf.b, cf.a) -- visible background local container = self.container container:SetPoint("CENTER", self, "CENTER") -- visible background color local cb = dbx.frameContentColor container:SetVertexColor(cb.r, cb.g, cb.b, cb.a) -- shrink the background, showing part of the real frame background (that is behind) as a inner border. local inset = (dbx.frameBorder + dbx.frameBorderDistance) * 2 container:SetSize(w - inset, h - inset) -- visible background texture local texture = Grid2:MediaFetch("statusbar", dbx.frameTexture, "Gradient") self.container:SetTexture(texture) -- set size if not InCombatLockdown() then self:SetSize(w, h) end -- highlight texture self:SetHighlightTexture(dbx.mouseoverHighlight and "Interface\\QuestFrame\\UI-QuestTitleHighlight" or nil) -- Adjust indicators position to the new size for _, indicator in Grid2:IterateIndicators() do indicator:Layout(self) end end function GridFramePrototype:CreateIndicators() for _, indicator in Grid2:IterateIndicators() do indicator:Create(self) end end function GridFramePrototype:UpdateIndicators() local unit = self.unit if unit then for _, indicator in Grid2:IterateIndicators() do indicator:Update(self, unit) end end end --}}} --{{{ Grid2Frame Grid2Frame = Grid2:NewModule("Grid2Frame") Grid2Frame.defaultDB = { profile = { debug = false, font = "Friz Quadrata TT", frameHeight = 48, frameWidth = 48, frameBorder = 2, frameBorderTexture = "Grid2 Flat", frameBorderDistance = 1, frameTexture = "Gradient", frameColor = {r = 0, g = 0, b = 0, a = 1}, frameContentColor = {r = 0, g = 0, b = 0, a = 1}, mouseoverHighlight = false, showTooltip = "OOC", orientation = "VERTICAL", textOrientation = "VERTICAL", intensity = 0.5, blinkType = "Flash", blinkFrequency = 2 } } function Grid2Frame:OnModuleInitialize() self.registeredFrames = {} end function Grid2Frame:OnModuleEnable() self:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdateFrameUnits") self:RegisterEvent("UNIT_ENTERED_VEHICLE") self:RegisterEvent("UNIT_EXITED_VEHICLE") self:RegisterMessage("Grid_UnitUpdate") self:UpdateBlink() self:UpdateBackdrop() self:UpdateFrameUnits() self:UpdateIndicators() end function Grid2Frame:OnModuleDisable() self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("UNIT_ENTERED_VEHICLE") self:UnregisterEvent("UNIT_EXITED_VEHICLE") self:UnregisterMessage("Grid_UnitUpdate") end function Grid2Frame:OnModuleUpdate() self:CreateIndicators() self:LayoutFrames() end function Grid2Frame:RegisterFrame(frame) GridFrame_Init(frame, self:GetFrameSize()) self.registeredFrames[frame:GetName()] = frame end function Grid2Frame:CreateIndicators() for _, frame in next, self.registeredFrames do frame:CreateIndicators() end end function Grid2Frame:UpdateIndicators() for _, frame in next, self.registeredFrames do frame:UpdateIndicators() end end function Grid2Frame:UpdateBackdrop() local dbx = self.db.profile local frameBorder = dbx.frameBorder frameBackdrop = Grid2:GetBackdropTable( Grid2:MediaFetch("border", dbx.frameBorderTexture, "Grid2 Flat"), -- edgeFile dbx.frameBorder, -- edgeSize [[Interface\Buttons\WHITE8X8]], -- bgFile true, -- tile 16 -- tileSize ) end function Grid2Frame:LayoutFrames() self:UpdateBackdrop() for name, frame in next, self.registeredFrames do frame:Layout() end self:SendMessage("Grid_UpdateLayoutSize") end function Grid2Frame:GetFrameSize() local p = self.db.profile return p.frameWidth, p.frameHeight end -- Grid2Frame:WithAllFrames() do local type, with = type, {} with["table"] = function(self, object, func, ...) if type(func) == "string" then func = object[func] end for _, frame in next, self.registeredFrames do func(object, frame, ...) end end with["function"] = function(self, func, ...) for _, frame in next, self.registeredFrames do func(frame, ...) end end function Grid2Frame:WithAllFrames(param, ...) with[type(param)](self, param, ...) end end -- shows the default unit tooltip do local TooltipCheck = { Always = function() return false end, Never = function() return true end, OOC = InCombatLockdown } function Grid2Frame:OnFrameEnter(frame) if TooltipCheck[self.db.profile.showTooltip]() then UnitFrame_OnLeave(frame) else UnitFrame_OnEnter(frame) end end function Grid2Frame:OnFrameLeave(frame) UnitFrame_OnLeave(frame) end end -- Frames blink animations management do local blinkDuration function Grid2Frame:SetBlinkEffect(frame, enabled) local anim = frame.blinkAnim if enabled then if not anim then anim = frame:CreateAnimationGroup() local alpha = anim:CreateAnimation("Alpha") alpha:SetOrder(1) alpha:SetChange(-0.9) anim:SetLooping("REPEAT") anim.alpha = alpha frame.blinkAnim = anim end if not anim:IsPlaying() then anim.alpha:SetDuration(blinkDuration) anim:Play() end elseif anim then anim:Stop() end end function Grid2Frame:UpdateBlink() local indicator = Grid2.indicatorPrototype indicator.Update = self.db.profile.blinkType ~= "None" and indicator.UpdateBlink or indicator.UpdateNoBlink blinkDuration = 1 / self.db.profile.blinkFrequency end end -- Event handlers function Grid2Frame:UpdateFrameUnits() for _, frame in next, self.registeredFrames do local old_unit = frame.unit local unit = SecureButton_GetModifiedUnit(frame) if old_unit ~= unit then Grid2:SetFrameUnit(frame, unit) frame.unit = unit frame:UpdateIndicators() end end end function Grid2Frame:UNIT_ENTERED_VEHICLE(_, unit) for frame in next, Grid2:GetUnitFrames(unit) do local old, new = frame.unit, SecureButton_GetModifiedUnit(frame) if old ~= new then Grid2:SetFrameUnit(frame, new) frame.unit = new frame:UpdateIndicators() end end end function Grid2Frame:UNIT_EXITED_VEHICLE(_, unit) local pet = Grid2:GetPetUnitByUnit(unit) or unit for frame in next, Grid2:GetUnitFrames(pet) do local old, new = frame.unit, SecureButton_GetModifiedUnit(frame) if old ~= new then Grid2:SetFrameUnit(frame, new) frame.unit = new frame:UpdateIndicators() end end end function Grid2Frame:Grid_UnitUpdate(_, unit) for frame in next, Grid2:GetUnitFrames(unit) do local old, new = frame.unit, SecureButton_GetModifiedUnit(frame) if old ~= new then Grid2:SetFrameUnit(frame, new) frame.unit = new end frame:UpdateIndicators() end end --}}} _G.Grid2Frame = Grid2Frame -- Allow other modules/addons to easily modify the grid unit frames Grid2Frame.Events = GridFrameEvents Grid2Frame.Prototype = GridFramePrototype