Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 54 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,58 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## How to contribute

1. **Add your changes under the top version block** (`## [@project-version@]`). Never edit older version blocks.
2. **Use the correct sub-header** for your change type:
- `### Message` — release notes / personal message to users
- `### Added` — new features
- `### Changed` — changes to existing behaviour
- `### Fixed` — bug fixes
- `### Removed` — removed features
3. **Write one bullet per change**, starting with `- `. Markdown formatting is supported in-game:
- `**bold**` renders gold, `` `code` `` renders cyan.
4. **Do not touch `ChangelogData.lua`** — it is auto-generated by `.scripts/update_changelog.py` on release.


## [@project-version@] - @project-date-iso@
### New Features
- Datatext Drawer - Click one of the four corners of the screen to open the datatext drawer. Drag and drop them anywhere on-screen. Drag them back into the drawer to disable. Drag the right hand corner to resize them. Will continue to expand on these and you're welcome to suggest more/improve whats been built.

- Meta Talents - Added a new QoL feature to help you keep track of the most popular talents for each spec. Find it in the Quality of Life tab in `/orbit plugins`.
- Select bosses or dungeons to view the most popular talents for that specific encounter, data is fetched and averaged from Warcraft Logs top 100 parses.
- Directly Apply the meta talents to your talent tree with a single click.

### Bugfixes
- Static Cooldown Timer Texts
- Player Buff Item Enhancements now draw a pixel border for item enhancements (weapon oils, etc)
- Player Buffs/Debuffs swipe now start at low alpha and fill as their duration expires
- Player Buffs/Debuffs now pulse in and out when expiring
### TLDR
- Lots of backend changes in this one, some icon frames may need size changes, have moved away from Scale and towards Pixels instead.
- Overhaul of Glows in Orbit, please revise all glows, added more customization options, better alignment and performance. No longer using LibCustomGlow so should resolve a lot of conflicts from other addons.
- Enabled Minimap plugin by default. Remember can disable all plugins in the `Plugin Manager (/orbit plugins)`.
- Added **Datatexts**, **just click one of the four corners of the screen** to open the datatext drawer and drag and drop them anywhere on-screen. Will continue to expand on these and you're welcome to suggest more/improve whats been built.

### Added
- **Datatexts Plugin:** Brand-new standalone plugin with 20+ widgets (Gold, Friends, Guild, Durability, Performance, Hearthstone, Spec, Location, Mail, Quest, Combat Timer, and more). Replaces the old Performance and Combat Timer from Menu Items.
- **Glows:** New custom glow library replacing `LibCustomGlow`. Supports **Pixel**, **Medium**, **Autocast**, **Classic**, **Thin**, **Thick** glow types with full per-type configuration (color, frequency, thickness, line count, particles, scale, and direction).
- **StrataEngine:** Centralized Z-index layering engine for root-level UI containers. Supports `BumpUp`/`BumpDown` reordering persisted to profile, ensuring consistent frame stacking across Edit Mode and Canvas Mode. `This is for future implementation and not currently active, but all strata has been updated to use the new engine.`
- **Group Frame Dispel Glow Type:** Added user-selectable glow types (**Pixel** vs **Autocast**) for dispel indicators on group frames, with per-type settings for thickness, line count, and length.

### Changed
- **Glow System Overhaul:** Migrated all glow rendering (Pandemic, Cooldown Manager, Action Bars, Dispel Indicators) from `LibCustomGlow` to the new `LibOrbitGlow-1.0`.
- **Strata Standardisation:** Replaced all hardcoded strata strings (`"MEDIUM"`, `"TOOLTIP"`, etc.) with `Constants.Strata.*` lookups managed by the StrataEngine.
- **Glow Settings Schema:** Expanded glow configuration panel with per-type sliders (frequency, thickness, particles, scale, line count) that dynamically show/hide based on the selected glow type.
- **Cast Bar Spark:** Player cast bar spark now uses `Pixel:Snap` for sub-pixel–accurate positioning.
- **Unit Health:**: Unit Health now has a checkbox to enable gradient colors instead of colors based on value.
- **UI Changes:** Various tweaks to UI elements and options. Bugfixes too.

### Fixed
- **Minimap Compartment:** Rewrote addon button flyout to use proxy icon buttons instead of reparenting. Fixes dark rendering on LibDBIcon buttons and flyout overlay blocking clicks.
- **Minimap Compartment Flyout:** Mouse-leave detection now checks the Orbit container instead of the raw `Minimap` surface, fixing premature flyout closure when third-party addons reparent the minimap.
- **Minimap Difficulty (Canvas):** Skull icon now renders without the background banner by default. A `Show Background` toggle controls it. Placeholder "25" label anchored directly beneath the skull.
- **Minimap Difficulty Display Dropdown:** Switching between Icon/Text in canvas settings now reflects the correct state. The value was being lost when the dialog reopened.
- **FarmHud Compatibility:** Added `Guard:Suspend`/`Guard:Resume` to `FrameGuard` so cooperating addons can temporarily reparent the minimap surface. Orbit now hooks FarmHud's show/hide to suspend protection, skip surface re-sync in `ApplySettings`, and resume on close — preventing the mount/dismount/shapeshift resource-display loss reported by users.
- **Cast Bar Preview (Sticky):** Fixed Target/Focus cast bar previews persisting on screen after exiting Edit Mode by clearing preview state before hiding and adding combat-exit guards. Hopefully combat stickiness too.
- **Cast Bar Preview (Ticks):** Fixed channel tick marks failing to render in the configuration preview.
- **Healer Aura Filtering:** Fixed healer-tracked auras not being excluded from the general Buffs frame on group frames when `HealerAuras` is enabled.Icon Canvas.
- **CDM:**: Dropping items/spells on the Cooldown Manager frames should be a bit less buggy now.

### Removed
- **Menu Items (CombatTimer & Performance):** Removed standalone `CombatTimer.lua` and `Performance.lua` from Menu Items—functionality replaced by the Datatexts plugin.

### Thanks for your support again! Next update will be focussed on fixing bugs. Hope everyone had a good easter. (Go Echo!)

## [1.0.0] - 2026-03-10
### Added
Expand Down
2 changes: 2 additions & 0 deletions Orbit/Core/CanvasMode/ComponentSettings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ function Settings:OnValueChanged(key, value)
local plugin = self.plugin
local systemIndex = self.systemIndex
local canvasDialog = OrbitEngine.CanvasModeDialog
-- Persist display choice before canvasDialog:Open() restarts the Transaction.
plugin:SetSetting(systemIndex, "DifficultyDisplay", value)
C_Timer.After(0, function()
if not (canvasDialog and plugin and canvasDialog.targetFrame and canvasDialog:IsShown()) then return end
canvasDialog:Open(canvasDialog.targetFrame, canvasDialog.targetPlugin, canvasDialog.targetSystemIndex)
Expand Down
23 changes: 21 additions & 2 deletions Orbit/Core/CanvasMode/Creators/IconFrameCreator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,25 @@ local function Create(container, preview, key, source, data)
end

local attached = 0
local skullTexture -- icon texture reference used to anchor the preview label
-- Respect DifficultyShowBackground: skip Background/Border art when disabled.
local savedOverrides = data and data.overrides or {}
local showBg = savedOverrides.DifficultyShowBackground
if showBg == nil then
local plugin = Orbit:GetPlugin("Orbit_Minimap")
showBg = plugin and plugin:GetSetting("Orbit_Minimap", "DifficultyShowBackground")
end

if activeFrame then
if Attach(activeFrame.Background, 1) then attached = attached + 1 end
if Attach(activeFrame.Border, 1) then attached = attached + 1 end
if showBg then
Attach(activeFrame.Background, 1)
Attach(activeFrame.Border, 1)
end
for _, region in ipairs({ activeFrame:GetRegions() }) do
if region ~= activeFrame.Background and region ~= activeFrame.Border and region:IsShown() and Attach(region) then
attached = attached + 1
local regions = { container.iconVisual:GetRegions() } -- skull anchor: last-created texture
skullTexture = regions[#regions]
break
end
end
Expand All @@ -131,8 +144,14 @@ local function Create(container, preview, key, source, data)
texture:SetSize(source.Icon:GetWidth(), source.Icon:GetHeight())
texture:SetPoint("CENTER", container.iconVisual, "CENTER")
CopyDifficultyTexture(texture, source.Icon, 1)
skullTexture = texture
end

local labelAnchor = skullTexture or container.iconVisual -- placeholder "25" beneath skull
local previewLabel = container.iconVisual:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
previewLabel:SetText("25")
previewLabel:SetPoint("TOP", labelAnchor, "BOTTOM", 0, 2)

local function UpdateDifficultySize(self, size)
local targetWidth = (size and size > 0) and size or baseWidth
local scale = (baseWidth > 0) and (targetWidth / baseWidth) or 1
Expand Down
16 changes: 14 additions & 2 deletions Orbit/Core/EditMode/Frame/Guard.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function Guard:Protect(frame, parent)

if not frame._orbitGuardHooked then
hooksecurefunc(frame, "SetParent", function(s, p)
if s._orbitRestoring then return end
if s._orbitRestoring or s._orbitGuardSuspended then return end
local intended = s._orbitGuardParent
if intended and p ~= intended then
s._orbitRestoring = true
Expand All @@ -24,7 +24,7 @@ function Guard:Protect(frame, parent)
end)

frame:HookScript("OnHide", function(s)
if s._orbitRestoring then return end
if s._orbitRestoring or s._orbitGuardSuspended then return end
if s._orbitGuardEnforceShow then
s._orbitRestoring = true
s:Show()
Expand All @@ -37,6 +37,18 @@ function Guard:Protect(frame, parent)
end
end

-- [ SUSPEND / RESUME ]------------------------------------------------------------------------------
-- Disables guard enforcement without removing hooks (e.g. FarmHud owns the surface temporarily).
function Guard:Suspend(frame)
if not frame then return end
frame._orbitGuardSuspended = true
end

function Guard:Resume(frame)
if not frame then return end
frame._orbitGuardSuspended = nil
end

-- [ UPDATE ]----------------------------------------------------------------------------------------

function Guard:UpdateProtection(frame, parent, onRestoreFunc, options)
Expand Down
48 changes: 45 additions & 3 deletions Orbit/Plugins/Minimap/Minimap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,11 @@ function Plugin:OnLoad()
isFontString = true,
onPositionChange = MPC("Coords"),
})
OrbitEngine.ComponentDrag:Attach(self._compartmentButton, self.frame, { key = "Compartment", onPositionChange = MPC("Compartment") })
OrbitEngine.ComponentDrag:Attach(self._compartmentButton, self.frame, {
key = "Compartment",
sourceOverride = self._compartmentButton.icon,
onPositionChange = MPC("Compartment"),
})
OrbitEngine.ComponentDrag:Attach(self.frame.ZoomContainer, self.frame, { key = "Zoom", onPositionChange = MPC("Zoom") })
if self.frame.DifficultyIcon then OrbitEngine.ComponentDrag:Attach(self.frame.DifficultyIcon, self.frame, { key = DIFFICULTY_ICON_KEY, onPositionChange = MPC(DIFFICULTY_ICON_KEY) }) end
if self.frame.DifficultyText then
Expand Down Expand Up @@ -520,6 +524,42 @@ function Plugin:UpdateDifficultyVisuals(textMultiplier)
end
end

if not iconFrame.PreviewIcon then
iconFrame.PreviewIcon = iconFrame:CreateTexture(nil, "OVERLAY")
-- Use the 25 player difficulty skull
iconFrame.PreviewIcon:SetTexture("Interface\\Minimap\\UI-DungeonDifficulty-Button")
iconFrame.PreviewIcon:SetTexCoord(0.5, 0.75, 0.0703125, 0.4140625)
iconFrame.PreviewIcon:SetSize(18, 18)
iconFrame.PreviewIcon:SetPoint("CENTER", iconFrame, "CENTER", 0.5, 0.5)
end
if not iconFrame.PreviewText then
iconFrame.PreviewText = iconFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
iconFrame.PreviewText:SetText("25")
iconFrame.PreviewText:SetPoint("TOP", iconFrame.PreviewIcon, "BOTTOM", -1, 4)
end

local realIconShown = false
if difficulty:IsShown() or mode == "icon" then
for _, sub in ipairs({ difficulty.Default, difficulty.Guild, difficulty.ChallengeMode }) do
if sub and sub:IsShown() then
for _, region in ipairs({ sub:GetRegions() }) do
if region and region:GetObjectType() == "Texture" and region:IsShown() and region ~= sub.Background and region ~= sub.Border then
realIconShown = true
break
end
end
end
end
end

if keepVisible and not realIconShown and mode == "icon" then
iconFrame.PreviewIcon:Show()
iconFrame.PreviewText:Show()
else
iconFrame.PreviewIcon:Hide()
iconFrame.PreviewText:Hide()
end

iconFrame.orbitOriginalWidth = difficulty.orbitOriginalWidth or iconFrame.orbitOriginalWidth or 16
iconFrame.orbitOriginalHeight = difficulty.orbitOriginalHeight or iconFrame.orbitOriginalHeight or 16
iconFrame:SetScale(1)
Expand Down Expand Up @@ -566,8 +606,9 @@ function Plugin:ApplySettings()
SetCVar("rotateMinimap", rotate and "1" or "0")

-- Keep the Minimap render surface in sync with the container.
-- Skip when FarmHud is active — it owns the surface position/size while its HUD is open.
local minimapSurface = self:GetBlizzardMinimap()
if minimapSurface then
if minimapSurface and not self._farmHudActive then
minimapSurface._orbitIntendedSize = size
-- Micro-size bounce for C++ redraw
minimapSurface:SetSize(size - 1, size - 1)
Expand Down Expand Up @@ -714,8 +755,9 @@ function Plugin:ApplySettings()
OrbitEngine.Frame:RestorePosition(frame, self, SYSTEM_ID)

-- Ensure minimap is captured (e.g. after reload).
-- Skip when FarmHud is active — it legitimately reparented the minimap for its HUD overlay.
local minimap = self:GetBlizzardMinimap()
if minimap and minimap:GetParent() ~= frame then
if minimap and minimap:GetParent() ~= frame and not self._farmHudActive then
self:CaptureBlizzardMinimap()
end

Expand Down
65 changes: 49 additions & 16 deletions Orbit/Plugins/Minimap/MinimapCapture.lua
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,7 @@ function Plugin:ReparentBlizzardComponents()
craftingOrder.Icon = craftingOrder:CreateTexture(nil, "ARTWORK")
craftingOrder.Icon:SetSize(20, 20)
craftingOrder.Icon:SetPoint("CENTER")

local info = C_Texture.GetAtlasInfo("UI-HUD-Minimap-CraftingOrder-Over-2x")
if info and info.file then
craftingOrder.Icon:SetTexture(info.file)
craftingOrder.Icon:SetTexCoord(info.leftTexCoord, info.rightTexCoord, info.topTexCoord, info.bottomTexCoord)
else
craftingOrder.Icon:SetAtlas("UI-HUD-Minimap-CraftingOrder-Over-2x", true)
end
craftingOrder.Icon:SetAtlas("UI-HUD-Minimap-CraftingOrder-Over-2x", true)

-- Ignore native scaling so the atlas stays crisp
craftingOrder.Icon:SetScale(1)
Expand Down Expand Up @@ -380,7 +373,7 @@ function Plugin:CaptureBlizzardMinimap()
-- the minimap away from our intended values.
if not minimap._orbitSetPointHooked then
hooksecurefunc(minimap, "SetPoint", function(f, ...)
if f._orbitRestoringPoint then return end
if f._orbitRestoringPoint or f._orbitGuardSuspended then return end
if f:GetParent() == self.frame then
local point = ...
local relFrame = select(2, ...)
Expand All @@ -394,7 +387,7 @@ function Plugin:CaptureBlizzardMinimap()
end
end)
hooksecurefunc(minimap, "SetSize", function(f, w, h)
if f._orbitRestoringPoint then return end
if f._orbitRestoringPoint or f._orbitGuardSuspended then return end
if f:GetParent() == self.frame then
local intended = self.frame:GetWidth()
if intended and (math.abs(w - intended) > 0.5 or math.abs(h - intended) > 0.5) then
Expand All @@ -411,12 +404,9 @@ function Plugin:CaptureBlizzardMinimap()
-- a MEDIUM-strata Button with SetPropagateMouseClicks(true) that covers the whole
-- minimap area and sits above most third-party overlays. No per-frame hook needed.

-- FarmHud integration: register our container so FarmHud knows about it.
C_Timer.After(0, function()
if FarmHud and FarmHud.RegisterForeignAddOnObject then
FarmHud:RegisterForeignAddOnObject(self.frame, "Orbit")
end
end)
-- FarmHud integration: register our container and hook show/hide to suspend
-- FrameGuard protection so FarmHud can reparent the minimap surface freely.
self:HookFarmHud()

-- Update zoom button state after scroll-wheel zoom
if not minimap._orbitScrollHooked then
Expand All @@ -429,3 +419,46 @@ function Plugin:CaptureBlizzardMinimap()

self._captured = true
end

-- [ FARMHUD COMPATIBILITY ]-------------------------------------------------------------------------
-- Suspend FrameGuard and surface-sync while FarmHud owns the Minimap. See readme for details.

function Plugin:HookFarmHud()
if self._farmHudHooked then return end

-- Deferred: FarmHud may load after Orbit.
C_Timer.After(0, function()
if not FarmHud then return end

FarmHud:RegisterForeignAddOnObject(self.frame, "Orbit")

-- Hook OnShow/OnHide only once.
if not self._farmHudHooked then
FarmHud:HookScript("OnShow", function() self:OnFarmHudShow() end)
FarmHud:HookScript("OnHide", function() self:OnFarmHudHide() end)
self._farmHudHooked = true
end
end)
end

function Plugin:OnFarmHudShow()
self._farmHudActive = true

local minimap = self:GetBlizzardMinimap()
if minimap then
OrbitEngine.FrameGuard:Suspend(minimap)
end
end

function Plugin:OnFarmHudHide()
self._farmHudActive = nil

local minimap = self:GetBlizzardMinimap()
if minimap then
OrbitEngine.FrameGuard:Resume(minimap)
end

-- Re-apply settings to recapture the minimap surface and restore our layout.
self:ApplySettings()
end

Loading