diff --git a/CHANGELOG.md b/CHANGELOG.md index 385c814..d2c76d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ Changes in this fork (OEVG/ShaguTweaks-ClassicAPI), newest first. The addon has This fork is based on [Dusk/ShaguTweaks-ClassicAPI](https://octowow.st/git/Dusk/ShaguTweaks-ClassicAPI) at commit `4391564` (2026-09-08). Earlier changes are in that repository's history. +## 2026-11-02 — Map window, Transports button and Loot History + +### Added + +- **Loot History** (Loot, on): `/loothistory` opens a window with the recent group-loot rolls. Each item shows who won it with which roll; click it to see everyone's need, greed or pass and their rolls. A Clear button empties the list. Ported from brues-code/pfUI's loot history and drawn with the classic dialog look. Needs ClassicAPI's `C_LootHistory`, which keeps the last 128 rolled items through `/reload`. +- **WorldMap Window:** when [OctoBus](https://github.com/Phridgey/OctoBus) is installed, a **Transports** button left of the Continent dropdown shows or hides the OctoBus window, like a left-click on its minimap icon. While the map is open, the OctoBus window is drawn above it. + +### Fixed + +- **WorldMap Window:** the map keeps the size picked with Ctrl+Mousewheel after closing and reopening it, and after a reload. It used to go back to the default size every time it opened. +- **WorldMap Window:** the title bar drags the window too. On Turtle WoW the title is drawn above the window's edge, so only the dropdown row could be dragged before. + ## 2026-11-01 — Swing Timer and Wand Timer ### Added diff --git a/README.md b/README.md index ccc459d..89ac26b 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Settings: **Esc → Advanced Options**. - **Range Color:** self/rangeless spells no longer use a misleading legacy fallback; invalid friendly/hostile target checks and stale red/no-mana tint are handled. No additional AoE-specific exceptions have been added. The range check runs five times a second instead of every frame. - **XP Bar Text:** hovering the experience bar shows current and needed XP like the reputation bar (`1555/3000`), then the percentage and the rested bonus. - **WorldMap Class Colors:** raid members on the world map and battlefield minimap show their own class color. +- **WorldMap Window:** the map keeps the size you pick with Ctrl+Mousewheel (saved per character), and the title bar drags the window as well. With [OctoBus](https://github.com/Phridgey/OctoBus) installed, a **Transports** button left of the Continent dropdown shows or hides its transport timers. +- **Loot History:** `/loothistory` lists recent group-loot rolls with the winner of each item; click an item for everyone's need, greed or pass and their rolls. Ported from [brues-code/pfUI](https://github.com/brues-code/pfUI). Requires ClassicAPI. **Performance and stability** @@ -78,6 +80,7 @@ Modules that use ClassicAPI directly: - Improved Castbar - Item Rarity Borders - Item Rarity Glows +- Loot History - Movable Unit Frames - Real Health Numbers - Nameplate Class Colors @@ -165,6 +168,7 @@ Names match the in-game options list. Modules marked *(off)* are disabled until - AoE Loot *(off)* - Improved Roll Frames *(off)* - Loot Cursor +- Loot History (`/loothistory`) ### Interface @@ -217,7 +221,7 @@ Special thanks to **Jesper_92** for reporting issues that helped improve the add Additional code and ideas from **pfUI** and **zUI**. -Swing Timer and Wand Timer ported from **brues-code/pfUI** (MIT, Shagu and contributors). +Swing Timer, Wand Timer and Loot History ported from **brues-code/pfUI** (MIT, Shagu and contributors). Extended Movable Unit Frames support adapted from **TokensWorth/ShaguTweaks-mods**, originally released under MIT by **GryllsAddons**. See `THIRD_PARTY_NOTICES.md`. diff --git a/ShaguTweaks.toc b/ShaguTweaks.toc index 86040a7..1f1742c 100644 --- a/ShaguTweaks.toc +++ b/ShaguTweaks.toc @@ -79,6 +79,7 @@ mods\reduced-actionbar.lua mods\no-toggle.lua mods\aoe-loot.lua mods\loot-cursor.lua +mods\loot-history.lua mods\improved-roll-frames.lua mods\improved-castbar.lua mods\swing-timer.lua diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 74083ce..0e399b3 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -39,9 +39,11 @@ The preserved license text is stored in ## brues-code/pfUI The Swing Timer and Wand Timer in `mods/swing-timer.lua` are ported from -pfUI's swing timer module and restyled: +pfUI's swing timer module and restyled, and the Loot History window in +`mods/loot-history.lua` is ported from pfUI's loot history module and rebuilt +with stock 1.12 widgets: -- Upstream module: `modules/swingtimer.lua` +- Upstream modules: `modules/swingtimer.lua`, `modules/loothistory.lua` - Source: https://github.com/brues-code/pfUI - Copyright (c) 2016-2021 Eric Mauser (Shagu) and contributors - License: MIT diff --git a/locales/translations_enUS.lua b/locales/translations_enUS.lua index bff38ad..8a84a6a 100644 --- a/locales/translations_enUS.lua +++ b/locales/translations_enUS.lua @@ -92,4 +92,13 @@ ShaguTweaks_translation["enUS"] = { ["Ranged"] = nil, ["Shows main-hand and off-hand swing timers above the cast bar, with the weapon's icon. Hold , and to move them; right-click to reset."] = nil, ["Shows the time until your next wand shot (or Auto Shot) above the cast bar, with the weapon's icon."] = nil, + ["Transports"] = nil, + ["Shows or hides the OctoBus transport timers."] = nil, + ["Loot History"] = nil, + ["Adds /loothistory: a window with the need, greed and pass rolls of recent group loot and who won each item. Requires ClassicAPI."] = nil, + ["Retrieving item information..."] = nil, + ["All players passed"] = nil, + ["Clear"] = nil, + ["No loot rolls yet."] = nil, + ["Loot History requires ClassicAPI."] = nil, } diff --git a/mods/loot-history.lua b/mods/loot-history.lua new file mode 100644 index 0000000..ca1cb98 --- /dev/null +++ b/mods/loot-history.lua @@ -0,0 +1,393 @@ +-- Loot History: a window with the recent group-loot rolls and who won them. +-- Ported from brues-code/pfUI's loothistory module (MIT, Shagu and +-- contributors), rebuilt with stock 1.12 widgets for the classic look. + +local _G = ShaguTweaks.GetGlobalEnv() +local T = ShaguTweaks.T + +local module = ShaguTweaks:register({ + title = T["Loot History"], + description = T["Adds /loothistory: a window with the need, greed and pass rolls of recent group loot and who won each item. Requires ClassicAPI."], + expansions = { ["vanilla"] = true }, + category = T["Loot"], + enabled = true, +}) + +local WIDTH, HEIGHT = 340, 400 +local ROW_H, ROWS = 20, 16 +local PLAYER_INDENT = 22 + +-- rollType from C_LootHistory.GetPlayerInfo: 0 pass, 1 need, 2 greed. +local ROLL_PASS, ROLL_NEED, ROLL_GREED = 0, 1, 2 +local ROLL_TEX = { + [ROLL_NEED] = "Interface\\Buttons\\UI-GroupLoot-Dice-Up", + [ROLL_GREED] = "Interface\\Buttons\\UI-GroupLoot-Coin-Up", + [ROLL_PASS] = "Interface\\Buttons\\UI-GroupLoot-Pass-Up", +} +local WINMARK = "Interface\\Buttons\\UI-CheckBox-Check" +local QUESTIONMARK = "Interface\\Icons\\INV_Misc_QuestionMark" + +local function Supported() + local lh = _G.C_LootHistory + return type(lh) == "table" and type(lh.GetNumItems) == "function" + and type(lh.GetItem) == "function" and type(lh.GetPlayerInfo) == "function" +end + +-- name, quality and icon of an item link; nil while it is not cached yet. +local function ItemVisual(link) + local name, quality, texture, _ + if _G.C_Item and type(_G.C_Item.GetItemInfo) == "function" then + name, _, quality, _, _, _, _, _, _, texture = _G.C_Item.GetItemInfo(link) + else + name, _, quality, _, _, _, _, _, texture = _G.GetItemInfo(link) + end + return name, quality, texture +end + +local function QualityColor(quality) + if quality and GetItemQualityColor then + local r, g, b = GetItemQualityColor(quality) + if r then return r, g, b end + end + local c = quality and ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[quality] + if c then return c.r, c.g, c.b end + return 1, 1, 1 +end + +local function ClassColor(class) + local c = class and RAID_CLASS_COLORS and RAID_CLASS_COLORS[class] + if c then return c.r, c.g, c.b end + return .8, .8, .8 +end + +-- While a roll is open everyone is listed. Once decided, only players who +-- rolled and yourself stay, as in the later clients' loot history. +local function ShouldDisplayPlayer(isDone, roll, isMe) + return isMe or (roll and roll > 0) or not isDone +end + +local frame, scroll, rows, empty +local expanded = {} -- keyed on the stable rollID +local list = {} +local pendingItems + +local Update + +local function ToggleExpanded(rollID) + if not rollID then return end + expanded[rollID] = not expanded[rollID] + Update() +end + +local function BuildList() + local lh = _G.C_LootHistory + local n = 0 + + for i = 1, lh.GetNumItems() do + local rollID, _, numPlayers, isDone = lh.GetItem(i) + n = n + 1 + list[n] = list[n] or {} + list[n].item, list[n].player = i, nil + + if rollID and expanded[rollID] then + for p = 1, numPlayers or 0 do + local _, _, _, roll, _, isMe = lh.GetPlayerInfo(i, p) + if ShouldDisplayPlayer(isDone, roll, isMe) then + n = n + 1 + list[n] = list[n] or {} + list[n].item, list[n].player = i, p + end + end + end + end + + for i = n + 1, table.getn(list) do list[i] = nil end + return n +end + +local function ShowItemRow(row, index) + local lh = _G.C_LootHistory + local rollID, link, numPlayers, isDone, winner = lh.GetItem(index) + + row.rollID, row.link = rollID, link + row.player:Hide() + row.itemrow:Show() + + local r = row.itemrow + if numPlayers and numPlayers > 0 then + if expanded[rollID] then + r.toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up") + r.toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-Down") + else + r.toggle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up") + r.toggle:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-Down") + end + r.toggle:Show() + else + r.toggle:Hide() + end + + local name, quality, texture + if link then name, quality, texture = ItemVisual(link) end + if name then + r.icon:SetTexture(texture or QUESTIONMARK) + r.name:SetText(name) + r.name:SetTextColor(QualityColor(quality)) + else + pendingItems = true + r.icon:SetTexture(QUESTIONMARK) + r.name:SetText(T["Retrieving item information..."]) + r.name:SetTextColor(1, .3, .3) + end + + -- winner summary on a decided, collapsed row + if isDone and not expanded[rollID] then + if winner then + local wname, wclass, wtype, wroll = lh.GetPlayerInfo(index, winner) + r.winicon:SetTexture(ROLL_TEX[wtype] or ROLL_TEX[ROLL_NEED]) + r.winroll:SetText(wroll and wroll > 0 and tostring(wroll) or "") + r.winname:SetText(wname or UNKNOWN) + r.winname:SetTextColor(ClassColor(wclass)) + else + r.winicon:SetTexture(ROLL_TEX[ROLL_PASS]) + r.winroll:SetText("") + r.winname:SetText(T["All players passed"]) + r.winname:SetTextColor(1, .4, .4) + end + r.winicon:Show() + r.winroll:Show() + r.winname:Show() + else + r.winicon:Hide() + r.winroll:Hide() + r.winname:Hide() + end +end + +local function ShowPlayerRow(row, index, player) + local name, class, rollType, roll, isWinner = _G.C_LootHistory.GetPlayerInfo(index, player) + + row.rollID, row.link = nil, nil + row.itemrow:Hide() + row.player:Show() + + local p = row.player + p.name:SetText(name or UNKNOWN) + p.name:SetTextColor(ClassColor(class)) + + if rollType and ROLL_TEX[rollType] then + p.rollicon:SetTexture(ROLL_TEX[rollType]) + p.rollicon:Show() + else + -- not voted yet + p.rollicon:Hide() + end + p.rolltext:SetText(roll and roll > 0 and tostring(roll) or "") + + if isWinner then p.winmark:Show() else p.winmark:Hide() end +end + +Update = function() + if not frame or not frame:IsShown() then return end + + pendingItems = nil + local total = BuildList() + FauxScrollFrame_Update(scroll, total, ROWS, ROW_H) + local offset = FauxScrollFrame_GetOffset(scroll) or 0 + + for i = 1, ROWS do + local row = rows[i] + local entry = list[i + offset] + if entry then + if entry.player then + ShowPlayerRow(row, entry.item, entry.player) + else + ShowItemRow(row, entry.item) + end + row:Show() + else + row.rollID, row.link = nil, nil + row:Hide() + end + end + + if total == 0 then empty:Show() else empty:Hide() end +end + +local function CreateRow(parent, i) + local row = CreateFrame("Button", nil, parent) + row:SetHeight(ROW_H) + row:SetPoint("TOPLEFT", scroll, "TOPLEFT", 0, -(i - 1) * ROW_H) + row:SetPoint("RIGHT", scroll, "RIGHT", 0, 0) + + local highlight = row:CreateTexture(nil, "HIGHLIGHT") + highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") + highlight:SetBlendMode("ADD") + highlight:SetAllPoints(row) + highlight:SetAlpha(.5) + + -- item row parts + local r = CreateFrame("Frame", nil, row) + r:SetAllPoints(row) + row.itemrow = r + + r.toggle = CreateFrame("Button", nil, r) + r.toggle:SetWidth(14) + r.toggle:SetHeight(14) + r.toggle:SetPoint("LEFT", 2, 0) + r.toggle:SetHighlightTexture("Interface\\Buttons\\UI-PlusButton-Hilight", "ADD") + r.toggle:SetScript("OnClick", function() ToggleExpanded(row.rollID) end) + + r.icon = r:CreateTexture(nil, "ARTWORK") + r.icon:SetWidth(16) + r.icon:SetHeight(16) + r.icon:SetPoint("LEFT", 20, 0) + r.icon:SetTexCoord(.08, .92, .08, .92) + + r.winicon = r:CreateTexture(nil, "OVERLAY") + r.winicon:SetWidth(16) + r.winicon:SetHeight(16) + r.winicon:SetPoint("RIGHT", r, "RIGHT", -2, 0) + + r.winroll = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") + r.winroll:SetPoint("RIGHT", r.winicon, "LEFT", -2, 0) + + r.winname = r:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") + r.winname:SetPoint("RIGHT", r.winroll, "LEFT", -4, 0) + r.winname:SetWidth(90) + r.winname:SetJustifyH("RIGHT") + + r.name = r:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") + r.name:SetPoint("LEFT", r.icon, "RIGHT", 5, 0) + r.name:SetPoint("RIGHT", r, "RIGHT", -120, 0) + r.name:SetHeight(ROW_H) + r.name:SetJustifyH("LEFT") + + -- player row parts + local p = CreateFrame("Frame", nil, row) + p:SetAllPoints(row) + row.player = p + + p.winmark = p:CreateTexture(nil, "OVERLAY") + p.winmark:SetWidth(16) + p.winmark:SetHeight(16) + p.winmark:SetTexture(WINMARK) + p.winmark:SetPoint("LEFT", PLAYER_INDENT, 0) + + p.name = p:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") + p.name:SetPoint("LEFT", PLAYER_INDENT + 18, 0) + p.name:SetJustifyH("LEFT") + + p.rollicon = p:CreateTexture(nil, "OVERLAY") + p.rollicon:SetWidth(16) + p.rollicon:SetHeight(16) + p.rollicon:SetPoint("RIGHT", p, "RIGHT", -2, 0) + + p.rolltext = p:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") + p.rolltext:SetPoint("RIGHT", p.rollicon, "LEFT", -3, 0) + + row:SetScript("OnClick", function() ToggleExpanded(this.rollID) end) + row:SetScript("OnEnter", function() + if this.link then + GameTooltip:SetOwner(this, "ANCHOR_RIGHT") + GameTooltip:SetHyperlink(this.link) + GameTooltip:Show() + end + end) + row:SetScript("OnLeave", function() GameTooltip:Hide() end) + + return row +end + +local function CreateWindow() + frame = CreateFrame("Frame", "ShaguTweaksLootHistory", UIParent) + frame:SetFrameStrata("DIALOG") + frame:SetWidth(WIDTH) + frame:SetHeight(HEIGHT) + frame:SetPoint("CENTER", 0, 0) + frame:SetMovable(true) + frame:SetClampedToScreen(true) + frame:EnableMouse(true) + frame:RegisterForDrag("LeftButton") + frame:SetScript("OnDragStart", function() this:StartMoving() end) + frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end) + frame:SetBackdrop({ + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, tileSize = 32, edgeSize = 32, + insets = { left = 11, right = 12, top = 12, bottom = 11 }, + }) + frame:Hide() + table.insert(UISpecialFrames, "ShaguTweaksLootHistory") + + local header = frame:CreateTexture(nil, "ARTWORK") + header:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header") + header:SetWidth(256) + header:SetHeight(64) + header:SetPoint("TOP", 0, 12) + + local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal") + title:SetPoint("TOP", header, "TOP", 0, -14) + title:SetText(T["Loot History"]) + + local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton") + close:SetPoint("TOPRIGHT", -5, -5) + + local clear = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate") + clear:SetWidth(80) + clear:SetHeight(22) + clear:SetPoint("BOTTOMRIGHT", -16, 14) + clear:SetText(T["Clear"]) + clear:SetScript("OnClick", function() + if type(_G.C_LootHistory.Clear) == "function" then + _G.C_LootHistory.Clear() + end + Update() + end) + if type(_G.C_LootHistory.Clear) ~= "function" then clear:Hide() end + + scroll = CreateFrame("ScrollFrame", "ShaguTweaksLootHistoryScroll", frame, "FauxScrollFrameTemplate") + scroll:SetPoint("TOPLEFT", 18, -32) + scroll:SetPoint("BOTTOMRIGHT", -40, 44) + scroll:SetScript("OnVerticalScroll", function() + FauxScrollFrame_OnVerticalScroll(ROW_H, Update) + end) + + rows = {} + for i = 1, ROWS do rows[i] = CreateRow(frame, i) end + + empty = frame:CreateFontString(nil, "OVERLAY", "GameFontDisable") + empty:SetPoint("CENTER", 0, 0) + empty:SetText(T["No loot rolls yet."]) + + frame:SetScript("OnShow", Update) + + -- Only redraw while the window is open; the history itself is kept by + -- ClassicAPI (last 128 items, through /reload, cleared at logout). + frame:RegisterEvent("LOOT_HISTORY_FULL_UPDATE") + frame:RegisterEvent("LOOT_HISTORY_ROLL_COMPLETE") + frame:RegisterEvent("LOOT_HISTORY_ROLL_CHANGED") + frame:RegisterEvent("GET_ITEM_INFO_RECEIVED") + frame:SetScript("OnEvent", function() + if event == "GET_ITEM_INFO_RECEIVED" and not pendingItems then return end + Update() + end) +end + +local function Toggle() + if not Supported() then + DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00ShaguTweaks:|r " .. T["Loot History requires ClassicAPI."]) + return + end + if not frame then CreateWindow() end + if frame:IsShown() then frame:Hide() else frame:Show() end +end + +module.enable = function(self) + -- pfUI ships the same command; leave it alone when pfUI already owns it. + if SlashCmdList["PFLOOTHISTORY"] then return end + + SLASH_SHAGULOOTHISTORY1 = "/loothistory" + SlashCmdList["SHAGULOOTHISTORY"] = Toggle + ShaguTweaks.ToggleLootHistory = Toggle +end diff --git a/mods/turtle-wow.lua b/mods/turtle-wow.lua index b229755..71bc23f 100644 --- a/mods/turtle-wow.lua +++ b/mods/turtle-wow.lua @@ -45,7 +45,8 @@ module.enable = function(self) WorldMapFrame:SetMovable(true) WorldMapFrame:EnableMouse(true) - WorldMapFrame:SetScale(.85) + -- Keep the size picked with Ctrl + Mousewheel (saved by WorldMap Window). + WorldMapFrame:SetScale(ShaguTweaks.GetWorldMapScale and ShaguTweaks.GetWorldMapScale() or .85) WorldMapFrame:ClearAllPoints() WorldMapFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 30) WorldMapFrame:SetWidth(WorldMapButton:GetWidth() + 15) @@ -54,6 +55,11 @@ module.enable = function(self) -- overwrite wrong title position set by turtlewow WorldMapFrameTitle:SetPoint("TOP", WorldMapFrame, 0, 17) + -- The title now sits above the frame: let the title bar drag it too. + if ShaguTweaks.UpdateWorldMapDragArea then + ShaguTweaks.UpdateWorldMapDragArea() + end + BlackoutWorld:Hide() end end diff --git a/mods/worldmap-window.lua b/mods/worldmap-window.lua index 06ba61d..3652250 100644 --- a/mods/worldmap-window.lua +++ b/mods/worldmap-window.lua @@ -11,6 +11,9 @@ local module = ShaguTweaks:register({ enabled = true, }) +local DEFAULT_SCALE = .85 +local MIN_SCALE, MAX_SCALE = .4, 2 + local function AddSpecialFrame(name) for i = 1, table.getn(UISpecialFrames) do if UISpecialFrames[i] == name then return end @@ -18,6 +21,123 @@ local function AddSpecialFrame(name) table.insert(UISpecialFrames, name) end +-- The scale chosen with Ctrl + Mousewheel is saved per character, so the map +-- reopens (and survives a reload) at the size it was left at. +local function GetSavedScale() + local scale = ShaguTweaks_config and tonumber(ShaguTweaks_config["WorldMapScale"]) + if not scale then return DEFAULT_SCALE end + if scale < MIN_SCALE then return MIN_SCALE end + if scale > MAX_SCALE then return MAX_SCALE end + return scale +end + +local function SaveScale(scale) + if not ShaguTweaks_config then return end + ShaguTweaks_config["WorldMapScale"] = scale +end + +-- Turtle WoW Compatibility re-applies the window layout after Turtle's own +-- WorldMapFrame_Maximize and uses this instead of a fixed scale. +ShaguTweaks.GetWorldMapScale = GetSavedScale + +-- The window's title bar is drawn above the frame's top edge (Turtle places +-- the title 17 units above it), so clicks there missed the frame and only +-- the dropdown row could be dragged. Extend the frame's clickable area up to +-- the top of the title. The close and minimize buttons are child frames on +-- a higher level, so they keep their clicks. +local TITLE_MARGIN = 6 + +local function TitleHeightAboveFrame() + local title = WorldMapFrameTitle + if not title then return 0 end + + -- Prefer the anchor: exact, and valid before the layout is computed. + local count = title.GetNumPoints and title:GetNumPoints() or 1 + for i = 1, count do + local point, relativeTo, relativePoint, _, y = title:GetPoint(i) + if point == "TOP" and relativeTo == WorldMapFrame + and (relativePoint == nil or relativePoint == "TOP") and y then + return y + end + end + + local frameTop, titleTop = WorldMapFrame:GetTop(), title:GetTop() + if frameTop and titleTop then return titleTop - frameTop end + return 0 +end + +local function UpdateDragArea() + local extra = TitleHeightAboveFrame() + if extra > 0 then + extra = math.floor(extra + TITLE_MARGIN + .5) + if extra > 40 then extra = 40 end + else + extra = 0 + end + + WorldMapFrame:SetHitRectInsets(0, 0, -extra, 0) +end + +ShaguTweaks.UpdateWorldMapDragArea = UpdateDragArea + +-- OctoBus (github.com/Phridgey/OctoBus) shows transport timers. When it is +-- loaded, add a "Transports" button in front of the Continent dropdown that +-- toggles its window, the same as a left-click on its minimap icon. +local function OctoBusAvailable() + return OctoBusPanel and SlashCmdList and SlashCmdList["OCTOBUS"] and true or false +end + +local function CreateTransportsButton() + if module.transports or not OctoBusAvailable() then return end + if not WorldMapContinentDropDown or not WorldMapZoomOutButton then return end + + local button = CreateFrame("Button", "ShaguTweaksWorldMapTransports", WorldMapFrame, "UIPanelButtonTemplate") + button:SetWidth(WorldMapZoomOutButton:GetWidth() or 110) + button:SetHeight(WorldMapZoomOutButton:GetHeight() or 22) + -- Mirror of the Zoom Out button, which sits 10 units into the zone + -- dropdown's transparent right edge and 3 units higher. + button:SetPoint("RIGHT", WorldMapContinentDropDown, "LEFT", 10, 3) + button:SetText(T["Transports"]) + + -- OctoBus' window lives on the MEDIUM strata, behind the full-screen map. + -- Lift it above the map while both are open (also when OctoBus opens it + -- by itself at a dock), and give it its own strata back afterwards. + local function RaisePanel() + if not WorldMapFrame:IsShown() or not OctoBusPanel:IsShown() then return end + if not module.panelStrata then + module.panelStrata = OctoBusPanel:GetFrameStrata() + end + OctoBusPanel:SetFrameStrata("FULLSCREEN_DIALOG") + end + + local function RestorePanel() + if module.panelStrata then + OctoBusPanel:SetFrameStrata(module.panelStrata) + module.panelStrata = nil + end + end + + HookScript(WorldMapFrame, "OnShow", RaisePanel) + HookScript(WorldMapFrame, "OnHide", RestorePanel) + HookScript(OctoBusPanel, "OnShow", RaisePanel) + + button:SetScript("OnClick", function() + -- OctoBus' "/ob" without arguments is the same toggle as its icon. + SlashCmdList["OCTOBUS"]("") + RaisePanel() + end) + + button:SetScript("OnEnter", function() + GameTooltip:SetOwner(this, "ANCHOR_BOTTOM") + GameTooltip:SetText(T["Transports"]) + GameTooltip:AddLine(T["Shows or hides the OctoBus transport timers."], 1, 1, 1, 1) + GameTooltip:Show() + end) + button:SetScript("OnLeave", function() GameTooltip:Hide() end) + + module.transports = button +end + module.enable = function(self) -- Only advertise the window as active after the delayed compatibility check. -- Turtle WoW consumes this flag instead of looking at config alone. @@ -65,14 +185,19 @@ module.enable = function(self) HookScript(WorldMapFrame, "OnShow", function() this:EnableKeyboard(false) this:EnableMouseWheel(1) - WorldMapFrame:SetScale(.85) + WorldMapFrame:SetScale(GetSavedScale()) + UpdateDragArea() end) HookScript(WorldMapFrame, "OnMouseWheel", function() if API.IsShiftKeyDown() then WorldMapFrame:SetAlpha(WorldMapFrame:GetAlpha() + arg1 / 10) elseif API.IsControlKeyDown() then - WorldMapFrame:SetScale(WorldMapFrame:GetScale() + arg1 / 10) + local scale = WorldMapFrame:GetScale() + arg1 / 10 + if scale < MIN_SCALE then scale = MIN_SCALE end + if scale > MAX_SCALE then scale = MAX_SCALE end + WorldMapFrame:SetScale(scale) + SaveScale(scale) end end) @@ -88,12 +213,15 @@ module.enable = function(self) WorldMapFrame:SetMovable(true) WorldMapFrame:EnableMouse(true) - WorldMapFrame:SetScale(.85) + WorldMapFrame:SetScale(GetSavedScale()) WorldMapFrame:ClearAllPoints() WorldMapFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 30) WorldMapFrame:SetWidth(WorldMapButton:GetWidth() + 15) WorldMapFrame:SetHeight(WorldMapButton:GetHeight() + 55) BlackoutWorld:Hide() + UpdateDragArea() + + CreateTransportsButton() -- Initialization is complete. Keeping this event registered would repeat -- the full layout work on every loading screen and reset a moved window.