├── .pkgmeta ├── Textures ├── Buttons.blp ├── TrinketMenu-Gear.blp ├── TrinketMenu-Icon-Up.tga └── TrinketMenu-Icon-Down.tga ├── TrinketMenu.toc ├── Bindings.xml ├── Libs └── LibStub │ └── LibStub.lua ├── TrinketMenuGlobals.lua ├── TrinketMenu.xml ├── TrinketMenuOpt.lua ├── Readme.txt ├── TrinketMenuOpt.xml ├── TrinketMenuQueue.lua ├── TrinketMenuQueue.xml └── TrinketMenu.lua /.pkgmeta: -------------------------------------------------------------------------------- 1 | package-as: TrinketMenu 2 | 3 | enable-nolib-creation: no 4 | -------------------------------------------------------------------------------- /Textures/Buttons.blp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resike/TrinketMenu/HEAD/Textures/Buttons.blp -------------------------------------------------------------------------------- /Textures/TrinketMenu-Gear.blp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resike/TrinketMenu/HEAD/Textures/TrinketMenu-Gear.blp -------------------------------------------------------------------------------- /Textures/TrinketMenu-Icon-Up.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resike/TrinketMenu/HEAD/Textures/TrinketMenu-Icon-Up.tga -------------------------------------------------------------------------------- /Textures/TrinketMenu-Icon-Down.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resike/TrinketMenu/HEAD/Textures/TrinketMenu-Icon-Down.tga -------------------------------------------------------------------------------- /TrinketMenu.toc: -------------------------------------------------------------------------------- 1 | ## Interface: 110105, 40402, 11507 2 | ## Title: TrinketMenu 11.1.8 3 | ## Version: 11.1.8 4 | ## Author: Gello, Resike 5 | ## Notes: Addon to manage trinkets. 6 | ## SavedVariables: TrinketMenuOptions 7 | ## SavedVariablesPerCharacter: TrinketMenuPerOptions, TrinketMenuQueue 8 | 9 | Libs\LibStub\LibStub.lua 10 | 11 | TrinketMenuGlobals.lua 12 | TrinketMenu.lua 13 | TrinketMenu.xml 14 | TrinketMenuOpt.lua 15 | TrinketMenuOpt.xml 16 | TrinketMenuQueue.lua 17 | TrinketMenuQueue.xml 18 | -------------------------------------------------------------------------------- /Bindings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | TrinketMenu.ToggleFrame(TrinketMenuOptions.DisableToggle == "ON" and TrinketMenu_OptFrame or TrinketMenu_MainFrame) 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Libs/LibStub/LibStub.lua: -------------------------------------------------------------------------------- 1 | -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info 2 | -- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke 3 | local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! 4 | local LibStub = _G[LIBSTUB_MAJOR] 5 | 6 | if not LibStub or LibStub.minor < LIBSTUB_MINOR then 7 | LibStub = LibStub or {libs = {}, minors = {} } 8 | _G[LIBSTUB_MAJOR] = LibStub 9 | LibStub.minor = LIBSTUB_MINOR 10 | 11 | function LibStub:NewLibrary(major, minor) 12 | assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") 13 | minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") 14 | 15 | local oldminor = self.minors[major] 16 | if oldminor and oldminor >= minor then return nil end 17 | self.minors[major], self.libs[major] = minor, self.libs[major] or {} 18 | return self.libs[major], oldminor 19 | end 20 | 21 | function LibStub:GetLibrary(major, silent) 22 | if not self.libs[major] and not silent then 23 | error(("Cannot find a library instance of %q."):format(tostring(major)), 2) 24 | end 25 | return self.libs[major], self.minors[major] 26 | end 27 | 28 | function LibStub:IterateLibraries() return pairs(self.libs) end 29 | setmetatable(LibStub, { __call = LibStub.GetLibrary }) 30 | end 31 | -------------------------------------------------------------------------------- /TrinketMenuGlobals.lua: -------------------------------------------------------------------------------- 1 | TRINKETMENU_BACKDROP_16_16_4444 = { 2 | bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", 3 | edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", 4 | tile = true, 5 | tileEdge = true, 6 | tileSize = 16, 7 | edgeSize = 16, 8 | insets = { left = 4, right = 4, top = 4, bottom = 4 }, 9 | } 10 | TRINKETMENU_BACKDROP_16 = { 11 | edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", 12 | edgeSize = 16, 13 | } 14 | TRINKETMENU_SLIDER_BACKDROP = { 15 | bgFile = "Interface\\Buttons\\UI-SliderBar-Background", 16 | edgeFile = "Interface\\Buttons\\UI-SliderBar-Border", 17 | tile = true, 18 | tileEdge = true, 19 | tileSize = 8, 20 | edgeSize = 8, 21 | insets = { left = 3, right = 3, top = 6, bottom = 6 }, 22 | } 23 | 24 | local BackdropTemplatePolyfillMixin = {} 25 | 26 | function BackdropTemplatePolyfillMixin:OnBackdropLoaded() 27 | if not self.backdropInfo then 28 | return 29 | end 30 | 31 | if not self.backdropInfo.edgeFile and not self.backdropInfo.bgFile then 32 | self.backdropInfo = nil 33 | return 34 | end 35 | 36 | self:ApplyBackdrop() 37 | 38 | if self.backdropColor then 39 | local r, g, b = self.backdropColor:GetRGB() 40 | self:SetBackdropColor(r, g, b, self.backdropColorAlpha or 1) 41 | end 42 | 43 | if self.backdropBorderColor then 44 | local r, g, b = self.backdropBorderColor:GetRGB() 45 | self:SetBackdropBorderColor(r, g, b, self.backdropBorderColorAlpha or 1) 46 | end 47 | 48 | if self.backdropBorderBlendMode then 49 | self:SetBackdropBorderBlendMode(self.backdropBorderBlendMode) 50 | end 51 | end 52 | 53 | function BackdropTemplatePolyfillMixin:OnBackdropSizeChanged() 54 | if self.backdropInfo then 55 | self:SetupTextureCoordinates() 56 | end 57 | end 58 | 59 | function BackdropTemplatePolyfillMixin:ApplyBackdrop() 60 | -- The SetBackdrop call will implicitly reset the background and border 61 | -- texture vertex colors to white, consistent across all client versions. 62 | 63 | self:SetBackdrop(self.backdropInfo) 64 | end 65 | 66 | function BackdropTemplatePolyfillMixin:ClearBackdrop() 67 | self:SetBackdrop(nil) 68 | self.backdropInfo = nil 69 | end 70 | 71 | function BackdropTemplatePolyfillMixin:GetEdgeSize() 72 | -- The below will indeed error if there's no backdrop assigned this is 73 | -- consistent with how it works on 9.x clients. 74 | 75 | return self.backdropInfo.edgeSize or 39 76 | end 77 | 78 | function BackdropTemplatePolyfillMixin:HasBackdropInfo(backdropInfo) 79 | return self.backdropInfo == backdropInfo 80 | end 81 | 82 | function BackdropTemplatePolyfillMixin:SetBorderBlendMode() 83 | -- The pre-9.x API doesn't support setting blend modes for backdrop 84 | -- borders, so this is a no-op that just exists in case we ever assume 85 | -- it exists. 86 | end 87 | 88 | function BackdropTemplatePolyfillMixin:SetupPieceVisuals() 89 | -- Deliberate no-op as backdrop internals are handled C-side pre-9.x. 90 | end 91 | 92 | function BackdropTemplatePolyfillMixin:SetupTextureCoordinates() 93 | -- Deliberate no-op as texture coordinates are handled C-side pre-9.x. 94 | end 95 | 96 | TrinketMenuBackdropTemplateMixin = CreateFromMixins(BackdropTemplateMixin or BackdropTemplatePolyfillMixin) 97 | -------------------------------------------------------------------------------- /TrinketMenu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | self:RegisterForClicks("LeftButtonUp", "RightButtonUp") 14 | if self.TogglePopup then 15 | self.TogglePopup = function() end 16 | end 17 | 18 | 19 | if self.Arrow then 20 | self.Arrow:SetShown(false) 21 | end 22 | 23 | 24 | TrinketMenu.MainTrinket_OnClick(self, button, down) 25 | 26 | 27 | if TrinketMenuOptions.MenuOnRight == "OFF" then 28 | TrinketMenu.BuildMenu() 29 | end 30 | TrinketMenu.WornTrinketTooltip(self) 31 | 32 | 33 | TrinketMenu.ClearTooltip() 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | self:RegisterForClicks("LeftButtonUp", "RightButtonUp") 42 | if self.TogglePopup then 43 | self.TogglePopup = function() end 44 | end 45 | if self.cooldown then 46 | self.cooldown:SetSwipeColor(0, 0, 0, 0.8) 47 | end 48 | if self.icon then 49 | self.icon:SetAllPoints() 50 | end 51 | 52 | 53 | if self.Arrow then 54 | self.Arrow:SetShown(false) 55 | end 56 | 57 | 58 | TrinketMenu.MenuTrinket_OnClick(self, button, down) 59 | 60 | 61 | TrinketMenu.MenuTrinketTooltip(self) 62 | 63 | 64 | TrinketMenu.ClearTooltip() 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 127 | 136 | 145 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then 168 | self:SetPoint("TOPLEFT", 4, -4) 169 | else 170 | self:SetPoint("TOPLEFT", 8, -8) 171 | end 172 | self:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp") 173 | if self.cooldown then 174 | self.cooldown:SetSwipeColor(0, 0, 0, 0.8) 175 | end 176 | if self.icon then 177 | self.icon:SetAllPoints() 178 | end 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then 196 | self:SetPoint("BOTTOMRIGHT", -3, 3) 197 | else 198 | self:SetPoint("BOTTOMRIGHT", -8, 8) 199 | end 200 | self:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp") 201 | if self.cooldown then 202 | self.cooldown:SetSwipeColor(0, 0, 0, 0.8) 203 | end 204 | if self.icon then 205 | self.icon:SetAllPoints() 206 | end 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | TrinketMenu.OnLoad(self) 216 | 217 | 218 | TrinketMenu.OnEvent(self, event, ...) 219 | 220 | 221 | TrinketMenu.MainFrame_OnMouseDown(self) 222 | 223 | 224 | TrinketMenu.MainFrame_OnMouseUp(self) 225 | 226 | 227 | TrinketMenu.OnShow() 228 | 229 | 230 | TrinketMenu.OnHide() 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 257 | 266 | 275 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | self:OnBackdropLoaded() 351 | self:SetBackdropColor(0.0, 0.0, 0.0) 352 | self:SetBackdropBorderColor(0.0, 0.0, 0.0) 353 | 354 | 355 | TrinketMenu.MenuFrame_OnMouseDown(button) 356 | 357 | 358 | TrinketMenu.MenuFrame_OnMouseUp(button) 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | TrinketMenu.TimersFrame_OnUpdate(elapsed) 367 | 368 | 369 | 370 | 371 | 378 | 379 | -------------------------------------------------------------------------------- /TrinketMenuOpt.lua: -------------------------------------------------------------------------------- 1 | --[[ TrinketMenuOpt.lua : Options and sort window for TrinketMenu ]] 2 | 3 | local _G, math, string, table = _G, math, string, table 4 | 5 | local IsRetail = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE 6 | 7 | TrinketMenu.CheckOptInfo = { 8 | {"ShowIcon", "ON", "Minimap Button", "Show or hide minimap button."}, 9 | {"SquareMinimap", "OFF", "Square Minimap", "Move minimap button as if around a square minimap.", "ShowIcon"}, 10 | {"CooldownCount", "OFF", "Cooldown Numbers", "Display time remaining on cooldowns ontop of the button."}, 11 | {"CooldownCountBlizzard", "OFF", "Blizzard Cooldowns", "Display time remaining on cooldowns ontop of the button."}, 12 | {"CooldownCountOmniCC", "OFF", "OmniCC Cooldowns", "Display time remaining on cooldowns ontop of the button."}, 13 | {"TooltipFollow", "OFF", "At Mouse", "Display all tooltips near the mouse.", "ShowTooltips"}, 14 | {"KeepOpen", "OFF", "Keep Menu Open", "Keep menu open at all times."}, 15 | {"KeepDocked", "ON", "Keep Menu Docked", "Keep menu docked at all times."}, 16 | {"Notify", "OFF", "Notify When Ready", "Sends an overhead notification when a trinket's cooldown is complete."}, 17 | {"DisableToggle", "OFF", "Disable Toggle", "Disables the minimap button's ability to toggle the trinket frame.", "ShowIcon"}, 18 | {"NotifyChatAlso", "OFF", "Notify Chat Also", "Sends notifications through chat also."}, 19 | {"Locked", "OFF", "Lock Windows", "Prevents the windows from being moved, resized or rotated."}, 20 | {"ShowTooltips", "ON", "Show Tooltips", "Shows tooltips."}, 21 | {"NotifyThirty", "ON", "Notify At 30 sec", "Sends an overhead notification when a trinket has 30 seconds left on cooldown."}, 22 | {"MenuOnShift", "OFF", "Menu On Shift", "Check this to prevent the menu appearing unless Shift is held."}, 23 | {"TinyTooltips", "OFF", "Tiny Tooltips", "Shrink trinket tooltips to only their name, charges and cooldown.", "ShowTooltips"}, 24 | {"SetColumns", "OFF", "Wrap at: ", "Define how many trinkets before the menu will wrap to the next row.\n\nUncheck to let TrinketMenu choose how to wrap the menu."}, 25 | {"LargeCooldown", "ON", "Large Numbers", "Display the cooldown time in a larger font.", "CooldownCount"}, 26 | {"ShowHotKeys", "ON", "Show Key Bindings", "Display the key bindings over the equipped trinkets."}, 27 | {"StopOnSwap", "OFF", "Stop Queue On Swap", "Swapping a passive trinket stops an auto queue. Check this to also stop the auto queue when a clickable trinket is manually swapped in via TrinketMenu. This will have the most use to those with frequent trinkets marked Priority."}, 28 | {"HideOnLoad", "OFF", "Close On Profile Load", "Check this to dismiss this window when you load a profile."}, 29 | {"RedRange", "OFF", "Red Out of Range", "Check this to red out worn trinkets that are out of range to a valid target. ie, Gnomish Death Ray and Gnomish Net-O-Matic."}, 30 | {"HidePetBattle", "ON", "Hide in Pet Battles", "Check this auto hide the frame while in a pet battle."}, 31 | {"MenuOnRight", "OFF", "Menu On Right-Click", "Check this to prevent the menu from appearing until either worn trinket is right-clicked.\n\nNOTE: This setting CANNOT be changed while in combat."} 32 | } 33 | 34 | TrinketMenu.TooltipInfo = { 35 | {"TrinketMenu_LockButton", "Lock Windows", "Prevents the windows from being moved, resized or rotated."}, 36 | {"TrinketMenu_Trinket0Check", "Top Trinket Auto Queue", "Check this to enable auto queue for this trinket slot. You can also Alt+Click the trinket slot to toggle Auto Queue."}, 37 | {"TrinketMenu_Trinket1Check", "Bottom Trinket Auto Queue", "Check this to enable auto queue for this trinket slot. You can also Alt+Click the trinket slot to toggle Auto Queue."}, 38 | {"TrinketMenu_SortPriority", "High Priority", "When checked, this trinket will be swapped in as soon as possible, whether the equipped trinket is on cooldown or not.\n\nWhen unchecked, this trinket will not equip over one already worn that's not on cooldown."}, 39 | {"TrinketMenu_SortDelay", "Swap Delay", "This is the time (in seconds) before a trinket will be swapped out. ie, for Earthstrike you want 20 seconds to get the full 20 second effect of the buff."}, 40 | {"TrinketMenu_SortKeepEquipped", "Pause Queue", "Check this to suspend the auto queue while this trinket is equipped. ie, for Carrot on a Stick if you have a mod to auto-equip it to a slot with Auto Queue active."}, 41 | {"TrinketMenu_Profiles", "Profiles", "Here you can load or save auto queue profiles."}, 42 | {"TrinketMenu_Delete", "Delete", "Remove this trinket from the list. Trinkets further down the list don't affect performance at all. This option is merely to keep the list managable. Note: Trinkets in your bags will return to end of the list."}, 43 | {"TrinketMenu_ProfilesDelete", "Delete Profile", "Remove this profile."}, 44 | {"TrinketMenu_ProfilesLoad", "Load Profile", "Load a queue order for the selected trinket slot. You can double-click a profile to load it also."}, 45 | {"TrinketMenu_ProfilesSave", "Save Profile", "Save the queue order from the selected trinket slot. Either trinket slot can use saved profiles."}, 46 | {"TrinketMenu_ProfileName", "Profile Name", "Enter a name to call the profile. When saved, you can load this profile to either trinket slot."} 47 | } 48 | 49 | function TrinketMenu.InitOptions() 50 | TrinketMenu.CreateTimer("DragMinimapButton", TrinketMenu.DragMinimapButton, 0, 1) 51 | TrinketMenu.MoveMinimapButton() 52 | local item 53 | for i = 1, #TrinketMenu.CheckOptInfo do 54 | item = _G["TrinketMenu_Opt"..TrinketMenu.CheckOptInfo[i][1].."Text"] 55 | if item then 56 | item:SetText(TrinketMenu.CheckOptInfo[i][3]) 57 | item:SetTextColor(.95, .95, .95) 58 | end 59 | end 60 | TrinketMenu.Tab_OnClick(1) 61 | table.insert(UISpecialFrames, "TrinketMenu_OptFrame") 62 | TrinketMenu_Title:SetText("TrinketMenu "..TrinketMenu_Version) 63 | TrinketMenu_OptFrame:SetBackdropBorderColor(.3, .3, .3, 1) 64 | TrinketMenu_SubOptFrame:SetBackdropBorderColor(.3, .3, .3, 1) 65 | if TrinketMenu.QueueInit then 66 | TrinketMenu.QueueInit() 67 | TrinketMenu_Tab1:Show() 68 | TrinketMenu_OptFrame:SetHeight(356) 69 | TrinketMenu_SubOptFrame:SetPoint("TOPLEFT", TrinketMenu_OptFrame, "TOPLEFT", 8, - 50) 70 | else 71 | TrinketMenu_OptStopOnSwap:Hide() -- remove StopOnSwap option if queue not loaded 72 | TrinketMenu_Tab1:Hide() -- hide options tab if it's only tab 73 | TrinketMenu_OptFrame:SetHeight(300) 74 | TrinketMenu_SubOptFrame:SetPoint("TOPLEFT", TrinketMenu_OptFrame, "TOPLEFT", 8, - 24) 75 | end 76 | TrinketMenu_OptColumnsSlider:SetValue(TrinketMenuOptions.Columns) 77 | TrinketMenu_OptColumnsSliderText:SetText(TrinketMenuOptions.Columns.." trinkets") 78 | TrinketMenu_OptMainScaleSlider:SetValue(TrinketMenuPerOptions.MainScale) 79 | TrinketMenu_OptMenuScaleSlider:SetValue(TrinketMenuPerOptions.MenuScale) 80 | TrinketMenu.ReflectLock() 81 | TrinketMenu.ReflectCooldownFont() 82 | TrinketMenu.KeyBindingsChanged() 83 | end 84 | 85 | function TrinketMenu.ToggleFrame(frame) 86 | if frame:IsVisible() then 87 | frame:Hide() 88 | else 89 | frame:Show() 90 | end 91 | end 92 | 93 | function TrinketMenu.OptFrame_OnShow() 94 | TrinketMenu.ValidateChecks() 95 | if TrinketMenu.CurrentlySorting then 96 | TrinketMenu.PopulateSort(TrinketMenu.CurrentlySorting) 97 | end 98 | end 99 | 100 | --[[ Minimap button ]] 101 | 102 | function TrinketMenu.MoveMinimapButton() 103 | local xpos, ypos 104 | if TrinketMenuOptions.SquareMinimap == "ON" then 105 | xpos = 110 * cos(TrinketMenuOptions.IconPos or 0) 106 | ypos = 110 * sin(TrinketMenuOptions.IconPos or 0) 107 | xpos = math.max(- 82, math.min(xpos, 84)) 108 | ypos = math.max(- 86, math.min(ypos, 82)) 109 | else 110 | local radius = IsRetail and 102 or 80 111 | xpos = radius * cos(TrinketMenuOptions.IconPos or 0) 112 | ypos = radius * sin(TrinketMenuOptions.IconPos or 0) 113 | end 114 | if IsRetail then 115 | TrinketMenu_IconFrame:SetPoint("TOPLEFT", "Minimap", "TOPLEFT", 82 - xpos, ypos - 84) 116 | else 117 | TrinketMenu_IconFrame:SetPoint("TOPLEFT", "Minimap", "TOPLEFT", 52 - xpos, ypos - 52) 118 | end 119 | if TrinketMenuOptions.ShowIcon == "ON" then 120 | TrinketMenu_IconFrame:Show() 121 | else 122 | TrinketMenu_IconFrame:Hide() 123 | end 124 | end 125 | 126 | function TrinketMenu.DragMinimapButton() 127 | local xpos, ypos = GetCursorPosition() 128 | local xmin, ymin = Minimap:GetLeft() or 400, Minimap:GetBottom() or 400 129 | xpos = xmin - xpos / Minimap:GetEffectiveScale() + 70 130 | ypos = ypos / Minimap:GetEffectiveScale() - ymin - 70 131 | TrinketMenuOptions.IconPos = math.deg(math.atan2(ypos, xpos)) 132 | TrinketMenu.MoveMinimapButton() 133 | end 134 | 135 | function TrinketMenu.MinimapButton_OnClick(button) 136 | PlaySound(825) 137 | if IsShiftKeyDown() then 138 | TrinketMenuOptions.Locked = TrinketMenuOptions.Locked == "ON" and "OFF" or "ON" 139 | TrinketMenu.ReflectLock() 140 | elseif IsAltKeyDown() and TrinketMenu.QueueInit then 141 | if button == "LeftButton" then 142 | TrinketMenuQueue.Enabled[0] = not TrinketMenuQueue.Enabled[0] and 1 or nil 143 | elseif button == "RightButton" then 144 | TrinketMenuQueue.Enabled[1] = not TrinketMenuQueue.Enabled[1] and 1 or nil 145 | end 146 | TrinketMenu.ReflectQueueEnabled() 147 | TrinketMenu.UpdateCombatQueue() 148 | else 149 | if button == "LeftButton" and TrinketMenuOptions.DisableToggle == "OFF" then 150 | TrinketMenu.ToggleFrame(TrinketMenu_MainFrame) 151 | else 152 | TrinketMenu.ToggleFrame(TrinketMenu_OptFrame) 153 | end 154 | end 155 | end 156 | 157 | --[[ CheckButton ]] 158 | 159 | function TrinketMenu.ValidateChecks() 160 | local check, button 161 | for i = 1, #TrinketMenu.CheckOptInfo do 162 | check = TrinketMenu.CheckOptInfo[i] 163 | button = _G["TrinketMenu_Opt"..check[1]] 164 | if button then 165 | button:SetChecked(TrinketMenuOptions[check[1]] == "ON") 166 | if check[5] then 167 | if TrinketMenuOptions[check[5]] == "ON" then 168 | button:Enable() 169 | _G["TrinketMenu_Opt"..check[1].."Text"]:SetTextColor(.95, .95, .95) 170 | else 171 | button:Disable() 172 | _G["TrinketMenu_Opt"..check[1].."Text"]:SetTextColor(.5, .5, .5) 173 | end 174 | end 175 | end 176 | end 177 | TrinketMenu_OptColumnsSlider:SetAlpha((TrinketMenuOptions.SetColumns == "ON") and 1 or .5) 178 | TrinketMenu_OptColumnsSlider:EnableMouse((TrinketMenuOptions.SetColumns == "ON") and 1 or 0) 179 | TrinketMenu_OptColumnsSlider:SetValue(TrinketMenuOptions.Columns) 180 | end 181 | 182 | function TrinketMenu.OptColumnsSlider_OnValueChanged(self, value) 183 | if not self._onsetting then 184 | self._onsetting = true 185 | self:SetValue(self:GetValue()) 186 | value = self:GetValue() 187 | self._onsetting = false 188 | else 189 | return 190 | end 191 | if TrinketMenuOptions then 192 | TrinketMenuOptions.Columns = self:GetValue() 193 | TrinketMenu_OptColumnsSliderText:SetText(TrinketMenuOptions.Columns.." trinkets") 194 | if TrinketMenu_MenuFrame:IsVisible() then 195 | TrinketMenu.BuildMenu() 196 | end 197 | end 198 | end 199 | 200 | function TrinketMenu.OptMainScaleSlider_OnValueChanged(self, value) 201 | if not self._onsetting then 202 | self._onsetting = true 203 | self:SetValue(self:GetValue()) 204 | value = self:GetValue() 205 | self._onsetting = false 206 | else 207 | return 208 | end 209 | if TrinketMenuPerOptions then 210 | TrinketMenuPerOptions.MainScale = self:GetValue() 211 | TrinketMenu_OptMainScaleSliderText:SetText(format("Main Scale: %.2f", TrinketMenuPerOptions.MainScale)) 212 | TrinketMenu_MainFrame:SetScale(TrinketMenuPerOptions.MainScale) 213 | end 214 | end 215 | 216 | function TrinketMenu.OptMenuScaleSlider_OnValueChanged(self, value) 217 | if not self._onsetting then 218 | self._onsetting = true 219 | self:SetValue(self:GetValue()) 220 | value = self:GetValue() 221 | self._onsetting = false 222 | else 223 | return 224 | end 225 | if TrinketMenuPerOptions then 226 | TrinketMenuPerOptions.MenuScale = self:GetValue() 227 | TrinketMenu_OptMenuScaleSliderText:SetText(format("Menu Scale: %.2f", TrinketMenuPerOptions.MenuScale)) 228 | TrinketMenu_MenuFrame:SetScale(TrinketMenuPerOptions.MenuScale) 229 | end 230 | end 231 | 232 | function TrinketMenu.SliderOnMouseWheel(self, delta) 233 | if delta > 0 then 234 | self:SetValue(self:GetValue() + self:GetValueStep()) 235 | else 236 | self:SetValue(self:GetValue() - self:GetValueStep()) 237 | end 238 | end 239 | 240 | function TrinketMenu.CheckButton_OnClick(self) 241 | local _, _, var = string.find(self:GetName(), "TrinketMenu_Opt(.+)") 242 | if TrinketMenuOptions[var] then 243 | TrinketMenuOptions[var] = self:GetChecked() and "ON" or "OFF" 244 | PlaySound(self:GetChecked() and 856 or 857) 245 | TrinketMenu.ValidateChecks() 246 | end 247 | if self == TrinketMenu_OptCooldownCount then 248 | TrinketMenu.WriteWornCooldowns() 249 | TrinketMenu.WriteMenuCooldowns() 250 | elseif self == TrinketMenu_OptCooldownCountBlizzard then 251 | if TrinketMenu_Trinket0 and TrinketMenu_Trinket0.cooldown then 252 | if TrinketMenuOptions.CooldownCountBlizzard == "ON" then 253 | TrinketMenu_Trinket0.cooldown:SetHideCountdownNumbers(false) 254 | else 255 | TrinketMenu_Trinket0.cooldown:SetHideCountdownNumbers(true) 256 | end 257 | end 258 | if TrinketMenu_Trinket1 and TrinketMenu_Trinket1.cooldown then 259 | if TrinketMenuOptions.CooldownCountBlizzard == "ON" then 260 | TrinketMenu_Trinket1.cooldown:SetHideCountdownNumbers(false) 261 | else 262 | TrinketMenu_Trinket1.cooldown:SetHideCountdownNumbers(true) 263 | end 264 | end 265 | for i = 1, TrinketMenu.MaxTrinkets do 266 | local menuButton = _G["TrinketMenu_Menu"..i] 267 | if menuButton and menuButton.cooldown then 268 | if TrinketMenuOptions.CooldownCountBlizzard == "ON" then 269 | menuButton.cooldown:SetHideCountdownNumbers(false) 270 | else 271 | menuButton.cooldown:SetHideCountdownNumbers(true) 272 | end 273 | end 274 | end 275 | elseif self == TrinketMenu_OptCooldownCountOmniCC then 276 | if TrinketMenu_Trinket0 and TrinketMenu_Trinket0.cooldown then 277 | if TrinketMenuOptions.CooldownCountOmniCC == "ON" then 278 | TrinketMenu_Trinket0.cooldown.noCooldownCount = false 279 | else 280 | TrinketMenu_Trinket0.cooldown.noCooldownCount = true 281 | end 282 | end 283 | if TrinketMenu_Trinket1 and TrinketMenu_Trinket1.cooldown then 284 | if TrinketMenuOptions.CooldownCountOmniCC == "ON" then 285 | TrinketMenu_Trinket1.cooldown.noCooldownCount = false 286 | else 287 | TrinketMenu_Trinket1.cooldown.noCooldownCount = true 288 | end 289 | end 290 | for i = 1, TrinketMenu.MaxTrinkets do 291 | local menuButton = _G["TrinketMenu_Menu"..i] 292 | if menuButton and menuButton.cooldown then 293 | if TrinketMenuOptions.CooldownCountOmniCC == "ON" then 294 | menuButton.cooldown.noCooldownCount = false 295 | else 296 | menuButton.cooldown.noCooldownCount = true 297 | end 298 | end 299 | end 300 | elseif self == TrinketMenu_OptLocked then 301 | TrinketMenu.DockWindows() 302 | TrinketMenu.ReflectLock() 303 | elseif self == TrinketMenu_OptKeepOpen or self == TrinketMenu_OptSetColumns then 304 | if TrinketMenuOptions.KeepOpen == "ON" then 305 | TrinketMenu.BuildMenu() 306 | end 307 | elseif self == TrinketMenu_OptKeepDocked then 308 | TrinketMenu.DockWindows() 309 | elseif self == TrinketMenu_OptLargeCooldown then 310 | TrinketMenu.ReflectCooldownFont() 311 | elseif self == TrinketMenu_OptSquareMinimap then 312 | TrinketMenu.MoveMinimapButton() 313 | elseif self == TrinketMenu_OptShowHotKeys then 314 | TrinketMenu.KeyBindingsChanged() 315 | elseif self == TrinketMenu_OptShowIcon then 316 | TrinketMenu.MoveMinimapButton() 317 | --[[elseif self == TrinketMenu_OptRedRange then 318 | TrinketMenu.ReflectRedRange()]] 319 | elseif self == TrinketMenu_OptMenuOnRight then 320 | TrinketMenu.ReflectMenuOnRight() 321 | elseif self == TrinketMenu_OptNotify or self == TrinketMenu_OptNotifyThirty then 322 | if TrinketMenu_OptNotify:GetChecked() or TrinketMenu_OptNotifyThirty:GetChecked() then 323 | TrinketMenu.StartTimer("CooldownUpdate") 324 | elseif not TrinketMenu_OptNotify:GetChecked() and not TrinketMenu_OptNotifyThirty:GetChecked() then 325 | TrinketMenu.StopTimer("CooldownUpdate") 326 | end 327 | end 328 | end 329 | 330 | function TrinketMenu.ReflectLock() 331 | local c = TrinketMenuOptions.Locked == "ON" and 0 or .5 332 | TrinketMenu_OptFrame:SetBackdropBorderColor(c, c, c, 1) 333 | TrinketMenu_MainFrame:SetBackdropColor(c, c, c, c) 334 | TrinketMenu_MainFrame:SetBackdropBorderColor(c, c, c, c * 2) 335 | TrinketMenu_MenuFrame:SetBackdropColor(c, c, c, c) 336 | TrinketMenu_MenuFrame:SetBackdropBorderColor(c, c, c, c * 2) 337 | TrinketMenu_MenuFrame:EnableMouse(c * 2) 338 | if TrinketMenuOptions.Locked == "ON" then 339 | TrinketMenu_OptLocked:SetChecked(true) 340 | else 341 | TrinketMenu_OptLocked:SetChecked(false) 342 | end 343 | local normalTexture = TrinketMenu_LockButton:GetNormalTexture() 344 | local pushedTexture = TrinketMenu_LockButton:GetPushedTexture() 345 | if c == 0 then 346 | normalTexture:SetTexCoord(.875, 1, .125, .25) 347 | pushedTexture:SetTexCoord(.75, .875, .125, .25) 348 | else 349 | normalTexture:SetTexCoord(.75, .875, .125, .25) 350 | pushedTexture:SetTexCoord(.875, 1, .125, .25) 351 | end 352 | end 353 | 354 | function TrinketMenu.ReflectCooldownFont() 355 | TrinketMenu.SetCooldownFont("TrinketMenu_Trinket0") 356 | TrinketMenu.SetCooldownFont("TrinketMenu_Trinket1") 357 | for i = 1, 30 do 358 | TrinketMenu.SetCooldownFont("TrinketMenu_Menu"..i) 359 | end 360 | end 361 | 362 | function TrinketMenu.SetCooldownFont(button) 363 | local item = _G[button.."Time"] 364 | if TrinketMenuOptions.LargeCooldown == "ON" then 365 | item:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE") 366 | item:SetTextColor(1, .82, 0, 1) 367 | item:ClearAllPoints() 368 | item:SetPoint("CENTER", button, "CENTER") 369 | else 370 | item:SetFont("Fonts\\ARIALN.TTF", 14, "OUTLINE") 371 | item:SetTextColor(1, 1, 1, 1) 372 | item:ClearAllPoints() 373 | item:SetPoint("BOTTOM", button, "BOTTOM") 374 | end 375 | end 376 | 377 | --[[ Titlebar buttons ]] 378 | 379 | function TrinketMenu.SmallButton_OnClick(self) 380 | PlaySound(856) 381 | if self == TrinketMenu_CloseButton then 382 | TrinketMenu_OptFrame:Hide() 383 | elseif self == TrinketMenu_LockButton then 384 | TrinketMenuOptions.Locked = (TrinketMenuOptions.Locked == "ON") and "OFF" or "ON" 385 | TrinketMenu.DockWindows() 386 | TrinketMenu.ReflectLock() 387 | end 388 | end 389 | 390 | --[[ Tabs ]] 391 | 392 | function TrinketMenu.Tab_OnClick(id) 393 | PlaySound(825) 394 | local tab 395 | if TrinketMenu_ProfilesFrame then 396 | TrinketMenu_ProfilesFrame:Hide() 397 | end 398 | for i = 1, 3 do 399 | tab = _G["TrinketMenu_Tab"..i] 400 | if tab then 401 | tab:UnlockHighlight() 402 | end 403 | end 404 | _G["TrinketMenu_Tab"..id]:LockHighlight() 405 | if id == 1 then 406 | TrinketMenu_SubOptFrame:Show() 407 | if TrinketMenu_SubQueueFrame then 408 | TrinketMenu_SubQueueFrame:Hide() 409 | end 410 | else 411 | TrinketMenu_SubOptFrame:Hide() 412 | TrinketMenu_SubQueueFrame:Show() 413 | TrinketMenu.OpenSort(3 - id) 414 | end 415 | end 416 | -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | TrinketMenu 5.0.2 2 | 3 | This is a mod to make swapping trinkets easier. It will display your two equipped trinkets in a bar. Mouseover on either trinket will display a menu of up to 30 trinkets in your bags to swap. 4 | 5 | __ New in 5.0.3 __ 6 | - Changed file coding to UTF-8. 7 | 8 | __ New in 5.0.2 __ 9 | - Fixed an itemID bug. 10 | 11 | __ New in 5.0.1 __ 12 | - Updated for 5.3. 13 | 14 | __ New in 5.0.0 __ 15 | - Updated for 5.2. 16 | - Minor fixes. 17 | - Code Cleanup. 18 | - Moved textures to "Textures" folder. 19 | - Added notification support for MSBT, Parrot, xCT, xCT+. 20 | 21 | __ Swapping/Using trinkets __ 22 | 23 | Left click a trinket in the menu to equip it to the top trinket slot. 24 | Right click a trinket in the menu to equip it to the bottom trinket slot. 25 | 26 | Left or Right click either equipped trinket to use them. Or make a key binding for either trinket. 27 | 28 | __ Auto Queue __ 29 | 30 | 3.0 introduces auto trinket queues to TrinketMenu. In options you can sort a trinket slot to the order you want trinkets equipped, turn on Auto Queue for that slot (Alt+Click the trinket on the bar or check the tab in options), and the mod will automatically swap trinkets as they're used and come off cooldown. 31 | 32 | It was (hopefully) made to be intuitive enough to use without instructions, but if wondering about specifics: 33 | 34 | The auto queue rules are: 35 | - A trinket at 30 seconds or less cooldown is considered off cooldown. 36 | - If the currently equipped trinket is on cooldown, swap to the first available trinket not on cooldown. 37 | - If the currently equipped trinket cannot go on cooldown (passive trinkets), equip a higher ranking trinket when it comes off cooldown. 38 | - If the currently equipped trinket is ready for use, then do nothing unless a higher-ranked trinket marked 'Priority' is waiting to swap in. 39 | - If a trinket has a 'Delay' defined, then hold that trinket for its delay before swapping it out. (ie, Earthstrike for 20 seconds) 40 | - If a trinket grants a buff and that buff is currently on you, hold that trinket until the buff fades. 41 | 42 | Auto queue icon colors: 43 | - A gold gear on a trinket means that auto queue is active for that slot. 44 | - A grey gear on a trinket means the equipped trinket has a delay defined and is waiting to swap out. 45 | - A red gear on a trinket means the equipped trinket is flagged 'Pause Queue' and auto queue is suspended. 46 | 47 | Other auto queue notes: 48 | - If you use some mod to automatically swap in passive trinkets (Carrot on a Stick or Argent Dawn Commission), flag those trinkets 'Pause Queue' to suspend the queue while they're equipped. 49 | - Swapping a passive trinket manually in TrinketMenu will stop the auto queue for that slot. Alt+click the slot to turn auto queue back on. 50 | - A purely passive trinket will mark the natural end of a queue. If you would like the queue to stop sooner (ie, Burst of Knowledge as bottom-most trinket even on cooldown), move the "-- stop queue here--" mark to where you want the queue to stop. 51 | - The auto queues work independently of the "trinket ready!" notifications. 52 | - Trinkets attempting to swap during combat or while dead will queue for when you drop out of combat or return to life. 53 | - If you don't want to use auto queue and would like to remove it completely, you can delete TrinketMenuQueue.xml and TrinketMenuQueue.lua while out of game. The remaining mod will be about the size of TrinketMenu 2.7 and run better than 2.7. 54 | 55 | __ Auto Queue Shared Timers __ 56 | 57 | Keep in mind as you set up your queues that many trinkets trigger shared cooldown timers. As an example: 58 | 59 | Trinket 0 contains a Cannonball Runner not on cooldown 60 | Trinket 1 contains a Diamond Flask not on cooldown 61 | 62 | When you click Diamond Flask, it will put the Cannonball Runner into a 60-second cooldown. TrinketMenu will then look for something more available for Trinket 0, and then 30 seconds later as the Cannonball Runner comes off cooldown it will swap it back in. 63 | 64 | This is expected behavior. If it seems like this happens a lot, you may want to Auto Queue only one trinket slot, until you get trinkets that can be used without triggering the other's cooldown. 65 | 66 | __ Customizing Display __ 67 | 68 | The main and menu windows are independently scalable and rotatable. While the windows are unlocked: 69 | 70 | - Move either window by dragging its edge. 71 | - Rotate either window by right-clicking its edge. 72 | - Scale/resize either window with a slider in options. 73 | 74 | If you're having problems grabbing the edge of the menu window to move/rotate it, hold Shift down while it's open and the menu won't go away when the mouse leaves the menu's edge. 75 | 76 | If you right-click the gear icon around the minimap (or /trinket options) a small options window will appear under the minimap. Here you can customize the display further by showing cooldowns as numbers and keeping the menu always open. 77 | 78 | Once you're settled on a setup you like, you can lock the windows in options. 79 | 80 | To set an exact scale (optional): 81 | /trinket scale main n : Scale the main window to n 82 | /trinket scale menu n : Scale the menu window to n 83 | ie: /trinket scale menu 0.85 84 | 85 | __ Docking __ 86 | 87 | While 'Keep Menu Docked' is checked (default), the menu will always be docked to one corner of the main window. To change the corner where it's docked, drag the menu window so that a corner of the main and menu windows meet. White brackets will appear at the corners that will dock as you drag. 88 | 89 | If you uncheck 'Keep Menu Docked', remember the menu goes away when the mouse leaves your trinkets. Feel free to experiment if you'd like. Remember that /trinket reset will restore positions/docking, or you can hold Shift down to keep the menu open. Or you can turn on 'Keep Menu Open' in options. 90 | 91 | __ Combat/Death Queued Trinkets __ 92 | 93 | We can't swap trinkets during combat or when we're dead. If you attempt to swap trinkets during combat or while dead it will put the trinket on hold and automatically swap them once you leave combat: 94 | 95 | - The queued trinket will appear as a small icon inset into the slot it's heading to. 96 | - If you want to unqueue the trinket, reselect it again for that slot (left or right click). 97 | - If you want to queue the trinket to the other slot, reselect it again for the other slot (left or right click). 98 | - The "combat queue" is only one-trinket deep right now. Meaning, once a queued trinket is equipped that queue is emptied. 99 | - Selecting a series of trinkets for a slot will only change the queued trinket, it won't set up an order to them. Go to options to set up an auto queue sort order. 100 | 101 | __ Misc __ 102 | 103 | - If you hold shift while you move trinkets up/down the sort list, the list will stay in place. 104 | - You can drag the minimap icon around the minimap directly. 105 | - You can Shift+click the trinkets to link them to chats just as you would from your bags or inventory. 106 | - If you log in to a character with no trinkets in bags or on their person, the trinket window will not be displayed. 107 | - You can hold Shift while swapping trinkets or manipulating the windows to prevent the menu from disappearing. 108 | - You can set up key bindings to use whatever trinket is in the top or bottom slot. 109 | - If you have Scrolling Combat Text installed, and 'Notify When Ready' checked, it will send a message via SCT when a trinket is ready. 110 | 111 | __ Optional Slash Commands __ 112 | 113 | /trinket or /trinketmenu : toggle the window 114 | /trinket reset : reset window 115 | /trinket opt : summons options window 116 | /trinket lock|unlock : toggles window lock 117 | /trinket scale main|menu n : scales windows to exact scale 118 | /trinket help : lists the above commands 119 | 120 | __ TrinketMenu.SetQueue (Advanced Users) __ 121 | 122 | This function is intended to be used by those that want to script different sort orders or script the auto queue behavior to work with other gear-swapping mods. 123 | 124 | TrinketMenu.SetQueue(0 or 1,"ON" or "OFF" or "PAUSE" or "RESUME" or list) 125 | 126 | "ON" : Turn queue on irregardless of previous state 127 | "OFF" : Turn queue off irregardless of previous state 128 | "PAUSE" : Suspend queue if it was on 129 | "RESUME" : Return queue to normal operation if it was paused 130 | 131 | some examples: 132 | /script TrinketMenu.SetQueue(1,"PAUSE") -- if queue is going, pause it 133 | /script TrinketMenu.SetQueue(1,"RESUME") -- if queue is paused, resume it 134 | /script TrinketMenu.SetQueue(1,"SORT","Earthstrike","Insignia of the Alliance","Diamond Flask") -- set sort 135 | /script TrinketMenu.SetQueue(0,"SORT","Lifestone","Darkmoon Card: Heroism") -- set sort 136 | /script TrinketMenu.SetQueue(1,"SORT","PVP Profile") -- set sort to "PVP Profile" 137 | (a "stop the queue" is assumed at the end of the list) 138 | 139 | So in ItemRack if you want a different queue when in a raid or not: 140 | 141 | name: In Raid 142 | trigger: RAID_ROSTER_UPDATE 143 | delay: 0.5 144 | script: 145 | if GetNumRaidMembers()>0 and not IR_INRAID then 146 | IR_INRAID = 1 147 | TrinketMenu.SetQueue(1,"SORT","Zandalarian Hero Badge","Force of Will") 148 | elseif IR_INRAID and GetNumRaidMembers()==0 then 149 | IR_INRAID = nil 150 | TrinketMenu.SetQueue(1,"SORT","Earthstrike","Diamond Flask","Defender of the Timbermaw") 151 | end 152 | --[[ Changes trinket sort orders depending on whether in a raid or not ]] 153 | 154 | or for some situation when you don't want trinkets swapping at all: 155 | 156 | name: In IF 157 | trigger: ZONE_CHANGED_NEW_AREA 158 | delay: 2 159 | script: 160 | if GetRealZoneText()=="Ironforge" and not IR_INIF then 161 | IR_INIF = 1 162 | TrinketMenu.SetQueue(0,"PAUSE") 163 | elseif IR_INIF and GetRealZoneText()~="Ironforge" then 164 | IR_INIF = nil 165 | TrinketMenu.SetQueue(0,"RESUME") 166 | end 167 | --[[ Pauses trinket slot 0 auto queue while in IF ]] 168 | 169 | __ FAQ for 3.x __ 170 | 171 | Q: Why did you remove the "missing trinket" bit? 172 | A: Because it wasn't always accurate and to make it more accurate would require more bag scanning than is necessary for the mod to function. Specifically: when a series of BAG_UPDATEs occur, it waits until they're done and then quickly scans only the bags that updated. When it finds a trinket it notes its position. If a trinket disappeared it doesn't care because it's not going to show in the menu. I am hyper-sensitive to BAG_UPDATE performance and don't want to spend more CPU cycles than is necessary in normal BAG_UPDATE actions. (You may note that if you remove the TrinketMenuQueue.* files then BAG_UPDATE isn't registered at all) 173 | 174 | Q: Can you let the auto queue remain enabled when I swap in passive trinkets? 175 | A: At some point, you will have to tell the mod that you no longer want to use the passive trinket. Alt+clicking the slot seems simplest. 176 | 177 | Q: Can you make auto queue stop/start with my trinket-swapping mod/macro? 178 | A: There are numerous ways of equipping trinkets: UseContainerItem, UseAction, PickupContainerItem/PickupInventoryItem, EquipCursorItem, etc. I don't want to hook all those functions. I want this mod to be small and unobtrusive. Check 'Pause Queue' on trinkets your mod/macro equips, or use TrinketMenu.SetQueue in the macro or event that does the swap. 179 | 180 | Q: You said you'd never add full queues to this. Why the change? 181 | A: Mostly it was to work out some design problems for ItemRack that will have queues for equippable and consumable items. I needed to back up to a simpler level and adding queues to TrinketMenu was a logical place to work them out. 182 | 183 | Q: One reason I used TrinketMenu was because it wasn't bloated with bells and whistles. Will you release a version without the Auto Queues? 184 | A: If you delete TrinketMenuQueue.xml and TrinketMenuQueue.lua then it will remove the Auto Queue and all the frames and code associated with it. What's left will be about the same size as 2.7 TrinketMenu. If there's demand I can post a zip with those files removed. 185 | 186 | Q: Does this mean you're not working on ItemRack? 187 | A: See above. Work is progressing. Some design issues needed sorted out and this mod's update was a helpful part of that. 188 | 189 | Q: Why a rewrite? 190 | A: I'm hoping to keep this mod tidy with as little feature creep as possible. Rewrites are a good way to trim out unnecessary junk. 191 | 192 | Q: I set the menu columns to X, but it's doing X rows and the wrong number of columns. 193 | A: Rotate the menu by right-clicking its unlocked edge. Then rows will become columns and vice versa. 194 | 195 | Q: I made Trinket A higher priority than Trinket B, but when Trinket A comes off cooldown it's not equipping. 196 | A: The default behavior is to not swap trinkets if the currently-equipped trinket is clickable and not on cooldown. This is to prevent the trinket slots excessively swapping and spending a lot of time in 30-second cooldowns. If you have a trinket you want equipped ASAP when it's ready, select it and check 'Priority' at the bottom. 197 | 198 | __ FAQ __ 199 | 200 | Q: How do I equip a trinket to the "off" trinket slot? 201 | A: Left click goes to main trinket slot, right click goes to off slot. 202 | 203 | Q: Can you add items other than trinkets to the menu? 204 | A: See ItemRack, which is the big brother to this mod. It handles all inventory slots as well as item sets and stuff. 205 | 206 | Q: What does ItemRack mean for TrinketMenu's future? 207 | A: TrinketMenu will stay focused on trinkets. For the foreseeable future it will be maintained alongside ItemRack since many are looking for just a trinket manager without the extras. While some new stuff may be added from time to time, any larger changes would probably happen in ItemRack. TrinketMenu will be kept small and focused. 208 | 209 | Q: Localization? 210 | A: This mod should work on all clients. I can't test this for myself but many report it works fine. 211 | 212 | Q: I changed my notify settings on my warrior, but the change shows on my other characters also. 213 | A: Everything in the options window saves for all characters. Just position, orientation, docking and scaling are saved per-character. 214 | 215 | Q: I'd like to go back to using global position/orientation/docking for all my characters. Can I do this? 216 | A: Sure. Edit TrinketMenu.toc and change these two lines to the one that follows: 217 | 218 | Change: 219 | ## SavedVariables: TrinketMenuOptions 220 | ## SavedVariablesPerCharacter: TrinketMenuPerOptions 221 | 222 | To: 223 | ## SavedVariables: TrinketMenuOptions, TrinketMenuPerOptions 224 | 225 | To change all settings (notify, tooltips, etc), change the previous two lines to: 226 | ## SavedVariablesPerCharacter: TrinketMenuOptions, TrinketMenuPerOptions 227 | 228 | Q: How do I move the minimap icon? 229 | A: Drag it like a normal window. Left click and drag it around and it will slide around the edge. 230 | 231 | Q: I'm trying to swap trinkets, but instead of swapping it put a tiny trinket icon over my equipped one. 232 | A: This means you're in combat mode. You won't be able to swap trinkets until you leave combat. The tiny trinket is the one that will swap in once you leave combat. 233 | 234 | Q: What if I don't have Scrolling Combat Text, will it still notify me when trinket cooldowns expire? 235 | A: If you don't have SCT, it will notify in the "errors" overhead, where you get "Insufficient mana", "Out of range", etc type errors. 236 | 237 | Q: I don't have many trinkets and because of this I'm having problems docking to some corners. Any way to make it easier? 238 | A: Temporarily resize either window to make the differences greater so it's easier to dock to an exact corner. 239 | 240 | Q: It's not showing all my trinkets, I have over 30 of them in my bags. 241 | A: This version can handle only up to 32 trinkets. Two equipped and 30 in bags. If you exceed this amount, post how many trinkets you have and I'll up the limit. 30 seemed a reasonable number, but as the screenshots show it's not very difficult to get 30 trinkets if you're an engineer. In the meantime the mod will lift trinkets from right bag to left if you want to control which 30 are displayed. 242 | 243 | Q: I can't rotate, move or do anything with the windows. 244 | A: That sounds like the windows are locked. Enter: /trinket unlock 245 | 246 | __ Changes __ 247 | 248 | 5.0.0 2013.04.15. Updated for 5.2, code cleanups. 249 | 3.81, 10/8/08, passed self to SortPriority_OnClick 250 | 3.8, 10/8/08, wotlk beta: scaling done via sliders, removed resize grips, this->self conversion should be complete, removed buff cache, queue won't process while casting 251 | 3.71, 5/7/08, removed ITEM_SPELL_CHARGES_P1 from tiny tooltip, no longer exists 252 | 3.7, 4/1/06, added: engineering bag support, queue won't swap a trinket with an active buff running 253 | 3.6, 12/5/06, live release of 3.5x beta changes 254 | 3.56, 12/1/06, bug fixed: GameTooltip:NumLines in shrink tooltip, removed use entries from Bindings.xml 255 | 3.55, 11/4/06, changed: key bindings moved to ClickBinder, added: shift/alt click options for minimap button 256 | 3.543, 10/27/06, changed: all key binding code to new dummy key bind method, attributes alt-item* to alt-slot* 257 | 3.542, 10/25/06, bugs fixed: converted .../args to .../select(#,...) in SetQueue, equip by name in process queue 258 | 3.541, 10/23/06, changed: UISpecialFrames temporarily removed 259 | 3.54, 10/22/06, added: key bindings, red out of range, removed: item cache and BAG_UPDATE system (wee), changed: using GetItemCooldown instead 260 | 3.53, 10/19/06, changed: "inventory" attribute to "item", check if GetItemInfo results valid on new item at patch 261 | 3.52, 10/14/06, changed: uses secure templates, alt to hide/show trinkets in menu, helpful pointer to the delay bit, /itemrack alpha 262 | 3.41, 8/24/06, added: /trinket load, changed: tabs removed and window shortened if TrinketMenuQueue not installed, bug fixed: /trinket reset (savedvars load defaults if nil), checked for Queue before setting HideOnLoad 263 | 3.4, 8/22/06, added: trinket profiles, delete trinket button 264 | 3.3, 8/5/06, added: 1.12 "Floating Combat Text" support, changed: trinkets coming off cooldown clear combat queue, toggle key binding obeys 'Disable Toggle' option 265 | 3.22, 7/24/06, added: TrinketMenu.SetQueue and TrinketMenu.GetQueue 266 | 3.21, 7/16/06, changed: lock also locks OptFrame, bug fixed: global strings stripped "%1$d Charge" to "%d Charge" 267 | 3.2, 7/16/06, added: Stop Queue On Swap option, global cooldown spinners, alt+click to stop queue cancels combatqueue 268 | 3.1, 7/12/06, changed: cooldown-enabled trinkets swapped in manually will not stop queue, added: "pause queue" attribute to trinkets, bug fixed: error from trinket used then banked while on cooldown, removed: trinket missing checks 269 | 3.01, 7/9/06, bug fixed: hunter fd will allow swap, minimap button can turn off 270 | 3.0, 7/9/06, rewritten, auto trinket queues, new timer and cooldown/notification system, options: set menu columns, tiny tooltips, large cooldowns, show key bindings 271 | 2.7 3/30/05 - added: /trinket debug, changed: update events disabled while zoning 272 | 2.6 2/8/05 - bug fixed: minimap button movement, added: option to drag around square minimap, option to show menu on shift only 273 | 2.5 1/4/05 - added: notify at 30 sec option, changes: 1.9 scaling, uses GetItemInfo, removed: scalebugfix, cooldowns off screen check 274 | 2.4 10/21/05 - added: /trinket scale slash command, sound on notify, changed: per-character position/orientation/docking, UseInventoryItem 13 and 14 hooked to reflect use, bug fixed: added scale bug fix back in 275 | 2.3 10/2/05 - added: option to disable tooltip, changed: options movable window that defaults to center, bug fixed: logging in character without trinkets won't prevent it from showing next login, for 1.8: pre-emptive fix for 1.8 SetPoint layout-cache bit, scale bug fix no longer performed 276 | 2.23 9/3/05 - bug fixed: hunter fd won't queue a trinket that can ordinarily swap, if the mod is hidden on logout it will be hidden on login 277 | 2.22 9/2/05 - bug fixed: if res'ed before releasing your spirit with trinkets in queue, they'll swap on revive normally 278 | 2.21 8/21/05 - bug fixed: window scaling bug definitively fixed, and error when clicking an empty trinket slot 279 | 2.2 8/20/05 - added: swap attempts while dead will queue trinkets to swap on revive, options to disable toggle, notify used only, and notify chats also, bugs fixed: error for more than 30 trinkets, notify corrected, hopeful fix for location bug some have: forced start/stopmove to save to layout-cache.txt, move the window to saved point going in/out of windowed mode 280 | 2.11 8/17/05 - changed: swap attempts won't happen if anything on cursor, bug fixed: options window will appear on screen irregardless where minimap is, added: /trinket debug to help find location bug issue some see 281 | 2.1 8/17/05 - added: a resize grip to lower right corner, trinket queue, option to dock/undock, notification when trinket cooldown ends (via SCT or overhead), bugs fixed: cooldown update made less frequent, 282 | 2.0 8/14/05 - rewritten from scratch, added up to 30+2 trinkets, menu grows outward, cooldown numbers, keep menu open option, minimap icon and scaling, far better handling of bag/inventory updates, cooldown models won't update if they're off the screen 283 | 1.1 7/20/05 - only react to BAG_UPDATE every second (by Thelgar), made lock/unlock more visually apparent and moved menu closer to main window 284 | 1.0 4/8/05 - initial release -------------------------------------------------------------------------------- /TrinketMenuOpt.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | TrinketMenu.CheckButton_OnClick(self) 41 | 42 | 43 | TrinketMenu.OnTooltip(self) 44 | 45 | 46 | GameTooltip:Hide() 47 | 48 | 49 | 50 | 51 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 146 | 161 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | TrinketMenu.OptColumnsSlider_OnValueChanged(self, value) 450 | 451 | 452 | TrinketMenu.SliderOnMouseWheel(self, delta) 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | self:OnBackdropLoaded() 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | TrinketMenu.OptMainScaleSlider_OnValueChanged(self, value) 499 | 500 | 501 | TrinketMenu.SliderOnMouseWheel(self, delta) 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | self:OnBackdropLoaded() 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | TrinketMenu.OptMenuScaleSlider_OnValueChanged(self, value) 548 | 549 | 550 | TrinketMenu.SliderOnMouseWheel(self, delta) 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | self:OnBackdropLoaded() 561 | 562 | 563 | 564 | 565 | 566 | 567 | self:OnBackdropLoaded() 568 | 569 | 570 | 571 | 572 | 573 | 574 | self:OnBackdropLoaded() 575 | 576 | 577 | self:StartMoving() 578 | 579 | 580 | self:StopMovingOrSizing() 581 | 582 | 583 | TrinketMenu.OptFrame_OnShow() 584 | 585 | 586 | 587 | 588 | -------------------------------------------------------------------------------- /TrinketMenuQueue.lua: -------------------------------------------------------------------------------- 1 | --[[ TrinketMenuQueue : auto queue system ]] 2 | 3 | local _G, type, string, tonumber, table, pairs, select = _G, type, string, tonumber, table, pairs, select 4 | 5 | local IsClassic = WOW_PROJECT_ID >= WOW_PROJECT_CLASSIC 6 | 7 | TrinketMenu.PausedQueue = { } -- 0 or 1 whether queue is paused 8 | 9 | local TRINKET_KEEP_BUFF_AFTER_SWAP = { 10 | [19341] = true, 11 | } 12 | 13 | function TrinketMenu.QueueInit() 14 | TrinketMenuQueue = TrinketMenuQueue or { 15 | Stats = { }, -- indexed by id of trinket, delay, priority and keep 16 | Sort = { }, -- indexed by number, ids in order of use 17 | Enabled = { } -- 0 or 1 whether auto queue is on for the slot 18 | } 19 | TrinketMenuQueue.Sort[0] = TrinketMenuQueue.Sort[0] or { } 20 | TrinketMenuQueue.Sort[1] = TrinketMenuQueue.Sort[1] or { } 21 | TrinketMenu_SubQueueFrame:SetBackdropBorderColor(.3, .3, .3,1) 22 | TrinketMenu_ProfilesFrame:SetBackdropBorderColor(.3, .3, .3, 1) 23 | TrinketMenu_ProfilesListFrame:SetBackdropBorderColor(.3, .3, .3, 1) 24 | TrinketMenu_SortPriorityText:SetText("Priority") 25 | TrinketMenu_SortPriorityText:SetTextColor(.95, .95, .95) 26 | TrinketMenu_SortKeepEquippedText:SetText("Pause Queue") 27 | TrinketMenu_SortKeepEquippedText:SetTextColor(.95, .95, .95) 28 | TrinketMenu_SortListFrame:SetBackdropBorderColor(.3, .3, .3, 1) 29 | TrinketMenu.ReflectQueueEnabled() 30 | TrinketMenu.UpdateCombatQueue() 31 | TrinketMenuQueue.Profiles = TrinketMenuQueue.Profiles or { } 32 | TrinketMenu.ValidateProfile() 33 | TrinketMenu.OpenSort(0) 34 | TrinketMenu.OpenSort(1) 35 | end 36 | 37 | function TrinketMenu.ReflectQueueEnabled() 38 | TrinketMenu_Trinket0Check:SetChecked(TrinketMenuQueue.Enabled[0]) 39 | TrinketMenu_Trinket1Check:SetChecked(TrinketMenuQueue.Enabled[1]) 40 | end 41 | 42 | function TrinketMenu.OpenSort(which) 43 | TrinketMenu.CurrentlySorting = which 44 | TrinketMenu.PopulateSort(which) 45 | TrinketMenu.SortSelected = 0 46 | TrinketMenu_SortScrollScrollBar:SetValue(0) 47 | TrinketMenu.SortValidate() 48 | TrinketMenu.SortScrollFrameUpdate() 49 | end 50 | 51 | function TrinketMenu.GetID(bag, slot) 52 | local _, id 53 | if slot then 54 | _, _, id = string.find(TrinketMenu.GetContainerItemLink(bag, slot) or "", "item:(%d+)") 55 | else 56 | _, _, id = string.find(GetInventoryItemLink("player", bag) or "", "item:(%d+)") 57 | end 58 | return id 59 | end 60 | 61 | function TrinketMenu.GetNameByID(id) 62 | if id == 0 then 63 | return "-- stop queue here --", "Interface\\Buttons\\UI-GroupLoot-Pass-Up", 1 64 | else 65 | local name, _, quality, _, _, _, _, _, _, texture = GetItemInfo(id or "") 66 | return name, texture, quality 67 | end 68 | end 69 | 70 | -- adds id to which sort if it's not already in the list 71 | function TrinketMenu.AddToSort(which, id) 72 | if not id then 73 | return 74 | end 75 | local found 76 | for i = 1, #TrinketMenuQueue.Sort[which] do 77 | found = found or TrinketMenuQueue.Sort[which][i] == id 78 | end 79 | if not found then 80 | table.insert(TrinketMenuQueue.Sort[which], id) 81 | end 82 | end 83 | 84 | -- populates sorts adding any new trinkets 85 | function TrinketMenu.PopulateSort(which) 86 | TrinketMenuQueue.Sort[which] = TrinketMenuQueue.Sort[which] or { } 87 | TrinketMenu.AddToSort(which,TrinketMenu.GetID(which + 13)) 88 | TrinketMenu.AddToSort(which,TrinketMenu.GetID((1 - which) + 13)) 89 | local _, equipLoc, id 90 | for i = 0, 4 do 91 | for j = 1, TrinketMenu.GetContainerNumSlots(i) do 92 | id = TrinketMenu.GetID(i, j) 93 | _, _, _, _, _, _, _, _, equipLoc = GetItemInfo(id or "") 94 | if equipLoc=="INVTYPE_TRINKET" then 95 | TrinketMenu.AddToSort(which, id) 96 | end 97 | end 98 | end 99 | TrinketMenu.AddToSort(which, 0) -- id 0 is Stop 100 | end 101 | 102 | function TrinketMenu.SortScrollFrameUpdate() 103 | local offset = FauxScrollFrame_GetOffset(TrinketMenu_SortScroll) 104 | local list = TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting] 105 | FauxScrollFrame_Update(TrinketMenu_SortScroll, list and #list or 0, 9, 24) 106 | if list and list[1] then 107 | local r, g, b, found 108 | local texture, name, quality, idx 109 | local item, itemName, itemIcon 110 | for i = 1, 9 do 111 | item = _G["TrinketMenu_Sort"..i] 112 | itemName = _G["TrinketMenu_Sort"..i.."Name"] 113 | itemIcon = _G["TrinketMenu_Sort"..i.."Icon"] 114 | idx = offset + i 115 | if idx <= #list then 116 | name, texture, quality = TrinketMenu.GetNameByID(list[idx]) 117 | itemIcon:SetTexture(texture) 118 | itemName:SetText(name) 119 | if quality then -- GetItemInfo may not be valid early on after patches 120 | r, g, b = GetItemQualityColor(quality) 121 | itemName:SetTextColor(r, g, b) 122 | itemIcon:SetVertexColor(1, 1, 1) 123 | end 124 | item:Show() 125 | if idx == TrinketMenu.SortSelected then 126 | TrinketMenu.LockHighlight(item) 127 | else 128 | TrinketMenu.UnlockHighlight(item) 129 | end 130 | else 131 | item:Hide() 132 | end 133 | end 134 | end 135 | end 136 | 137 | function TrinketMenu.LockHighlight(frame) 138 | if type(frame) == "string" then 139 | frame = _G[frame] 140 | end 141 | if not frame then 142 | return 143 | end 144 | frame.lockedHighlight = 1 145 | _G[frame:GetName().."Highlight"]:Show() 146 | end 147 | 148 | function TrinketMenu.UnlockHighlight(frame) 149 | if type(frame) == "string" then 150 | frame = _G[frame] 151 | end 152 | if not frame then 153 | return 154 | end 155 | frame.lockedHighlight = nil 156 | _G[frame:GetName().."Highlight"]:Hide() 157 | end 158 | 159 | -- shows tooltip for items in the sort list 160 | function TrinketMenu.SortTooltip(self) 161 | local idx = FauxScrollFrame_GetOffset(TrinketMenu_SortScroll) + self:GetID() 162 | local _ 163 | local name, itemLink = GetItemInfo(TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting][idx] or "") 164 | _, _, itemLink = string.find(itemLink or "","(item:%d+:%d+:%d+:%d+:%d+:%d+:%d+)") 165 | if itemLink and TrinketMenuOptions.ShowTooltips == "ON" then 166 | TrinketMenu.AnchorTooltip(self) 167 | GameTooltip:SetHyperlink(itemLink) 168 | GameTooltip:Show() 169 | else 170 | TrinketMenu.OnTooltip(self,"Stop Queue Here", "Move this to mark the lowest trinket to auto queue. Sometimes you may want a passive trinket with a click effect to be the end (Burst of Knowledge, Second Wind, etc).") 171 | end 172 | end 173 | 174 | function TrinketMenu.SortOnClick(self) 175 | TrinketMenu_SortDelay:ClearFocus() 176 | local idx = FauxScrollFrame_GetOffset(TrinketMenu_SortScroll) + self:GetID() 177 | if TrinketMenu.SortSelected == idx then 178 | TrinketMenu.SortSelected = 0 179 | else 180 | TrinketMenu.SortSelected = idx 181 | end 182 | TrinketMenu.SortScrollFrameUpdate() 183 | TrinketMenu.SortValidate() 184 | end 185 | 186 | -- turns move buttons on/off, moves the list to keep selected in view and keeps the sorting slot button highlighted 187 | function TrinketMenu.SortValidate() 188 | local selected = TrinketMenu.SortSelected 189 | local list = TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting] 190 | TrinketMenu_MoveTop:Enable() 191 | TrinketMenu_MoveUp:Enable() 192 | TrinketMenu_MoveDown:Enable() 193 | TrinketMenu_MoveBottom:Enable() 194 | if selected == 0 or #list < 2 then -- none selected, disable all 195 | TrinketMenu_MoveTop:Disable() 196 | TrinketMenu_MoveUp:Disable() 197 | TrinketMenu_MoveDown:Disable() 198 | TrinketMenu_MoveBottom:Disable() 199 | elseif selected == 1 then -- top selected, disable up 200 | TrinketMenu_MoveUp:Disable() 201 | TrinketMenu_MoveTop:Disable() 202 | TrinketMenu_MoveDown:Enable() 203 | elseif selected == #list then -- bottom selected, disable down 204 | TrinketMenu_MoveDown:Disable() 205 | TrinketMenu_MoveBottom:Disable() 206 | end 207 | local idx = FauxScrollFrame_GetOffset(TrinketMenu_SortScroll) 208 | if selected > 0 and list[selected] and list[selected] ~= 0 then 209 | TrinketMenu_SortDelay:Show() 210 | TrinketMenu_SortPriority:Show() 211 | TrinketMenu_SortKeepEquipped:Show() 212 | TrinketMenu_Delete:Enable() 213 | else 214 | TrinketMenu_SortDelay:Hide() 215 | TrinketMenu_SortPriority:Hide() 216 | TrinketMenu_SortKeepEquipped:Hide() 217 | TrinketMenu_Delete:Disable() 218 | end 219 | local stats = TrinketMenuQueue.Stats[list[TrinketMenu.SortSelected]] 220 | TrinketMenu_SortDelay:SetText(stats and (stats.delay or "0") or "0") 221 | TrinketMenu_SortPriority:SetChecked(stats and stats.priority) 222 | TrinketMenu_SortKeepEquipped:SetChecked(stats and stats.keep) 223 | if not IsShiftKeyDown() and selected > 0 then -- keep selected visible on list, moving thumb as needed, unless shift is down 224 | local parent = TrinketMenu_SortScrollScrollBar 225 | local offset 226 | if selected <= idx then 227 | offset = (selected == 1) and 0 or (parent:GetValue() - (parent:GetHeight() / 2)) 228 | parent:SetValue(offset) 229 | PlaySound(1115) 230 | elseif selected >= (idx + 10) then 231 | offset = (selected == #list) and TrinketMenu_SortScroll:GetVerticalScrollRange() or (parent:GetValue() + (parent:GetHeight() / 2)) 232 | parent:SetValue(offset) 233 | PlaySound(1115) 234 | end 235 | end 236 | end 237 | 238 | -- movement buttons 239 | function TrinketMenu.SortMove(self) 240 | TrinketMenu_SortDelay:ClearFocus() 241 | local dir = ((self == TrinketMenu_MoveUp) and - 1) or ((self == TrinketMenu_MoveTop) and "top") or ((self == TrinketMenu_MoveDown) and 1) or ((self == TrinketMenu_MoveBottom) and "bottom") 242 | local list = TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting] 243 | local idx1 = TrinketMenu.SortSelected 244 | if dir then 245 | local idx2 = ((dir == "top") and 1) or ((dir == "bottom") and #list) or idx1 + dir 246 | local temp = list[idx1] 247 | if tonumber(dir) then 248 | list[idx1] = list[idx2] 249 | list[idx2] = temp 250 | elseif dir == "top" then 251 | table.remove(list, idx1) 252 | table.insert(list, 1, temp) 253 | elseif dir == "bottom" then 254 | table.remove(list, idx1) 255 | table.insert(list, temp) 256 | end 257 | TrinketMenu.SortSelected = idx2 258 | elseif self == TrinketMenu_Profiles then 259 | TrinketMenu.SortSelected = 0 260 | TrinketMenu.ShowProfiles(TrinketMenu_SortListFrame:IsVisible()) 261 | elseif self == TrinketMenu_Delete then 262 | table.remove(list, idx1) 263 | TrinketMenu.SortSelected = 0 264 | end 265 | TrinketMenu.SortValidate() 266 | TrinketMenu.SortScrollFrameUpdate() 267 | end 268 | 269 | function TrinketMenu.SortDelay_OnTextChanged() 270 | local delay = tonumber(TrinketMenu_SortDelay:GetText()) or 0 271 | local id = TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting][TrinketMenu.SortSelected] 272 | TrinketMenuQueue.Stats[id] = TrinketMenuQueue.Stats[id] or { } 273 | TrinketMenuQueue.Stats[id].delay = delay ~= 0 and delay or nil 274 | end 275 | 276 | function TrinketMenu.SortPriority_OnClick(self) 277 | local check = self:GetChecked() 278 | local id = TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting][TrinketMenu.SortSelected] 279 | TrinketMenuQueue.Stats[id] = TrinketMenuQueue.Stats[id] or { } 280 | TrinketMenuQueue.Stats[id].priority = check 281 | end 282 | 283 | function TrinketMenu.SortKeepEquipped_OnClick(self) 284 | local check = self:GetChecked() 285 | local id = TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting][TrinketMenu.SortSelected] 286 | TrinketMenuQueue.Stats[id] = TrinketMenuQueue.Stats[id] or { } 287 | TrinketMenuQueue.Stats[id].keep = check 288 | end 289 | 290 | function TrinketMenu.TabCheck_OnClick(self) 291 | TrinketMenuQueue.Enabled[3 - self:GetID()] = self:GetChecked() 292 | TrinketMenu.UpdateCombatQueue() 293 | end 294 | 295 | --[[ Auto queue processing ]] 296 | 297 | function TrinketMenu.TrinketNearReady(id) 298 | local start, duration = TrinketMenu.GetItemCooldown(id) 299 | if start == 0 or duration - (GetTime() - start) <= 30 then 300 | return 1 301 | end 302 | end 303 | 304 | function TrinketMenu.CanCooldown(inv) 305 | local _, _, enable = GetInventoryItemCooldown("player", inv) 306 | return enable == 1 307 | end 308 | 309 | -- this function quickly checks if conditions are right for a possible ProcessAutoQueue 310 | function TrinketMenu.PeriodicQueueCheck() 311 | if not TrinketMenuQueue.Enabled[0] and not TrinketMenuQueue.Enabled[1] then 312 | TrinketMenu.StopTimer("QueueUpdate") 313 | return 314 | end 315 | TrinketMenu.StartTimer("QueueUpdate") 316 | for i = 0, 1 do 317 | if TrinketMenuQueue.Enabled[i] then 318 | TrinketMenu.ProcessAutoQueue(i) 319 | end 320 | end 321 | end 322 | 323 | -- which = 0 or 1, decides if a trinket should be equipped and equips if so 324 | function TrinketMenu.ProcessAutoQueue(which) 325 | local _, _, id, name = string.find(GetInventoryItemLink("player", 13 + which) or "", "item:(%d+).+%[(.+)%]") 326 | if not id then 327 | return 328 | end -- leave if no trinket equipped 329 | local start, duration, enable = GetInventoryItemCooldown("player", 13 + which) 330 | local timeLeft = GetTime() - start 331 | local icon = _G["TrinketMenu_Trinket"..which.."Queue"] 332 | if IsInventoryItemLocked(13 + which) then 333 | return 334 | end -- leave if slot being swapped 335 | if (IsClassic and (CastingInfo() or ChannelInfo())) or (not IsClassic and (UnitCastingInfo("player") or UnitChannelInfo("player"))) then 336 | return 337 | end -- leave if player is casting/channeling 338 | if TrinketMenu.PausedQueue[which] then 339 | icon:SetVertexColor(1, .5, .5) -- leave if SetQueue(which, "PAUSE") 340 | return 341 | end 342 | if TrinketMenuQueue.Stats[id] then 343 | if TrinketMenuQueue.Stats[id].keep then 344 | icon:SetVertexColor(1, .5, .5) 345 | return -- leave if .keep flag set on this item 346 | end 347 | if TrinketMenuQueue.Stats[id].delay then 348 | -- leave if currently equipped trinket is on cooldown for less than its delay 349 | if start > 0 and (duration - timeLeft) > 30 and timeLeft < TrinketMenuQueue.Stats[id].delay then 350 | icon:SetDesaturated(true) 351 | return 352 | end 353 | else 354 | local buffName = GetItemSpell(id) 355 | if buffName then 356 | if IsClassic then 357 | if not TRINKET_KEEP_BUFF_AFTER_SWAP[id] then 358 | local i = 1 359 | local buff 360 | while UnitAura("player", i, "HELPFUL") do 361 | buff = UnitAura("player", i, "HELPFUL") 362 | if buffName == buff or (start > 0 and (duration - timeLeft) > 30 and timeLeft < 1) then 363 | icon:SetDesaturated(true) 364 | return 365 | end 366 | i = i + 1 367 | end 368 | end 369 | else 370 | if AuraUtil.FindAuraByName(buffName, "player", "HELPFUL") or (start > 0 and (duration - timeLeft) > 30 and timeLeft < 1) then 371 | icon:SetDesaturated(true) 372 | return 373 | end 374 | end 375 | end 376 | end 377 | end 378 | icon:SetDesaturated(false) -- normal queue operation, reflect that in queue inset 379 | icon:SetVertexColor(1, 1, 1) 380 | local name 381 | local ready = TrinketMenu.TrinketNearReady(id) 382 | if ready and TrinketMenu.CombatQueue[which] then 383 | TrinketMenu.CombatQueue[which] = nil 384 | TrinketMenu.UpdateCombatQueue() 385 | end 386 | local list, rank = TrinketMenuQueue.Sort[which] 387 | for i = 1, #list do 388 | if list[i] == 0 then 389 | rank = i 390 | break 391 | end 392 | if ready and list[i] == id then 393 | rank = i 394 | break 395 | end 396 | end 397 | if rank then 398 | for i = 1, rank do 399 | if not ready or enable == 0 or (TrinketMenuQueue.Stats[list[i]] and TrinketMenuQueue.Stats[list[i]].priority) then 400 | if TrinketMenu.TrinketNearReady(list[i]) then 401 | if GetItemCount(list[i]) > 0 and not IsEquippedItem(list[i]) then 402 | local _, bag, slot = TrinketMenu.FindItem(list[i]) 403 | if bag then 404 | name = GetItemInfo(list[i]) 405 | if TrinketMenu.CombatQueue[which] ~= name then 406 | TrinketMenu.EquipTrinketByName(name, 13 + which) 407 | end 408 | break 409 | end 410 | end 411 | end 412 | end 413 | end 414 | end 415 | end 416 | 417 | --[[ TrinketMenu.SetQueue and TrinketMenu.GetQueue ]] 418 | 419 | -- These functions are for macros and mods to configure sort queues 420 | 421 | -- TrinketMenu.SetQueue(0 or 1,"ON" or "OFF" or "PAUSE" or "RESUME" or "SORT"[,"sort list") 422 | -- some examples: 423 | -- TrinketMenu.SetQueue(1, "PAUSE") -- if queue is going, pause it 424 | -- TrinketMenu.SetQueue(1, "RESUME") -- if queue is paused, resume it 425 | -- TrinketMenu.SetQueue(1, "SORT", "Earthstrike", "Insignia of the Alliance", "Diamond Flask") -- set sort 426 | -- TrinketMenu.SetQueue(0, "SORT", "Lifestone", "Darkmoon Card: Heroism") -- set sort for trinket 0 427 | -- TrinketMenu.SetQueue(1, "SORT", "Pvp Profile") -- note you can replace list with a profile name 428 | -- (a "stop the queue" is assumed at the end of the list) 429 | function TrinketMenu.SetQueue(which, ...) 430 | local errorstub = "|cFFBBBBBBTrinketMenu:|cFFFFFFFF " 431 | if not which or not tonumber(which) or which < 0 or which > 1 then 432 | DEFAULT_CHAT_FRAME:AddMessage(errorstub.."First parameter must be 0 for top trinket or 1 for bottom.") 433 | return 434 | end 435 | if (select("#", ...)) < 1 then 436 | DEFAULT_CHAT_FRAME:AddMessage(errorstub.."Second parameter is either ON, OFF, PAUSE, RESUME or the beginning of a list of trinkets in a sort order.") 437 | return 438 | end 439 | if TrinketMenu_OptFrame:IsVisible() then 440 | TrinketMenu_OptFrame:Hide() -- close option frame if it's up. the mess otherwise would be scary 441 | end 442 | local cmd = (select(1, ...)) 443 | if cmd == "ON" then 444 | TrinketMenuQueue.Enabled[which] = 1 445 | TrinketMenu.PausedQueue[which] = nil 446 | elseif cmd == "OFF" then 447 | TrinketMenuQueue.Enabled[which] = nil 448 | TrinketMenu.PausedQueue[which] = nil 449 | elseif cmd == "PAUSE" then 450 | TrinketMenu.PausedQueue[which] = 1 451 | elseif cmd == "RESUME" then 452 | TrinketMenu.PausedQueue[which] = nil 453 | elseif cmd == "SORT" and (select("#",...)) > 1 then 454 | local inv, bag, slot 455 | for i in pairs(TrinketMenuQueue.Sort[which]) do 456 | TrinketMenuQueue.Sort[which][i] = nil 457 | end 458 | --table.setn(TrinketMenuQueue.Sort[which], 0) 459 | local profile = TrinketMenu.GetProfileID((select(2,...))) 460 | if profile then 461 | for i = 2, #TrinketMenuQueue.Profiles[profile] do 462 | table.insert(TrinketMenuQueue.Sort[which], TrinketMenuQueue.Profiles[profile][i]) 463 | end 464 | else 465 | for i = 2, (select("#", ...)) do 466 | inv, bag, slot = TrinketMenu.FindItem((select(i, ...)), true) -- include inventory 467 | if inv then 468 | table.insert(TrinketMenuQueue.Sort[which], TrinketMenu.GetID(inv)) 469 | elseif bag then 470 | table.insert(TrinketMenuQueue.Sort[which], TrinketMenu.GetID(bag, slot)) 471 | else 472 | DEFAULT_CHAT_FRAME:AddMessage(errorstub.."Trinket or profile \""..(select(i, ...)).."\" not found.") 473 | end 474 | end 475 | table.insert(TrinketMenuQueue.Sort[which], 0) 476 | end 477 | else 478 | DEFAULT_CHAT_FRAME:AddMessage(errorstub.." Expected ON, OFF, PAUSE, RESUME or SORT+list") 479 | end 480 | TrinketMenu.ReflectQueueEnabled() 481 | TrinketMenu.UpdateCombatQueue() 482 | end 483 | 484 | -- returns 1 or nil if queue is enabled, and a table containing an ordered list of the trinkets 485 | function TrinketMenu.GetQueue(which) 486 | if not which or not tonumber(which) or which < 0 or which > 1 then 487 | DEFAULT_CHAT_FRAME:AddMessage("|cFFBBBBBBTrinketMenu.GetQueue:|cFFFFFFFF Parameter must be 0 for top trinket or 1 for bottom.") 488 | return 489 | end 490 | local trinketList, name = { } 491 | for i = 1, #TrinketMenuQueue.Sort[which] do 492 | name = TrinketMenu.GetNameByID(TrinketMenuQueue.Sort[which][i]) 493 | table.insert(trinketList, name) 494 | end 495 | return TrinketMenuQueue.Enabled[which], trinketList 496 | end 497 | 498 | --[[ Profiles ]] 499 | 500 | -- add="add" or "remove" to add or remove "frame" from UISpecialFrames 501 | function TrinketMenu.Escable(frame, add) 502 | local found 503 | for i in pairs(UISpecialFrames) do 504 | found = found or (UISpecialFrames[i] == frame and i) 505 | end 506 | if not found and add == "add" then 507 | table.insert(UISpecialFrames, frame) 508 | elseif found and add == "remove" then 509 | table.remove(UISpecialFrames, found) 510 | end 511 | end 512 | 513 | -- shows profile if show non-nil. TrinketMenu_ProfilesFrame has an OnHide that calls this with nil 514 | function TrinketMenu.ShowProfiles(show) 515 | local normalTexture = TrinketMenu_Profiles:GetNormalTexture() 516 | local pushedTexture = TrinketMenu_Profiles:GetPushedTexture() 517 | if show then 518 | TrinketMenu_SortListFrame:Hide() 519 | TrinketMenu_ProfilesFrame:Show() 520 | normalTexture:SetTexCoord(.875, 1, .25, .375) 521 | pushedTexture:SetTexCoord(.75, .875, .25, .375) 522 | TrinketMenu.Escable("TrinketMenu_ProfilesFrame", "add") 523 | TrinketMenu.Escable("TrinketMenu_OptFrame", "remove") 524 | else 525 | TrinketMenu_SortListFrame:Show() 526 | TrinketMenu_ProfilesFrame:Hide() 527 | pushedTexture:SetTexCoord(.875, 1, .25, .375) 528 | normalTexture:SetTexCoord(.75, .875, .25, .375) 529 | TrinketMenu.Escable("TrinketMenu_ProfilesFrame", "remove") 530 | TrinketMenu.Escable("TrinketMenu_OptFrame", "add") 531 | end 532 | end 533 | 534 | function TrinketMenu.ProfilesFrame_OnHide() 535 | PlaySound(624) 536 | TrinketMenu.ResetProfileSelected() 537 | TrinketMenu.ShowProfiles(nil) 538 | end 539 | 540 | function TrinketMenu.ResetProfileSelected() 541 | TrinketMenu.ProfileSelected = nil 542 | TrinketMenu_ProfileName:SetText("") 543 | TrinketMenu.ProfileScrollFrameUpdate() 544 | TrinketMenu.ValidateProfile() 545 | end 546 | 547 | function TrinketMenu.ProfileScrollFrameUpdate() 548 | local offset = FauxScrollFrame_GetOffset(TrinketMenu_ProfileScroll) 549 | local list = TrinketMenuQueue.Profiles 550 | FauxScrollFrame_Update(TrinketMenu_ProfileScroll, #(list) or 0, 7, 20) 551 | local item, idx 552 | for i = 1, 7 do 553 | idx = offset + i 554 | item = _G["TrinketMenu_Profile"..i] 555 | if idx <= #list then 556 | _G["TrinketMenu_Profile"..i.."Name"]:SetText(list[idx][1]) 557 | item:Show() 558 | if TrinketMenu.ProfileSelected == idx then 559 | item:LockHighlight() 560 | else 561 | item:UnlockHighlight() 562 | end 563 | else 564 | item:Hide() 565 | end 566 | end 567 | if #list == 0 then 568 | TrinketMenu_Profile1Name:SetText("No profiles saved yet.") 569 | TrinketMenu_Profile1:Show() 570 | TrinketMenu_Profile1:UnlockHighlight() 571 | end 572 | 573 | end 574 | 575 | function TrinketMenu.ProfileList_OnClick(self) 576 | if #TrinketMenuQueue.Profiles > 0 then 577 | local idx = self:GetID() + FauxScrollFrame_GetOffset(TrinketMenu_ProfileScroll) 578 | if TrinketMenu.ProfileSelected == idx then 579 | TrinketMenu.ProfileSelected = nil 580 | TrinketMenu_ProfileName:SetText("") 581 | else 582 | TrinketMenu.ProfileSelected = idx 583 | TrinketMenu_ProfileName:SetText(TrinketMenuQueue.Profiles[idx][1]) 584 | end 585 | TrinketMenu.ProfileScrollFrameUpdate() 586 | TrinketMenu.ValidateProfile() 587 | end 588 | end 589 | 590 | function TrinketMenu.GetProfileID(name) 591 | for i = 1, #TrinketMenuQueue.Profiles do 592 | if TrinketMenuQueue.Profiles[i][1] == name then 593 | return i 594 | end 595 | end 596 | end 597 | 598 | function TrinketMenu.ValidateProfile() 599 | local name = TrinketMenu_ProfileName:GetText() or "" 600 | TrinketMenu_ProfilesDelete:Disable() 601 | TrinketMenu_ProfilesLoad:Disable() 602 | TrinketMenu_ProfilesSave:Disable() 603 | if TrinketMenu.GetProfileID(name) then 604 | TrinketMenu_ProfilesDelete:Enable() 605 | TrinketMenu_ProfilesLoad:Enable() 606 | end 607 | if strlen(name) > 0 then 608 | TrinketMenu_ProfilesSave:Enable() 609 | end 610 | end 611 | 612 | function TrinketMenu.ProfileName_OnTextChanged() 613 | TrinketMenu.ProfileSelected = TrinketMenu.GetProfileID(TrinketMenu_ProfileName:GetText()) 614 | TrinketMenu.ProfileScrollFrameUpdate() 615 | TrinketMenu.ValidateProfile() 616 | end 617 | 618 | function TrinketMenu.ProfilesButton_OnClick(self) 619 | local idx = TrinketMenu.ProfileSelected 620 | local name = TrinketMenu_ProfileName:GetText() or "" 621 | if self == TrinketMenu_ProfilesDelete then 622 | if idx and TrinketMenuQueue.Profiles[idx] then 623 | table.remove(TrinketMenuQueue.Profiles, idx) 624 | end 625 | TrinketMenu.ResetProfileSelected() 626 | elseif self == TrinketMenu_ProfilesSave then 627 | if idx and TrinketMenuQueue.Profiles[idx] then 628 | table.remove(TrinketMenuQueue.Profiles, idx) 629 | end 630 | table.insert(TrinketMenuQueue.Profiles, 1, {name}) 631 | local list = TrinketMenuQueue.Sort[TrinketMenu.CurrentlySorting] 632 | local save = TrinketMenuQueue.Profiles[1] 633 | for i = 1, #list do 634 | table.insert(save, list[i]) 635 | if list[i] == 0 then 636 | break 637 | end 638 | end 639 | TrinketMenu_ProfilesFrame:Hide() 640 | elseif self == TrinketMenu_ProfilesLoad then 641 | TrinketMenu.LoadProfile(TrinketMenu.CurrentlySorting, idx) 642 | elseif self == TrinketMenu_ProfilesCancel then 643 | TrinketMenu_ProfilesFrame:Hide() 644 | end 645 | end 646 | 647 | function TrinketMenu.ProfileList_OnDoubleClick(self) 648 | if #TrinketMenuQueue.Profiles > 0 then 649 | local idx = self:GetID() + FauxScrollFrame_GetOffset(TrinketMenu_ProfileScroll) 650 | if TrinketMenuQueue.Profiles[idx] then 651 | TrinketMenu.LoadProfile(TrinketMenu.CurrentlySorting, idx) 652 | end 653 | end 654 | end 655 | 656 | function TrinketMenu.LoadProfile(which, idx) 657 | local list = TrinketMenuQueue.Sort[which] 658 | local load = TrinketMenuQueue.Profiles[idx] 659 | for i in pairs(list) do 660 | list[i] = nil 661 | end 662 | --table.setn(list, 0) 663 | for i = 2, #load do 664 | table.insert(list, load[i]) 665 | end 666 | TrinketMenu_ProfilesFrame:Hide() 667 | TrinketMenu.OpenSort(which) 668 | if TrinketMenuOptions.HideOnLoad == "ON" then 669 | TrinketMenu_OptFrame:Hide() 670 | end 671 | end 672 | -------------------------------------------------------------------------------- /TrinketMenuQueue.xml: -------------------------------------------------------------------------------- 1 | 2 | 29 | 30 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | self:SetFrameLevel(getglobal("TrinketMenu_Tab"..self:GetID()):GetFrameLevel()+2) 57 | 58 | 59 | TrinketMenu.OnTooltip(self) 60 | 61 | 62 | GameTooltip:Hide() 63 | 64 | 65 | TrinketMenu.TabCheck_OnClick(self) 66 | 67 | 68 | 69 | 70 | 129 | 130 | 149 | 150 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 236 | 254 | 272 | 290 | 305 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | TrinketMenu.OnTooltip(self) 393 | 394 | 395 | GameTooltip:Hide() 396 | 397 | 398 | self:ClearFocus() 399 | 400 | 401 | self:ClearFocus() 402 | 403 | 404 | TrinketMenu.SortDelay_OnTextChanged() 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | TrinketMenu.SortPriority_OnClick(self) 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | TrinketMenu.SortKeepEquipped_OnClick(self) 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 489 | 494 | 499 | 504 | 509 | 514 | 519 | 524 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | FauxScrollFrame_OnVerticalScroll(self, offset, 24, TrinketMenu.SortScrollFrameUpdate) 559 | 560 | 561 | TrinketMenu.SortScrollFrameUpdate() 562 | 563 | 564 | 565 | 566 | 567 | 568 | self:OnBackdropLoaded() 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | TrinketMenu.OnTooltip(self) 672 | 673 | 674 | GameTooltip:Hide() 675 | 676 | 677 | self:ClearFocus() 678 | 679 | 680 | self:ClearFocus() 681 | 682 | 683 | TrinketMenu.ProfileName_OnTextChanged() 684 | 685 | 686 | 687 | 688 | 697 | 706 | 715 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 772 | 777 | 782 | 787 | 792 | 797 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | FauxScrollFrame_OnVerticalScroll(self, offset, 20, TrinketMenu.ProfileScrollFrameUpdate) 832 | 833 | 834 | TrinketMenu.ProfileScrollFrameUpdate() 835 | 836 | 837 | 838 | 839 | 840 | 841 | self:OnBackdropLoaded() 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | self:OnBackdropLoaded() 858 | 859 | 860 | TrinketMenu.ProfilesFrame_OnHide() 861 | 862 | 863 | PlaySound(624) 864 | 865 | 866 | 867 | 868 | 869 | 870 | -------------------------------------------------------------------------------- /TrinketMenu.lua: -------------------------------------------------------------------------------- 1 | --[[ TrinketMenu 11.1.8 ]]-- 2 | 3 | TrinketMenu = { } 4 | 5 | local _G, math, tonumber, string, type, pairs, ipairs, table, select = _G, math, tonumber, string, type, pairs, ipairs, table, select 6 | local Masque = LibStub("Masque", true) 7 | 8 | local IsClassic = WOW_PROJECT_ID >= WOW_PROJECT_CLASSIC 9 | local IsVanillaClassic = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC 10 | local IsRetail = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE 11 | 12 | -- localized strings required to support engineering bags 13 | TrinketMenu.BAG = "Bag" -- 7th return of GetItemInfo on a normal bag 14 | TrinketMenu.ENGINEERING_BAG = "Engineering Bag" -- 7th return of GetItemInfo on an engineering bag 15 | TrinketMenu.TRADE_GOODS = "Trade Goods" -- 6th return of GetItemInfo on most engineered trinkets 16 | TrinketMenu.DEVICES = "Devices" -- 7th return of GetItemInfo on most engineered trinkets 17 | TrinketMenu.REQUIRES_ENGINEERING = "Requires Engineering" -- from tooltip when GetItemInfo ambiguous 18 | 19 | function TrinketMenu.LoadDefaults() 20 | TrinketMenuOptions = TrinketMenuOptions or { 21 | IconPos = - 100, -- angle of initial minimap icon position 22 | ShowIcon = "ON", -- whether to show the minimap button 23 | SquareMinimap = "OFF", -- whether the minimap is square instead of circular 24 | CooldownCount = "OFF", -- whether to display numerical cooldown counters 25 | CooldownCountBlizzard = "ON", -- whether to display numerical blizzard cooldown counters 26 | CooldownCountOmniCC = "ON", -- whether to display numerical omnicc cooldown counters 27 | LargeCooldown = "ON", -- whether cooldown numbers are large or small 28 | TooltipFollow = "OFF", -- whether tooltips follow the mouse 29 | KeepOpen = "OFF", -- whether menu hides after use 30 | KeepDocked = "ON", -- whether to keep menu docked at all times 31 | Notify = "OFF", -- whether a message appears when a trinket is ready 32 | DisableToggle = "OFF", -- whether minimap button toggles trinkets 33 | NotifyUsedOnly = "OFF", -- whether notify happens only on trinkets used 34 | NotifyChatAlso = "OFF", -- whether to send notify to chat also 35 | Locked = "OFF", -- whether windows can be moved/scaled/rotated 36 | ShowTooltips = "ON", -- whether to display tooltips at all 37 | NotifyThirty = "OFF", -- whether to notify cooldowns at 30 seconds instead of 0 38 | MenuOnShift = "OFF", -- whether menu requires Shift to display 39 | TinyTooltips = "OFF", -- whether tooltips display only name and cooldown 40 | SetColumns = "OFF", -- whether number of columns in menu is chosen automatically 41 | Columns = 4, -- if SetColumns "ON", number of columns before menu wraps 42 | ShowHotKeys = "OFF", -- whether hotkeys show on trinkets 43 | StopOnSwap = "OFF", -- whether to stop auto queue on all manual swaps 44 | RedRange = "OFF", -- whether to monitor and red out out of range trinkets 45 | HidePetBattle = "ON", -- whether to hide the trinkets while in a pet battle 46 | MenuOnRight = "OFF" -- whether to open menu with right-click 47 | } 48 | TrinketMenuPerOptions = TrinketMenuPerOptions or { 49 | MainDock = "BOTTOMRIGHT", -- corner of main window docked to 50 | MenuDock = "BOTTOMLEFT", -- corner menu window is docked from 51 | MainOrient = "HORIZONTAL", -- direction of main window 52 | MenuOrient = "VERTICAL", -- direction of menu window 53 | XPos = 400, -- left edge of main window 54 | YPos = 400, -- top edge of main window 55 | MainScale = 1, -- scaling of main window 56 | MenuScale = 1, -- scaling of menu window 57 | Visible = "ON", -- whether to display the trinkets 58 | FirstUse = true, -- whether this is the first time this user has used the mod 59 | ItemsUsed = { }, -- table of trinkets used and their cooldown status 60 | Alpha = 1, -- alpha of both windows 61 | Hidden = { } -- table of trinkets hidden 62 | } 63 | end 64 | 65 | --[[ Misc Variables ]]-- 66 | 67 | TrinketMenu_Version = C_AddOns.GetAddOnMetadata("TrinketMenu", "Version") 68 | BINDING_HEADER_TRINKETMENU = "TrinketMenu" 69 | setglobal("BINDING_NAME_CLICK TrinketMenu_Trinket0:LeftButton", "Use Top Trinket") 70 | setglobal("BINDING_NAME_CLICK TrinketMenu_Trinket1:LeftButton", "Use Bottom Trinket") 71 | 72 | TrinketMenu.MaxTrinkets = 30 -- add more to TrinketMenu_MenuFrame if this changes 73 | TrinketMenu.BaggedTrinkets = { } -- indexed by number, 1-30 of trinkets in the menu 74 | TrinketMenu.NumberOfTrinkets = 0 -- number of trinkets in the menu 75 | TrinketMenu.CombatQueue = { } -- [0] or [1] = name of trinket queued for slot 0 or 1 76 | TrinketMenu.Corners = {"TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT"} 77 | 78 | --[[ Local functions ]]-- 79 | 80 | -- dock-dependant offset and directions: MainDock..MenuDock 81 | -- x/yoff = offset MenuFrame is positioned to MainFrame 82 | -- x/ydir = direction trinkets are added to menu 83 | -- x/ystart = starting offset when building a menu, relativePoint MenuDock 84 | if IsRetail then 85 | TrinketMenu.DockStats = { 86 | ["TOPRIGHTTOPLEFT"] = { xoff = -7, yoff = 0, xdir = 1, ydir = - 1, xstart = 4, ystart = -4 }, 87 | ["BOTTOMRIGHTBOTTOMLEFT"] = { xoff = -7, yoff = 0, xdir = 1, ydir = 1, xstart = 4, ystart = 48 }, 88 | ["TOPLEFTTOPRIGHT"] = { xoff = 7, yoff = 0, xdir = - 1, ydir = -1, xstart = -48, ystart = -4 }, 89 | ["BOTTOMLEFTBOTTOMRIGHT"] = { xoff = 7, yoff = 0, xdir = - 1, ydir = 1, xstart = -48, ystart = 48 }, 90 | ["TOPRIGHTBOTTOMRIGHT"] = { xoff = 0, yoff = -7, xdir = -1, ydir = 1, xstart = -48, ystart = 48 }, 91 | ["BOTTOMRIGHTTOPRIGHT"] = { xoff = 0, yoff = 7, xdir = - 1, ydir = -1, xstart = -48, ystart = -4 }, 92 | ["TOPLEFTBOTTOMLEFT"] = { xoff = 0, yoff = -7, xdir = 1, ydir = 1, xstart = 4, ystart = 48 }, 93 | ["BOTTOMLEFTTOPLEFT"] = { xoff = 0, yoff = 7, xdir = 1, ydir = - 1, xstart = 4, ystart = -4 } 94 | } 95 | else 96 | TrinketMenu.DockStats = { 97 | ["TOPRIGHTTOPLEFT"] = { xoff = -12, yoff = 0, xdir = 1, ydir = - 1, xstart = 8, ystart = -8 }, 98 | ["BOTTOMRIGHTBOTTOMLEFT"] = { xoff = -12, yoff = 0, xdir = 1, ydir = 1, xstart = 8, ystart = 44 }, 99 | ["TOPLEFTTOPRIGHT"] = { xoff = 12, yoff = 0, xdir = -1, ydir = -1, xstart = -44, ystart = -8 }, 100 | ["BOTTOMLEFTBOTTOMRIGHT"] = { xoff = 12, yoff = 0, xdir = -1, ydir = 1, xstart = -44, ystart = 44 }, 101 | ["TOPRIGHTBOTTOMRIGHT"] = { xoff = 0, yoff = -12, xdir = -1, ydir = 1, xstart = -44, ystart = 44 }, 102 | ["BOTTOMRIGHTTOPRIGHT"] = { xoff = 0, yoff = 12, xdir = -1, ydir = -1, xstart = -44, ystart = -8 }, 103 | ["TOPLEFTBOTTOMLEFT"] = { xoff = 0, yoff = -12, xdir = 1, ydir = 1, xstart = 8, ystart = 44 }, 104 | ["BOTTOMLEFTTOPLEFT"] = { xoff = 0, yoff = 12, xdir = 1, ydir = - 1, xstart = 8, ystart = -8 } 105 | } 106 | end 107 | 108 | -- returns offset and direction depending on current docking. ie: TrinketMenu.DockInfo("xoff") 109 | function TrinketMenu.DockInfo(arg1) 110 | local anchor = TrinketMenuPerOptions.MainDock..TrinketMenuPerOptions.MenuDock 111 | if TrinketMenu.DockStats[anchor] and arg1 and TrinketMenu.DockStats[anchor][arg1] then 112 | return TrinketMenu.DockStats[anchor][arg1] 113 | else 114 | return 0 115 | end 116 | end 117 | 118 | -- hide the docking markers 119 | function TrinketMenu.ClearDocking() 120 | for i = 1, 4 do 121 | _G["TrinketMenu_MainDock_"..TrinketMenu.Corners[i]]:Hide() 122 | _G["TrinketMenu_MenuDock_"..TrinketMenu.Corners[i]]:Hide() 123 | end 124 | end 125 | 126 | -- returns true if the two values are close to each other 127 | function TrinketMenu.Near(arg1, arg2) 128 | return (math.max(arg1, arg2) - math.min(arg1, arg2)) < 15 129 | end 130 | 131 | -- moves the MenuFrame to the dock position against MainFrame 132 | function TrinketMenu.DockWindows() 133 | TrinketMenu.ClearDocking() 134 | if TrinketMenuOptions.KeepDocked == "ON" then 135 | TrinketMenu_MenuFrame:ClearAllPoints() 136 | if TrinketMenuOptions.Locked == "OFF" then 137 | TrinketMenu_MenuFrame:SetPoint(TrinketMenuPerOptions.MenuDock, "TrinketMenu_MainFrame", TrinketMenuPerOptions.MainDock, TrinketMenu.DockInfo("xoff"), TrinketMenu.DockInfo("yoff")) 138 | else 139 | TrinketMenu_MenuFrame:SetPoint(TrinketMenuPerOptions.MenuDock, "TrinketMenu_MainFrame", TrinketMenuPerOptions.MainDock, TrinketMenu.DockInfo("xoff"), TrinketMenu.DockInfo("yoff")) 140 | end 141 | end 142 | if TrinketMenu_MenuFrame:IsVisible() then 143 | TrinketMenu.BuildMenu() 144 | end 145 | end 146 | 147 | -- displays windows vertically or horizontally 148 | function TrinketMenu.OrientWindows() 149 | if TrinketMenuPerOptions.MainOrient == "HORIZONTAL" then 150 | if IsRetail then 151 | TrinketMenu_MainFrame:SetWidth(97) 152 | TrinketMenu_MainFrame:SetHeight(52) 153 | else 154 | TrinketMenu_MainFrame:SetWidth(92) 155 | TrinketMenu_MainFrame:SetHeight(52) 156 | end 157 | else 158 | if IsRetail then 159 | TrinketMenu_MainFrame:SetWidth(52) 160 | TrinketMenu_MainFrame:SetHeight(97) 161 | else 162 | TrinketMenu_MainFrame:SetWidth(52) 163 | TrinketMenu_MainFrame:SetHeight(92) 164 | end 165 | end 166 | end 167 | 168 | function TrinketMenu.ScaleFrame(scale) 169 | TrinketMenu.FrameToScale:SetScale(scale) 170 | end 171 | 172 | function TrinketMenu.GetContainerNumSlots(bagID) 173 | return C_Container.GetContainerNumSlots(bagID) 174 | end 175 | 176 | function TrinketMenu.GetContainerItemCooldown(bagID, slotIndex) 177 | return C_Container.GetContainerItemCooldown(bagID, slotIndex) 178 | end 179 | 180 | function TrinketMenu.GetContainerItemInfo(bagID, slotIndex) 181 | return C_Container.GetContainerItemInfo(bagID, slotIndex) 182 | end 183 | 184 | function TrinketMenu.GetContainerItemLink(bagID, slotIndex) 185 | return C_Container.GetContainerItemLink(bagID, slotIndex) 186 | end 187 | 188 | function TrinketMenu.PickupContainerItem(bagID, slotIndex) 189 | return C_Container.PickupContainerItem(bagID, slotIndex) 190 | end 191 | 192 | function TrinketMenu.GetItemCooldown(itemID) 193 | return C_Container.GetItemCooldown(itemID) 194 | end 195 | 196 | -- scan inventory and build MenuFrame 197 | function TrinketMenu.BuildMenu() 198 | if not IsShiftKeyDown() and TrinketMenuOptions.MenuOnShift == "ON" then 199 | return 200 | end 201 | local idx = 1 202 | local _, itemLink, itemID, itemName, equipSlot, itemTexture 203 | -- go through bags and gather trinkets into .BaggedTrinkets 204 | for i = 0, 4 do 205 | for j = 1, TrinketMenu.GetContainerNumSlots(i) do 206 | itemLink = TrinketMenu.GetContainerItemLink(i, j) 207 | if itemLink then 208 | _, _, itemID, itemName = string.find(TrinketMenu.GetContainerItemLink(i, j) or "", "item:(%d+).+%[(.+)%]") 209 | _, _, _, _, _, _, _, _, equipSlot, itemTexture = GetItemInfo(itemID or "") 210 | if equipSlot == "INVTYPE_TRINKET" and (IsAltKeyDown() or not TrinketMenuPerOptions.Hidden[itemID]) then 211 | if not TrinketMenu.BaggedTrinkets[idx] then 212 | TrinketMenu.BaggedTrinkets[idx] = { } 213 | end 214 | TrinketMenu.BaggedTrinkets[idx].id = itemID 215 | TrinketMenu.BaggedTrinkets[idx].bag = i 216 | TrinketMenu.BaggedTrinkets[idx].slot = j 217 | TrinketMenu.BaggedTrinkets[idx].name = itemName 218 | TrinketMenu.BaggedTrinkets[idx].texture = itemTexture 219 | idx = idx + 1 220 | end 221 | end 222 | end 223 | end 224 | TrinketMenu.NumberOfTrinkets = math.min(idx - 1, TrinketMenu.MaxTrinkets) 225 | if TrinketMenu.NumberOfTrinkets < 1 then 226 | -- user has no bagged trinkets :( 227 | TrinketMenu_MenuFrame:Hide() 228 | else 229 | -- display trinkets outward from docking point 230 | local col, row, xpos, ypos = 0, 0, TrinketMenu.DockInfo("xstart"), TrinketMenu.DockInfo("ystart") 231 | local max_cols = 1 232 | if TrinketMenu.NumberOfTrinkets > 24 then 233 | max_cols = 5 234 | elseif TrinketMenu.NumberOfTrinkets > 18 then 235 | max_cols = 4 236 | elseif TrinketMenu.NumberOfTrinkets > 12 then 237 | max_cols = 3 238 | elseif TrinketMenu.NumberOfTrinkets > 4 then 239 | max_cols = 2 240 | end 241 | if TrinketMenuOptions.SetColumns == "ON" and TrinketMenuOptions.Columns then 242 | max_cols = TrinketMenuOptions.Columns 243 | end 244 | local item, icon 245 | for i = 1, TrinketMenu.NumberOfTrinkets do 246 | item = _G["TrinketMenu_Menu"..i] 247 | icon = _G["TrinketMenu_Menu"..i.."Icon"] 248 | icon:SetTexture(TrinketMenu.BaggedTrinkets[i].texture) 249 | if TrinketMenuPerOptions.Hidden[TrinketMenu.BaggedTrinkets[i].id] then 250 | icon:SetDesaturated(true) 251 | else 252 | icon:SetDesaturated(false) 253 | end 254 | item:SetPoint("TOPLEFT", "TrinketMenu_MenuFrame", TrinketMenuPerOptions.MenuDock, xpos, ypos) 255 | if TrinketMenuPerOptions.MenuOrient == "VERTICAL" then 256 | xpos = xpos + TrinketMenu.DockInfo("xdir") * (IsRetail and 45 or 40) 257 | col = col + 1 258 | if col == max_cols then 259 | xpos = TrinketMenu.DockInfo("xstart") 260 | col = 0 261 | ypos = ypos + TrinketMenu.DockInfo("ydir") * (IsRetail and 45 or 40) 262 | row = row + 1 263 | end 264 | item:Show() 265 | else 266 | ypos = ypos + TrinketMenu.DockInfo("ydir") * (IsRetail and 45 or 40) 267 | col = col + 1 268 | if col == max_cols then 269 | ypos = TrinketMenu.DockInfo("ystart") 270 | col = 0 271 | xpos = xpos + TrinketMenu.DockInfo("xdir") * (IsRetail and 45 or 40) 272 | row = row + 1 273 | end 274 | item:Show() 275 | end 276 | end 277 | for i = (TrinketMenu.NumberOfTrinkets + 1), TrinketMenu.MaxTrinkets do 278 | _G["TrinketMenu_Menu"..i]:Hide() 279 | end 280 | if col == 0 then 281 | row = row - 1 282 | end 283 | if TrinketMenuPerOptions.MenuOrient == "VERTICAL" then 284 | TrinketMenu_MenuFrame:SetWidth((IsRetail and 7 or 12) + (max_cols * (IsRetail and 45 or 40))) 285 | TrinketMenu_MenuFrame:SetHeight((IsRetail and 7 or 12) + ((row + 1) * (IsRetail and 45 or 40))) 286 | else 287 | TrinketMenu_MenuFrame:SetWidth((IsRetail and 7 or 12) + ((row + 1) * (IsRetail and 45 or 40))) 288 | TrinketMenu_MenuFrame:SetHeight((IsRetail and 7 or 12) + (max_cols * (IsRetail and 45 or 40))) 289 | end 290 | TrinketMenu.UpdateMenuCooldowns() 291 | TrinketMenu_MenuFrame:Show() 292 | TrinketMenu.StartTimer("MenuMouseover") 293 | end 294 | end 295 | 296 | function TrinketMenu.Initialize() 297 | local options = TrinketMenuOptions 298 | -- Set TrinketMenu Skin 299 | if (Masque and not TrinketMenu.MasqueGroup) then 300 | local group = Masque:Group("TrinketMenu") 301 | TrinketMenu.MasqueGroup = group 302 | group:AddButton(TrinketMenu_Trinket0) 303 | group:AddButton(TrinketMenu_Trinket1) 304 | for i = 1, 30 do 305 | _G["TrinketMenu_Menu"..i]:SetFrameLevel(2) 306 | group:AddButton(_G["TrinketMenu_Menu"..i]) 307 | end 308 | end 309 | options.KeepDocked = options.KeepDocked or "ON" -- new option for 2.1 310 | options.Notify = options.Notify or "OFF" -- 2.1 311 | options.DisableToggle = options.DisableToggle or "OFF" -- new option for 2.2 312 | options.NotifyUsedOnly = options.NotifyUsedOnly or "OFF" -- 2.2 313 | options.NotifyChatAlso = options.NotifyChatAlso or "OFF" -- 2.2 314 | options.ShowTooltips = options.ShowTooltips or "ON" -- 2.3 315 | options.NotifyThirty = options.NotifyThirty or "OFF" -- 2.5 316 | options.SquareMinimap = options.SquareMinimap or "OFF" -- 2.6 317 | options.MenuOnShift = options.MenuOnShift or "OFF" -- 2.6 318 | options.TinyTooltips = options.TinyTooltips or "OFF" -- 3.0 319 | options.SetColumns = options.SetColumns or "OFF" -- 3.0 320 | options.Columns = options.Columns or 4 -- 3.0 321 | options.CooldownCount = options.CooldownCount or "OFF" -- 3.0 322 | options.LargeCooldown = options.LargeCooldown or "OFF" -- 3.0 323 | options.ShowHotKeys = options.ShowHotKeys or "OFF" -- 3.0 324 | TrinketMenuPerOptions.ItemsUsed = TrinketMenuPerOptions.ItemsUsed or { } -- 3.0 325 | options.StopOnSwap = options.StopOnSwap or "OFF" -- 3.2 326 | options.HideOnLoad = options.HideOnLoad or "OFF" -- 3.4 327 | options.RedRange = options.RedRange or "OFF" -- 3.54 328 | options.HidePetBattle = options.HidePetBattle or "ON" -- 6.0.3 329 | options.CooldownCountBlizzard = options.CooldownCountBlizzard or "ON" -- 11.1.6 330 | options.CooldownCountOmniCC = options.CooldownCountOmniCC or "ON" -- 11.1.6 331 | TrinketMenuPerOptions.Alpha = TrinketMenuPerOptions.Alpha or 1 -- 3.5 332 | TrinketMenuPerOptions.Hidden = TrinketMenuPerOptions.Hidden or { } 333 | options.MenuOnRight = options.MenuOnRight or "OFF" -- 3.61 334 | if TrinketMenuPerOptions.XPos and TrinketMenuPerOptions.YPos then 335 | TrinketMenu_MainFrame:ClearAllPoints() 336 | TrinketMenu_MainFrame:SetPoint("TOPLEFT", "UIParent", "BOTTOMLEFT", TrinketMenuPerOptions.XPos, TrinketMenuPerOptions.YPos) 337 | end 338 | if TrinketMenuPerOptions.MainScale then 339 | TrinketMenu_MainFrame:SetScale(TrinketMenuPerOptions.MainScale) 340 | end 341 | if TrinketMenuPerOptions.MenuScale then 342 | TrinketMenu_MenuFrame:SetScale(TrinketMenuPerOptions.MenuScale) 343 | end 344 | TrinketMenu.ReflectAlpha() 345 | TrinketMenu_Trinket0:SetAttribute("type", "item") 346 | TrinketMenu_Trinket1:SetAttribute("type", "item") 347 | TrinketMenu_Trinket0:SetAttribute("slot", 13) 348 | TrinketMenu_Trinket1:SetAttribute("slot", 14) 349 | if TrinketMenu.QueueInit then 350 | -- alt has a special purpose if queue installed 351 | TrinketMenu_Trinket0:SetAttribute("alt-slot*", ATTRIBUTE_NOOP) 352 | TrinketMenu_Trinket1:SetAttribute("alt-slot*", ATTRIBUTE_NOOP) 353 | end 354 | TrinketMenu_Trinket0:SetAttribute("shift-slot*", ATTRIBUTE_NOOP) 355 | TrinketMenu_Trinket1:SetAttribute("shift-slot*", ATTRIBUTE_NOOP) 356 | TrinketMenu.ReflectMenuOnRight() 357 | TrinketMenu.InitTimers() 358 | TrinketMenu.CreateTimer("UpdateWornTrinkets", TrinketMenu.UpdateWornTrinkets, .75) 359 | TrinketMenu.CreateTimer("DockingMenu", TrinketMenu.DockingMenu, .2, 1) 360 | TrinketMenu.CreateTimer("MenuMouseover", TrinketMenu.MenuMouseover, .25, 1) 361 | TrinketMenu.CreateTimer("TooltipUpdate", TrinketMenu.TooltipUpdate, 1, 1) 362 | TrinketMenu.CreateTimer("CooldownUpdate", TrinketMenu.CooldownUpdate, 1, 1) 363 | TrinketMenu.CreateTimer("QueueUpdate", TrinketMenu.QueueUpdate, 1, 1) 364 | --TrinketMenu.CreateTimer("RedRange", TrinketMenu.RedRangeUpdate, .33, 1) 365 | hooksecurefunc("UseInventoryItem", TrinketMenu.newUseInventoryItem) 366 | hooksecurefunc("UseAction", TrinketMenu.newUseAction) 367 | TrinketMenu.InitOptions() 368 | TrinketMenu.UpdateWornTrinkets() 369 | TrinketMenu.DockWindows() 370 | TrinketMenu.OrientWindows() 371 | if options.CooldownCount == "ON" or options.NotifyThirty == "ON" or options.Notify == "ON" then 372 | TrinketMenu.StartTimer("CooldownUpdate") 373 | end 374 | if TrinketMenu_Trinket0 and TrinketMenu_Trinket0.cooldown then 375 | if options.CooldownCountBlizzard == "ON" then 376 | TrinketMenu_Trinket0.cooldown:SetHideCountdownNumbers(false) 377 | else 378 | TrinketMenu_Trinket0.cooldown:SetHideCountdownNumbers(true) 379 | end 380 | if options.CooldownCountOmniCC == "ON" then 381 | TrinketMenu_Trinket0.cooldown.noCooldownCount = false 382 | else 383 | TrinketMenu_Trinket0.cooldown.noCooldownCount = true 384 | 385 | end 386 | end 387 | if TrinketMenu_Trinket1 and TrinketMenu_Trinket1.cooldown then 388 | if options.CooldownCountBlizzard == "ON" then 389 | TrinketMenu_Trinket1.cooldown:SetHideCountdownNumbers(false) 390 | else 391 | TrinketMenu_Trinket1.cooldown:SetHideCountdownNumbers(true) 392 | end 393 | if options.CooldownCountOmniCC == "ON" then 394 | TrinketMenu_Trinket1.cooldown.noCooldownCount = false 395 | else 396 | TrinketMenu_Trinket1.cooldown.noCooldownCount = true 397 | end 398 | end 399 | for i = 1, TrinketMenu.MaxTrinkets do 400 | local menuButton = _G["TrinketMenu_Menu"..i] 401 | if menuButton and menuButton.cooldown then 402 | if options.CooldownCountBlizzard == "ON" then 403 | menuButton.cooldown:SetHideCountdownNumbers(false) 404 | else 405 | menuButton.cooldown:SetHideCountdownNumbers(true) 406 | end 407 | if options.CooldownCountOmniCC == "ON" then 408 | menuButton.cooldown.noCooldownCount = false 409 | else 410 | menuButton.cooldown.noCooldownCount = true 411 | end 412 | end 413 | end 414 | if TrinketMenu.PeriodicQueueCheck then 415 | TrinketMenu.PeriodicQueueCheck() 416 | end 417 | --TrinketMenu.StartTimer("QueueUpdate") 418 | --TrinketMenu.ReflectRedRange() 419 | if TrinketMenuPerOptions.Visible == "ON" and (GetInventoryItemLink("player", 13) or GetInventoryItemLink("player", 14)) then 420 | TrinketMenu_MainFrame:Show() 421 | end 422 | -- fix for OmniCC 423 | TrinketMenu_MainFrame:SetFrameLevel(1) 424 | TrinketMenu_MenuFrame:SetFrameLevel(1) 425 | TrinketMenu_Trinket0:SetFrameLevel(2) 426 | TrinketMenu_Trinket1:SetFrameLevel(2) 427 | for i = 1, TrinketMenu.MaxTrinkets do 428 | _G["TrinketMenu_Menu"..i]:SetFrameLevel(2) 429 | end 430 | 431 | end 432 | 433 | function TrinketMenu.ReflectMenuOnRight() 434 | TrinketMenu_Trinket0:SetAttribute("slot2", TrinketMenuOptions.MenuOnRight == "ON" and ATTRIBUTE_NOOP or nil) 435 | TrinketMenu_Trinket1:SetAttribute("slot2", TrinketMenuOptions.MenuOnRight == "ON" and ATTRIBUTE_NOOP or nil) 436 | end 437 | 438 | -- returns true if the player is really dead or ghost, not merely FD 439 | function TrinketMenu.IsPlayerReallyDead() 440 | if IsVanillaClassic then 441 | return UnitIsDeadOrGhost("player") and not UnitIsFeignDeath("player") 442 | else 443 | return UnitIsDeadOrGhost("player") 444 | end 445 | end 446 | 447 | function TrinketMenu.ItemInfo(slot) 448 | local _ 449 | local link, id, name, equipLoc, texture = GetInventoryItemLink("player", slot) 450 | if link then 451 | local _, _, id = string.find(link, "item:(%d+)") 452 | name, _, _, _, _, _, _, _, equipLoc, texture = GetItemInfo(id) 453 | else 454 | _, texture = GetInventorySlotInfo("Trinket"..(slot - 13).."Slot") 455 | end 456 | return texture, name, equipLoc 457 | end 458 | 459 | function TrinketMenu.FindItem(item, includeInventory) 460 | if includeInventory then 461 | for i = 13, 14 do 462 | local itemLink = GetInventoryItemLink("player", i) or "" 463 | local inventoryItemID = strmatch(itemLink, "item:(%d+)") 464 | local itemName = GetItemInfo(itemLink) 465 | if item == itemName or item == inventoryItemID then 466 | return i 467 | end 468 | end 469 | end 470 | for i = 0, 4 do 471 | for j = 1, TrinketMenu.GetContainerNumSlots(i) do 472 | local containerItemLink = TrinketMenu.GetContainerItemLink(i, j) or "" 473 | local containerItemID = strmatch(containerItemLink, "item:(%d+)") 474 | local containerItemName = GetItemInfo(containerItemLink) 475 | if item == containerItemName or item == containerItemID then 476 | return nil, i, j 477 | end 478 | end 479 | end 480 | end 481 | 482 | --[[ Frame Scripts ]]-- 483 | 484 | function TrinketMenu.OnLoad(self) 485 | self:OnBackdropLoaded() 486 | self:SetBackdropColor(0.0, 0.0, 0.0) 487 | self:SetBackdropBorderColor(0.0, 0.0, 0.0) 488 | SlashCmdList["TrinketMenuCOMMAND"] = TrinketMenu.SlashHandler 489 | SLASH_TrinketMenuCOMMAND1 = "/trinketmenu" 490 | SLASH_TrinketMenuCOMMAND2 = "/trinket" 491 | self:RegisterEvent("PLAYER_LOGIN") 492 | end 493 | 494 | function TrinketMenu.OnEvent(self, event, ...) 495 | if event == "UNIT_INVENTORY_CHANGED" then 496 | local unitID = ... 497 | if unitID == "player" then 498 | TrinketMenu.UpdateWornTrinkets() 499 | end 500 | elseif event == "PLAYER_EQUIPMENT_CHANGED" then 501 | TrinketMenu.UpdateWornTrinkets() 502 | elseif event == "ACTIONBAR_UPDATE_COOLDOWN" then 503 | TrinketMenu.UpdateWornCooldowns(1) 504 | elseif event == "PET_BATTLE_OPENING_START" then 505 | if TrinketMenuOptions.HidePetBattle == "ON" then 506 | TrinketMenu_MainFrame.WasShown = TrinketMenu_MainFrame:IsShown() 507 | if TrinketMenu_MainFrame.WasShown then 508 | TrinketMenu_MainFrame:Hide() 509 | end 510 | TrinketMenu_MenuFrame.WasShown = TrinketMenu_MenuFrame:IsShown() 511 | if TrinketMenu_MenuFrame.WasShown then 512 | TrinketMenu_MenuFrame:Hide() 513 | end 514 | end 515 | elseif event == "PET_BATTLE_CLOSE" then 516 | if TrinketMenuOptions.HidePetBattle == "ON" then 517 | if TrinketMenu_MainFrame.WasShown then 518 | TrinketMenu_MainFrame:Show() 519 | end 520 | if TrinketMenu_MenuFrame.WasShown then 521 | TrinketMenu_MenuFrame:Show() 522 | end 523 | end 524 | elseif (event == "PLAYER_REGEN_ENABLED" or event == "PLAYER_UNGHOST" or event == "PLAYER_ALIVE") and not TrinketMenu.IsPlayerReallyDead() then 525 | if TrinketMenu.CombatQueue[0] or TrinketMenu.CombatQueue[1] then 526 | TrinketMenu.EquipTrinketByName(TrinketMenu.CombatQueue[0], 13) 527 | TrinketMenu.EquipTrinketByName(TrinketMenu.CombatQueue[1], 14) 528 | TrinketMenu.CombatQueue[0] = nil 529 | TrinketMenu.CombatQueue[1] = nil 530 | TrinketMenu.UpdateCombatQueue() 531 | end 532 | TrinketMenu_OptMenuOnRight:Enable() 533 | elseif event == "UPDATE_BINDINGS" then 534 | TrinketMenu.KeyBindingsChanged() 535 | elseif event == "PLAYER_REGEN_DISABLED" then 536 | TrinketMenu_OptMenuOnRight:Disable() 537 | elseif event == "PLAYER_LOGIN" then 538 | TrinketMenu.LoadDefaults() 539 | TrinketMenu.Initialize() 540 | self:RegisterEvent("PLAYER_REGEN_ENABLED") 541 | self:RegisterEvent("PLAYER_REGEN_DISABLED") 542 | self:RegisterEvent("PLAYER_UNGHOST") 543 | self:RegisterEvent("PLAYER_ALIVE") 544 | self:RegisterEvent("UNIT_INVENTORY_CHANGED") 545 | self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") 546 | self:RegisterEvent("UPDATE_BINDINGS") 547 | self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN") 548 | if not IsClassic then 549 | self:RegisterEvent("PET_BATTLE_OPENING_START") 550 | self:RegisterEvent("PET_BATTLE_CLOSE") 551 | end 552 | end 553 | end 554 | 555 | function TrinketMenu.UpdateWornTrinkets() 556 | local texture, name = TrinketMenu.ItemInfo(13) 557 | TrinketMenu_Trinket0Icon:SetTexture(texture) 558 | texture, name = TrinketMenu.ItemInfo(14) 559 | TrinketMenu_Trinket1Icon:SetTexture(texture) 560 | TrinketMenu_Trinket0Icon:SetDesaturated(false) 561 | TrinketMenu_Trinket0:SetChecked(false) 562 | TrinketMenu_Trinket1Icon:SetDesaturated(false) 563 | TrinketMenu_Trinket1:SetChecked(false) 564 | TrinketMenu.UpdateWornCooldowns() 565 | if TrinketMenu_MenuFrame:IsVisible() then 566 | TrinketMenu.BuildMenu() 567 | end 568 | end 569 | 570 | function TrinketMenu.SlashHandler(msg) 571 | local _, _, which, profile = string.find(msg, "load (.+) (.+)") 572 | if profile and TrinketMenu.SetQueue then 573 | which = string.lower(which) 574 | if which == "top" or which == "0" then 575 | which = 0 576 | elseif which == "bottom" or which == "1" then 577 | which = 1 578 | end 579 | if type(which) == "number" then 580 | TrinketMenu.SetQueue(which, "SORT", profile) 581 | return 582 | end 583 | end 584 | msg = string.lower(msg) 585 | if not msg or msg == "" then 586 | TrinketMenu.ToggleFrame(TrinketMenu_MainFrame) 587 | elseif string.find(msg, "^opt") or string.find(msg, "^config") then 588 | TrinketMenu.ToggleFrame(TrinketMenu_OptFrame) 589 | elseif msg == "lock" then 590 | TrinketMenuOptions.Locked = "ON" 591 | TrinketMenu.DockWindows() 592 | TrinketMenu.ReflectLock() 593 | elseif msg == "unlock" then 594 | TrinketMenuOptions.Locked = "OFF" 595 | TrinketMenu.DockWindows() 596 | TrinketMenu.ReflectLock() 597 | elseif msg == "reset" then 598 | TrinketMenu.ResetSettings() 599 | elseif msg == "clear" then 600 | wipe(TrinketMenuPerOptions.Hidden) 601 | DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00TrinketMenu: Cleared all ignored/hidden trinkets.") 602 | elseif string.find(msg, "alpha") then 603 | local _, _, alpha = string.find(msg, "alpha (.+)") 604 | alpha = tonumber(alpha) 605 | if alpha and alpha > 0 and alpha <= 1.0 then 606 | TrinketMenuPerOptions.Alpha = alpha 607 | else 608 | DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00TrinketMenu alpha:") 609 | DEFAULT_CHAT_FRAME:AddMessage("trinket alpha (number) : set alpha from 0.1 to 1.0") 610 | end 611 | TrinketMenu.ReflectAlpha() 612 | elseif string.find(msg, "scale") then 613 | local _, _, menuscale = string.find(msg, "scale menu (.+)") 614 | if tonumber(menuscale) then 615 | TrinketMenu.FrameToScale = TrinketMenu_MenuFrame 616 | TrinketMenu.ScaleFrame(menuscale) 617 | end 618 | local _, _, mainscale = string.find(msg, "scale main (.+)") 619 | if tonumber(mainscale) then 620 | TrinketMenu.FrameToScale = TrinketMenu_MainFrame 621 | TrinketMenu.ScaleFrame(mainscale) 622 | end 623 | if not tonumber(menuscale) and not tonumber(mainscale) then 624 | DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00TrinketMenu scale:") 625 | DEFAULT_CHAT_FRAME:AddMessage("/trinket scale main (number) : set exact main scale") 626 | DEFAULT_CHAT_FRAME:AddMessage("/trinket scale menu (number) : set exact menu scale") 627 | DEFAULT_CHAT_FRAME:AddMessage("ie, /trinket scale menu 0.85") 628 | DEFAULT_CHAT_FRAME:AddMessage("Note: You can drag the lower-right corner of either window to scale. This slash command is for those who want to set an exact scale.") 629 | end 630 | TrinketMenu.FrameToScale = nil 631 | TrinketMenuPerOptions.MainScale = TrinketMenu_MainFrame:GetScale() 632 | TrinketMenuPerOptions.MenuScale = TrinketMenu_MenuFrame:GetScale() 633 | elseif string.find(msg, "load") then 634 | DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00TrinketMenu load:") 635 | DEFAULT_CHAT_FRAME:AddMessage("/trinket load (top|bottom) profilename\nie: /trinket load bottom PvP") 636 | else 637 | DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00TrinketMenu useage:") 638 | DEFAULT_CHAT_FRAME:AddMessage("/trinket or /trinketmenu : toggle the window") 639 | DEFAULT_CHAT_FRAME:AddMessage("/trinket reset : reset all settings") 640 | DEFAULT_CHAT_FRAME:AddMessage("/trinket clear : clear all ignored/hidden trinkets") 641 | DEFAULT_CHAT_FRAME:AddMessage("/trinket opt : summon options window") 642 | DEFAULT_CHAT_FRAME:AddMessage("/trinket lock|unlock : toggles window lock") 643 | DEFAULT_CHAT_FRAME:AddMessage("/trinket scale main|menu (number) : sets an exact scale") 644 | DEFAULT_CHAT_FRAME:AddMessage("/trinket load top|bottom profilename : loads a profile to top or bottom trinket") 645 | end 646 | end 647 | 648 | function TrinketMenu.ResetSettings() 649 | StaticPopupDialogs["TRINKETMENURESET"] = { 650 | text = "Are you sure you want to reset TrinketMenu to default state and reload the UI?", 651 | button1 = "Yes", button2 = "No", showAlert = 1, timeout = 0, whileDead = 1, 652 | OnAccept = function() 653 | TrinketMenuOptions = nil 654 | TrinketMenuPerOptions = nil 655 | TrinketMenuQueue = nil 656 | ReloadUI() 657 | end 658 | } 659 | StaticPopup_Show("TRINKETMENURESET") 660 | end 661 | 662 | --[[ Window Movement ]]-- 663 | 664 | function TrinketMenu.MainFrame_OnMouseUp(self) 665 | local arg1 = GetMouseButtonClicked() 666 | if arg1 == "LeftButton" then 667 | self:StopMovingOrSizing() 668 | TrinketMenuPerOptions.XPos = TrinketMenu_MainFrame:GetLeft() 669 | TrinketMenuPerOptions.YPos = TrinketMenu_MainFrame:GetTop() 670 | elseif TrinketMenuOptions.Locked == "OFF" then 671 | if TrinketMenuPerOptions.MainOrient == "VERTICAL" then 672 | TrinketMenuPerOptions.MainOrient = "HORIZONTAL" 673 | else 674 | TrinketMenuPerOptions.MainOrient = "VERTICAL" 675 | end 676 | TrinketMenu.OrientWindows() 677 | end 678 | end 679 | 680 | function TrinketMenu.MainFrame_OnMouseDown(self) 681 | if GetMouseButtonClicked() == "LeftButton" and TrinketMenuOptions.Locked == "OFF" then 682 | self:StartMoving() 683 | end 684 | end 685 | 686 | --[[ Timers ]] 687 | 688 | function TrinketMenu.InitTimers() 689 | TrinketMenu.TimerPool = { } 690 | TrinketMenu.Timers = { } 691 | end 692 | 693 | function TrinketMenu.CreateTimer(name, func, delay, rep) 694 | TrinketMenu.TimerPool[name] = {func = func, delay = delay, rep = rep, elapsed = delay} 695 | end 696 | 697 | function TrinketMenu.IsTimerActive(name) 698 | for i, j in ipairs(TrinketMenu.Timers) do 699 | if j == name then 700 | return i 701 | end 702 | end 703 | return nil 704 | end 705 | 706 | function TrinketMenu.StartTimer(name, delay) 707 | TrinketMenu.TimerPool[name].elapsed = delay or TrinketMenu.TimerPool[name].delay 708 | if not TrinketMenu.IsTimerActive(name) then 709 | table.insert(TrinketMenu.Timers, name) 710 | TrinketMenu_TimersFrame:Show() 711 | end 712 | end 713 | 714 | function TrinketMenu.StopTimer(name) 715 | local idx = TrinketMenu.IsTimerActive(name) 716 | if idx then 717 | table.remove(TrinketMenu.Timers, idx) 718 | if #TrinketMenu.Timers < 1 then 719 | TrinketMenu_TimersFrame:Hide() 720 | end 721 | end 722 | end 723 | 724 | function TrinketMenu.TimersFrame_OnUpdate(elapsed) 725 | local timerPool 726 | for _, name in ipairs(TrinketMenu.Timers) do 727 | timerPool = TrinketMenu.TimerPool[name] 728 | timerPool.elapsed = timerPool.elapsed - elapsed 729 | if timerPool.elapsed < 0 then 730 | timerPool.func() 731 | if timerPool.rep then 732 | timerPool.elapsed = timerPool.delay 733 | else 734 | TrinketMenu.StopTimer(name) 735 | end 736 | end 737 | end 738 | if TrinketMenu.PeriodicQueueCheck then 739 | TrinketMenu.PeriodicQueueCheck() 740 | end -- Check for auto queue 741 | end 742 | 743 | function TrinketMenu.TimerDebug() 744 | local on = "|cFF00FF00On" 745 | local off = "|cFFFF0000Off" 746 | DEFAULT_CHAT_FRAME:AddMessage("|cFF44AAFFTrinketMenu_TimersFrame is "..(TrinketMenu_TimersFrame:IsVisible() and on or off)) 747 | for i in pairs(TrinketMenu.TimerPool) do 748 | DEFAULT_CHAT_FRAME:AddMessage(i.." is "..(TrinketMenu.IsTimerActive(i) and on or off)) 749 | end 750 | end 751 | 752 | --[[ OnClicks ]] 753 | 754 | function TrinketMenu.MainTrinket_OnClick(self, button, down) 755 | self:SetChecked(false) 756 | if button == "RightButton" and TrinketMenuOptions.MenuOnRight == "ON" then 757 | if TrinketMenu_MenuFrame:IsVisible() then 758 | TrinketMenu_MenuFrame:Hide() 759 | else 760 | TrinketMenu.BuildMenu() 761 | end 762 | elseif IsShiftKeyDown() and down then 763 | if ChatFrame1EditBox:IsVisible() then 764 | ChatFrame1EditBox:Insert(GetInventoryItemLink("player", self:GetID())) 765 | end 766 | elseif IsAltKeyDown() and not down and TrinketMenu.QueueInit then 767 | local which = self:GetID() - 13 768 | if TrinketMenuQueue.Enabled[which] then 769 | TrinketMenu.CombatQueue[self:GetID() - 13] = nil 770 | TrinketMenuQueue.Enabled[which] = nil 771 | else 772 | TrinketMenuQueue.Enabled[which] = 1 773 | end 774 | TrinketMenu.ReflectQueueEnabled() 775 | -- toggle queue 776 | TrinketMenu.UpdateCombatQueue() 777 | else 778 | TrinketMenu.ReflectTrinketUse(self:GetID()) 779 | end 780 | end 781 | 782 | function TrinketMenu.MenuTrinket_OnClick(self, button, down) 783 | self:SetChecked(false) 784 | if IsShiftKeyDown() and ChatFrame1EditBox:IsVisible() then 785 | ChatFrame1EditBox:Insert(TrinketMenu.GetContainerItemLink(TrinketMenu.BaggedTrinkets[self:GetID()].bag, TrinketMenu.BaggedTrinkets[self:GetID()].slot)) 786 | elseif IsAltKeyDown() then 787 | local _, _, itemID = string.find(TrinketMenu.GetContainerItemLink(TrinketMenu.BaggedTrinkets[self:GetID()].bag, TrinketMenu.BaggedTrinkets[self:GetID()].slot) or "", "item:(%d+)") 788 | if TrinketMenuPerOptions.Hidden[itemID] then 789 | TrinketMenuPerOptions.Hidden[itemID] = nil 790 | else 791 | TrinketMenuPerOptions.Hidden[itemID] = 1 792 | end 793 | TrinketMenu.BuildMenu() 794 | else 795 | local slot = (button == "LeftButton") and 13 or 14 796 | if TrinketMenu.QueueInit then 797 | local _, _, canCooldown = TrinketMenu.GetContainerItemCooldown(TrinketMenu.BaggedTrinkets[self:GetID()].bag, TrinketMenu.BaggedTrinkets[self:GetID()].slot) 798 | if canCooldown == 0 or TrinketMenuOptions.StopOnSwap == "ON" then -- if incoming trinket can't go on cooldown 799 | TrinketMenuQueue.Enabled[slot - 13] = nil -- turn off autoqueue 800 | TrinketMenu.ReflectQueueEnabled() 801 | end 802 | end 803 | TrinketMenu.EquipTrinketByName(TrinketMenu.BaggedTrinkets[self:GetID()].name, slot) 804 | if not IsShiftKeyDown() and TrinketMenuOptions.KeepOpen == "OFF" then 805 | TrinketMenu_MenuFrame:Hide() 806 | end 807 | end 808 | end 809 | 810 | --[[ Docking ]] 811 | 812 | function TrinketMenu.MenuFrame_OnMouseDown(button) 813 | if button == "LeftButton" and TrinketMenuOptions.Locked == "OFF" then 814 | TrinketMenu_MenuFrame:StartMoving() 815 | if TrinketMenuOptions.KeepDocked == "ON" then 816 | TrinketMenu.StartTimer("DockingMenu") 817 | end 818 | end 819 | end 820 | 821 | function TrinketMenu.MenuFrame_OnMouseUp(button) 822 | if button == "LeftButton" then 823 | TrinketMenu.StopTimer("DockingMenu") 824 | TrinketMenu_MenuFrame:StopMovingOrSizing() 825 | if TrinketMenuOptions.KeepDocked == "ON" then 826 | TrinketMenu.DockWindows() 827 | end 828 | elseif TrinketMenuOptions.Locked == "OFF" then 829 | if TrinketMenuPerOptions.MenuOrient == "VERTICAL" then 830 | TrinketMenuPerOptions.MenuOrient = "HORIZONTAL" 831 | else 832 | TrinketMenuPerOptions.MenuOrient = "VERTICAL" 833 | end 834 | TrinketMenu.BuildMenu() 835 | end 836 | end 837 | 838 | function TrinketMenu.DockingMenu() 839 | local main = TrinketMenu_MainFrame 840 | local menu = TrinketMenu_MenuFrame 841 | local mainscale = TrinketMenu_MainFrame:GetScale() 842 | local menuscale = TrinketMenu_MenuFrame:GetScale() 843 | local near = TrinketMenu.Near 844 | if near(main:GetRight() * mainscale,menu:GetLeft() * menuscale) then 845 | if near(main:GetTop() * mainscale,menu:GetTop() * menuscale) then 846 | TrinketMenuPerOptions.MainDock = "TOPRIGHT" 847 | TrinketMenuPerOptions.MenuDock = "TOPLEFT" 848 | elseif near(main:GetBottom() * mainscale,menu:GetBottom() * menuscale) then 849 | TrinketMenuPerOptions.MainDock = "BOTTOMRIGHT" 850 | TrinketMenuPerOptions.MenuDock = "BOTTOMLEFT" 851 | end 852 | elseif near(main:GetLeft() * mainscale,menu:GetRight() * menuscale) then 853 | if near(main:GetTop() * mainscale,menu:GetTop() * menuscale) then 854 | TrinketMenuPerOptions.MainDock = "TOPLEFT" 855 | TrinketMenuPerOptions.MenuDock = "TOPRIGHT" 856 | elseif near(main:GetBottom() * mainscale,menu:GetBottom() * menuscale) then 857 | TrinketMenuPerOptions.MainDock = "BOTTOMLEFT" 858 | TrinketMenuPerOptions.MenuDock = "BOTTOMRIGHT" 859 | end 860 | elseif near(main:GetRight() * mainscale,menu:GetRight() * menuscale) then 861 | if near(main:GetTop() * mainscale,menu:GetBottom() * menuscale) then 862 | TrinketMenuPerOptions.MainDock = "TOPRIGHT" 863 | TrinketMenuPerOptions.MenuDock = "BOTTOMRIGHT" 864 | elseif near(main:GetBottom() * mainscale,menu:GetTop() * menuscale) then 865 | TrinketMenuPerOptions.MainDock = "BOTTOMRIGHT" 866 | TrinketMenuPerOptions.MenuDock = "TOPRIGHT" 867 | end 868 | elseif near(main:GetLeft() * mainscale,menu:GetLeft() * menuscale) then 869 | if near(main:GetTop() * mainscale,menu:GetBottom() * menuscale) then 870 | TrinketMenuPerOptions.MainDock = "TOPLEFT" 871 | TrinketMenuPerOptions.MenuDock = "BOTTOMLEFT" 872 | elseif near(main:GetBottom() * mainscale,menu:GetTop() * menuscale) then 873 | TrinketMenuPerOptions.MainDock = "BOTTOMLEFT" 874 | TrinketMenuPerOptions.MenuDock = "TOPLEFT" 875 | end 876 | end 877 | TrinketMenu.ClearDocking() 878 | _G["TrinketMenu_MainDock_"..TrinketMenuPerOptions.MainDock]:Show() 879 | _G["TrinketMenu_MenuDock_"..TrinketMenuPerOptions.MenuDock]:Show() 880 | end 881 | 882 | function TrinketMenu.MenuMouseover() 883 | if (not MouseIsOver(TrinketMenu_MainFrame)) and (not MouseIsOver(TrinketMenu_MenuFrame)) and not IsShiftKeyDown() and (TrinketMenuOptions.KeepOpen == "OFF") then 884 | TrinketMenu.StopTimer("MenuMouseover") 885 | TrinketMenu_MenuFrame:Hide() 886 | end 887 | end 888 | 889 | --[[ Cooldowns ]] 890 | 891 | function TrinketMenu.UpdateWornCooldowns(maybeGlobal) 892 | local start, duration, enable = GetInventoryItemCooldown("player", 13) 893 | CooldownFrame_Set(TrinketMenu_Trinket0Cooldown, start, duration, enable) 894 | start, duration, enable = GetInventoryItemCooldown("player", 14) 895 | CooldownFrame_Set(TrinketMenu_Trinket1Cooldown, start, duration, enable) 896 | if not maybeGlobal then 897 | TrinketMenu.WriteWornCooldowns() 898 | end 899 | end 900 | 901 | function TrinketMenu.UpdateMenuCooldowns() 902 | local start, duration, enable 903 | for i = 1, TrinketMenu.NumberOfTrinkets do 904 | start,duration,enable = TrinketMenu.GetContainerItemCooldown(TrinketMenu.BaggedTrinkets[i].bag, TrinketMenu.BaggedTrinkets[i].slot) 905 | CooldownFrame_Set(_G["TrinketMenu_Menu"..i.."Cooldown"], start, duration, enable) 906 | end 907 | TrinketMenu.WriteMenuCooldowns() 908 | end 909 | 910 | --[[ Item use ]] 911 | 912 | function TrinketMenu.ReflectTrinketUse(slot) 913 | _G["TrinketMenu_Trinket"..(slot - 13)]:SetChecked(true) 914 | TrinketMenu.StartTimer("UpdateWornTrinkets") 915 | local _, _, id = string.find(GetInventoryItemLink("player", slot) or "", "item:(%d+)") 916 | if id then 917 | TrinketMenuPerOptions.ItemsUsed[id] = 0 -- 0 is an indeterminate state, cooldown will figure if it's worth watching 918 | end 919 | end 920 | 921 | function TrinketMenu.newUseInventoryItem(slot) 922 | if slot == 13 or slot == 14 and not MerchantFrame:IsVisible() then 923 | TrinketMenu.ReflectTrinketUse(slot) 924 | end 925 | end 926 | 927 | function TrinketMenu.newUseAction(slot) 928 | if IsEquippedAction(slot) then 929 | TrinketMenu_TooltipScan:SetOwner(WorldFrame, "ANCHOR_NONE") 930 | TrinketMenu_TooltipScan:SetAction(slot) 931 | local _, trinket0 = TrinketMenu.ItemInfo(13) 932 | local _, trinket1 = TrinketMenu.ItemInfo(14) 933 | if GameTooltipTextLeft1:GetText() == trinket0 then 934 | TrinketMenu.ReflectTrinketUse(13) 935 | elseif GameTooltipTextLeft1:GetText() == trinket1 then 936 | TrinketMenu.ReflectTrinketUse(14) 937 | end 938 | end 939 | end 940 | 941 | --[[ Tooltips ]] 942 | 943 | function TrinketMenu.WornTrinketTooltip(self) 944 | if TrinketMenuOptions.ShowTooltips == "OFF" then 945 | return 946 | end 947 | local id = self:GetID() 948 | TrinketMenu.TooltipOwner = self 949 | TrinketMenu.TooltipType = "INVENTORY" 950 | TrinketMenu.TooltipSlot = id 951 | TrinketMenu.TooltipBag = TrinketMenu.CombatQueue[id - 13] 952 | TrinketMenu.StartTimer("TooltipUpdate", 0) 953 | end 954 | 955 | function TrinketMenu.MenuTrinketTooltip(self) 956 | if TrinketMenuOptions.ShowTooltips == "OFF" then 957 | return 958 | end 959 | local id = self:GetID() 960 | TrinketMenu.TooltipOwner = self 961 | TrinketMenu.TooltipType = "BAG" 962 | TrinketMenu.TooltipBag = TrinketMenu.BaggedTrinkets[id].bag 963 | TrinketMenu.TooltipSlot = TrinketMenu.BaggedTrinkets[id].slot 964 | TrinketMenu.StartTimer("TooltipUpdate", 0) 965 | end 966 | 967 | function TrinketMenu.ClearTooltip() 968 | GameTooltip:Hide() 969 | TrinketMenu.StopTimer("TooltipUpdate") 970 | TrinketMenu.TooltipType = nil 971 | end 972 | 973 | function TrinketMenu.AnchorTooltip(self) 974 | if TrinketMenuOptions.TooltipFollow == "ON" then 975 | if self.GetLeft and self:GetLeft() and self:GetLeft() < 400 then 976 | GameTooltip:SetOwner(self, "ANCHOR_RIGHT") 977 | else 978 | GameTooltip:SetOwner(self, "ANCHOR_LEFT") 979 | end 980 | else 981 | GameTooltip_SetDefaultAnchor(GameTooltip, self) 982 | end 983 | end 984 | 985 | -- updates the tooltip created in the functions above 986 | function TrinketMenu.TooltipUpdate() 987 | if TrinketMenu.TooltipType then 988 | local cooldown 989 | TrinketMenu.AnchorTooltip(TrinketMenu.TooltipOwner) 990 | if TrinketMenu.TooltipType == "BAG" then 991 | GameTooltip:SetBagItem(TrinketMenu.TooltipBag, TrinketMenu.TooltipSlot) 992 | cooldown = TrinketMenu.GetContainerItemCooldown(TrinketMenu.TooltipBag, TrinketMenu.TooltipSlot) 993 | else 994 | GameTooltip:SetInventoryItem("player", TrinketMenu.TooltipSlot) 995 | cooldown = GetInventoryItemCooldown("player", TrinketMenu.TooltipSlot) 996 | end 997 | TrinketMenu.ShrinkTooltip(TrinketMenu.TooltipOwner) -- if TinyTooltips on, shrink it 998 | if TrinketMenu.TooltipType == "INVENTORY" and TrinketMenu.TooltipBag then 999 | GameTooltip:AddLine("Queued: "..TrinketMenu.TooltipBag) 1000 | end 1001 | GameTooltip:Show() 1002 | if cooldown == 0 then 1003 | -- stop updates if this trinket has no cooldown 1004 | TrinketMenu.TooltipType = nil 1005 | TrinketMenu.StopTimer("TooltipUpdate") 1006 | end 1007 | end 1008 | 1009 | end 1010 | 1011 | -- normal tooltip for options 1012 | function TrinketMenu.OnTooltip(self, line1, line2) 1013 | if TrinketMenuOptions.ShowTooltips == "ON" then 1014 | TrinketMenu.AnchorTooltip(self) 1015 | if line1 then 1016 | GameTooltip:AddLine(line1) 1017 | GameTooltip:AddLine(line2, .8, .8, .8, 1) 1018 | GameTooltip:Show() 1019 | else 1020 | local name = self:GetName() or "" 1021 | for i = 1, #TrinketMenu.CheckOptInfo do 1022 | if name == "TrinketMenu_Opt"..TrinketMenu.CheckOptInfo[i][1] and TrinketMenu.CheckOptInfo[i][3] then 1023 | TrinketMenu.OnTooltip(self, TrinketMenu.CheckOptInfo[i][3], TrinketMenu.CheckOptInfo[i][4]) 1024 | end 1025 | end 1026 | for i = 1, #TrinketMenu.TooltipInfo do 1027 | if TrinketMenu.TooltipInfo[i][1] == name and TrinketMenu.TooltipInfo[i][2] then 1028 | TrinketMenu.OnTooltip(self, TrinketMenu.TooltipInfo[i][2], TrinketMenu.TooltipInfo[i][3]) 1029 | end 1030 | end 1031 | end 1032 | end 1033 | end 1034 | 1035 | -- strip format reordering in global strings 1036 | TrinketMenu.ITEM_SPELL_CHARGES = string.gsub(ITEM_SPELL_CHARGES, "%%%d%$d", "%%d") 1037 | 1038 | function TrinketMenu.ShrinkTooltip(owner) 1039 | if TrinketMenuOptions.TinyTooltips == "ON" then 1040 | local r, g, b = GameTooltipTextLeft1:GetTextColor() 1041 | local name = GameTooltipTextLeft1:GetText() 1042 | local line, cooldown, charge 1043 | for i = 2, GameTooltip:NumLines() do 1044 | line = _G["GameTooltipTextLeft"..i] 1045 | if line:IsVisible() then 1046 | line = line:GetText() or "" 1047 | if string.find(line, COOLDOWN_REMAINING) then 1048 | cooldown = line 1049 | end 1050 | if string.find(line, TrinketMenu.ITEM_SPELL_CHARGES) then 1051 | charge = line 1052 | end 1053 | end 1054 | end 1055 | TrinketMenu.AnchorTooltip(owner) 1056 | GameTooltip:AddLine(name, r, g, b) 1057 | GameTooltip:AddLine(charge, 1, 1, 1) 1058 | GameTooltip:AddLine(cooldown, 1, 1, 1) 1059 | end 1060 | end 1061 | 1062 | -- returns 1 if the item at bag(,slot) is an engineered trinket 1063 | function TrinketMenu.IsEngineered(bag, slot) 1064 | local item = slot and TrinketMenu.GetContainerItemLink(bag, slot) or GetInventoryItemLink("player", bag) 1065 | if item then 1066 | local _, _, _, _, _, itemType, itemSubtype, _, itemLoc = GetItemInfo(item) 1067 | if itemType == TrinketMenu.TRADE_GOODS and itemSubtype == TrinketMenu.DEVICES and itemLoc == "INVTYPE_TRINKET" then 1068 | return 1 1069 | end 1070 | TrinketMenu_TooltipScan:SetOwner(WorldFrame, "ANCHOR_NONE") 1071 | TrinketMenu_TooltipScan:SetHyperlink(item) 1072 | for i = 1, TrinketMenu_TooltipScan:NumLines() do 1073 | if string.match(_G["TrinketMenu_TooltipScanTextLeft"..i]:GetText() or "", TrinketMenu.REQUIRES_ENGINEERING) then 1074 | return 1 1075 | end 1076 | end 1077 | end 1078 | end 1079 | 1080 | -- returns bag,slot of a free bag space, if one found. engineering true if only looking for an engineering bag 1081 | function TrinketMenu.FindSpace(engineering) 1082 | local bagType 1083 | for i = 4, 0, -1 do 1084 | bagType = (select(7, GetItemInfo(GetInventoryItemLink("player", 19 + i) or ""))) 1085 | if (engineering and bagType == TrinketMenu.ENGINEERING_BAG) or (not engineering and bagType == TrinketMenu.BAG) then 1086 | for j = 1, TrinketMenu.GetContainerNumSlots(i) do 1087 | if not TrinketMenu.GetContainerItemLink(i, j) then 1088 | return i, j 1089 | end 1090 | end 1091 | end 1092 | end 1093 | end 1094 | 1095 | --[[ Combat Queue ]] 1096 | 1097 | function TrinketMenu.EquipTrinketByName(name, slot) 1098 | if not name then 1099 | return 1100 | end 1101 | if UnitAffectingCombat("player") or TrinketMenu.IsPlayerReallyDead() or (IsRetail and C_PetBattles.IsInBattle() or false) then 1102 | -- queue trinket 1103 | local queue = TrinketMenu.CombatQueue 1104 | local which = slot - 13 -- 0 or 1 1105 | if queue[which] == name then 1106 | queue[which] = nil 1107 | elseif queue[1 - which] == name then 1108 | queue[1 - which] = nil 1109 | queue[which] = name 1110 | else 1111 | queue[which] = name 1112 | end 1113 | elseif not CursorHasItem() and not SpellIsTargeting() then 1114 | local _, b, s = TrinketMenu.FindItem(name) 1115 | if b then 1116 | if not TrinketMenu.GetContainerItemInfo(b, s).isLocked and not IsInventoryItemLocked(slot) then 1117 | -- neither container item nor inventory item locked, perform swap 1118 | local directSwap = true -- assume a direct swap will happen 1119 | if (select(7, GetItemInfo(GetInventoryItemLink("player", 19 + b) or ""))) == TrinketMenu.ENGINEERING_BAG then 1120 | -- incoming trinket is in an engineering bag 1121 | if not TrinketMenu.IsEngineered(slot) then 1122 | -- outgoing trinket can't go inside it 1123 | local freeBag,freeSlot = TrinketMenu.FindSpace() 1124 | if freeBag then 1125 | PickupInventoryItem(slot) 1126 | TrinketMenu.PickupContainerItem(freeBag, freeSlot) 1127 | TrinketMenu.PickupContainerItem(b, s) 1128 | EquipCursorItem(slot) 1129 | directSwap = nil 1130 | end 1131 | end 1132 | elseif TrinketMenu.IsEngineered(slot) and not TrinketMenu.IsEngineered(b, s) then 1133 | -- outgoing trinket is engineered, incoming trinket is not 1134 | local freeBag, freeSlot = TrinketMenu.FindSpace(1) 1135 | if freeBag then 1136 | -- move outgoing trinket to engineering bag, equip incoming trinket 1137 | PickupInventoryItem(slot) 1138 | TrinketMenu.PickupContainerItem(freeBag, freeSlot) 1139 | TrinketMenu.PickupContainerItem(b, s) 1140 | EquipCursorItem(slot) 1141 | directSwap = nil 1142 | end 1143 | end 1144 | if directSwap then 1145 | TrinketMenu.PickupContainerItem(b, s) 1146 | PickupInventoryItem(slot) 1147 | end 1148 | _G["TrinketMenu_Trinket"..(slot - 13).."Icon"]:SetDesaturated(true) 1149 | TrinketMenu.StartTimer("UpdateWornTrinkets") -- in case it's not equipped (stunned, etc) 1150 | end 1151 | end 1152 | end 1153 | TrinketMenu.UpdateCombatQueue() 1154 | end 1155 | 1156 | function TrinketMenu.UpdateCombatQueue() 1157 | local _, bag, slot 1158 | for which = 0, 1 do 1159 | local trinket = TrinketMenu.CombatQueue[which] 1160 | local icon = _G["TrinketMenu_Trinket"..which.."Queue"] 1161 | icon:Hide() 1162 | if trinket then 1163 | _, bag, slot = TrinketMenu.FindItem(trinket) 1164 | if bag then 1165 | icon:SetTexture(TrinketMenu.GetContainerItemInfo(bag, slot).iconFileID) 1166 | icon:Show() 1167 | end 1168 | elseif TrinketMenu.QueueInit and TrinketMenuQueue and TrinketMenuQueue.Enabled[which] then 1169 | icon:SetTexture("Interface\\AddOns\\TrinketMenu\\Textures\\TrinketMenu-Gear") 1170 | icon:Show() 1171 | end 1172 | end 1173 | end 1174 | 1175 | --[[ Notify ]] 1176 | 1177 | function TrinketMenu.Notify(msg) 1178 | PlaySound(4146) 1179 | if MikSBT then -- send via MSBT if it exists 1180 | MikSBT.DisplayMessage(msg, "Notification", true, 255, 0, 0, nil, nil, nil, nil) 1181 | elseif SCT_Display then -- send via SCT if it exists 1182 | SCT_Display(msg, {r = .2, g = .7, b = .9}) 1183 | elseif Parrot then -- send via Parrot if it exists 1184 | Parrot:ShowMessage(msg, "Notification", true, 255, 0, 0, nil, nil, nil, nil) 1185 | elseif xCT then -- send via xCT if it exists 1186 | ct.frames[3]:AddMessage(msg, 255, 0, 0) 1187 | elseif xCT_Plus then -- send via xCT+ if it exists 1188 | xCT_Plus:AddMessage("general", msg, {1, 0, 0}) 1189 | elseif SHOW_COMBAT_TEXT == "1" and CombatText_AddMessage then -- or default UI's SCT 1190 | CombatText_AddMessage(msg, CombatText_StandardScroll, .2, .7, .9) 1191 | else 1192 | -- send vis UIErrorsFrame if neither SCT exists 1193 | UIErrorsFrame:AddMessage(msg, .2, .7, .9, 1, UIERRORS_HOLD_TIME) 1194 | end 1195 | if TrinketMenuOptions.NotifyChatAlso == "ON" then 1196 | DEFAULT_CHAT_FRAME:AddMessage("|cff33b2e5"..msg) 1197 | end 1198 | end 1199 | 1200 | function TrinketMenu.CooldownUpdate() 1201 | local inv, bag, slot, start, duration, name, remain 1202 | for i in pairs(TrinketMenuPerOptions.ItemsUsed) do 1203 | start, duration = TrinketMenu.GetItemCooldown(i) 1204 | if start and TrinketMenuPerOptions.ItemsUsed[i] < 3 then 1205 | TrinketMenuPerOptions.ItemsUsed[i] = TrinketMenuPerOptions.ItemsUsed[i] + 1 -- count for 3 seconds before seeing if this is a real cooldown 1206 | elseif start then 1207 | if start > 0 then 1208 | remain = duration - (GetTime() - start) 1209 | if TrinketMenuPerOptions.ItemsUsed[i] < 5 then 1210 | if remain > 29 then 1211 | TrinketMenuPerOptions.ItemsUsed[i] = 30 -- first actual cooldown greater than 30 seconds, tag it for 30+0 notify 1212 | elseif remain > 5 then 1213 | TrinketMenuPerOptions.ItemsUsed[i] = 5 -- first actual cooldown less than 30 but greater than 5, tag for 0 notify 1214 | end 1215 | end 1216 | end 1217 | if TrinketMenuPerOptions.ItemsUsed[i] == 30 and start > 0 and remain < 30 then 1218 | if TrinketMenuOptions.NotifyThirty == "ON" then 1219 | name = GetItemInfo(i) 1220 | if name then 1221 | TrinketMenu.Notify(name.." ready soon!") 1222 | end 1223 | end 1224 | TrinketMenuPerOptions.ItemsUsed[i] = 5 -- tag for just 0 notify now 1225 | elseif TrinketMenuPerOptions.ItemsUsed[i] == 5 and start == 0 then 1226 | if TrinketMenuOptions.Notify == "ON" then 1227 | name = GetItemInfo(i) 1228 | if name then 1229 | TrinketMenu.Notify(name.." ready!") 1230 | end 1231 | end 1232 | end 1233 | if start == 0 then 1234 | TrinketMenuPerOptions.ItemsUsed[i] = nil 1235 | end 1236 | end 1237 | end 1238 | -- update cooldown numbers 1239 | if TrinketMenuOptions.CooldownCount == "ON" then 1240 | if TrinketMenu_MainFrame:IsVisible() then 1241 | TrinketMenu.WriteWornCooldowns() 1242 | end 1243 | if TrinketMenu_MenuFrame:IsVisible() then 1244 | TrinketMenu.WriteMenuCooldowns() 1245 | end 1246 | end 1247 | end 1248 | 1249 | function TrinketMenu.QueueUpdate() 1250 | if TrinketMenu.PeriodicQueueCheck then 1251 | TrinketMenu.PeriodicQueueCheck() 1252 | end 1253 | end 1254 | 1255 | function TrinketMenu.WriteWornCooldowns() 1256 | local start, duration 1257 | start, duration = GetInventoryItemCooldown("player", 13) 1258 | TrinketMenu.WriteCooldown(TrinketMenu_Trinket0Time, start, duration) 1259 | start, duration = GetInventoryItemCooldown("player", 14) 1260 | TrinketMenu.WriteCooldown(TrinketMenu_Trinket1Time, start, duration) 1261 | end 1262 | 1263 | function TrinketMenu.WriteMenuCooldowns() 1264 | local start, duration 1265 | for i = 1, TrinketMenu.NumberOfTrinkets do 1266 | start, duration = TrinketMenu.GetContainerItemCooldown(TrinketMenu.BaggedTrinkets[i].bag, TrinketMenu.BaggedTrinkets[i].slot) 1267 | TrinketMenu.WriteCooldown(_G["TrinketMenu_Menu"..i.."Time"], start, duration) 1268 | end 1269 | end 1270 | 1271 | function TrinketMenu.WriteCooldown(where, start, duration) 1272 | local cooldown = duration - (GetTime() - start) 1273 | if start == 0 or TrinketMenuOptions.CooldownCount == "OFF" then 1274 | where:SetText("") 1275 | elseif cooldown < 3 and not where:GetText() then 1276 | -- this is a global cooldown. don't display it. not accurate but at least not annoying 1277 | else 1278 | where:SetText((cooldown < 60 and math.floor(cooldown + .5).." s") or (cooldown < 3600 and math.ceil(cooldown / 60).." m") or math.ceil(cooldown / 3600).." h") 1279 | end 1280 | end 1281 | 1282 | function TrinketMenu.OnShow() 1283 | TrinketMenuPerOptions.Visible = "ON" 1284 | if TrinketMenuOptions.KeepOpen == "ON" then 1285 | TrinketMenu.BuildMenu() 1286 | end 1287 | end 1288 | 1289 | function TrinketMenu.OnHide() 1290 | TrinketMenu_MenuFrame:Hide() 1291 | TrinketMenuPerOptions.Visible = "OFF" 1292 | end 1293 | 1294 | function TrinketMenu.ReflectAlpha() 1295 | TrinketMenu_MainFrame:SetAlpha(TrinketMenuPerOptions.Alpha) 1296 | TrinketMenu_MenuFrame:SetAlpha(TrinketMenuPerOptions.Alpha) 1297 | end 1298 | 1299 | --[[ Key bindings ]] 1300 | 1301 | function TrinketMenu.KeyBindingsChanged() 1302 | if TrinketMenuOptions.ShowHotKeys == "ON" then 1303 | local key 1304 | for i = 0, 1 do 1305 | key = GetBindingKey("CLICK TrinketMenu_Trinket"..i..":LeftButton") 1306 | _G["TrinketMenu_Trinket"..i.."HotKey"]:SetText(GetBindingText(key or "", nil, 1)) 1307 | end 1308 | else 1309 | TrinketMenu_Trinket0HotKey:SetText("") 1310 | TrinketMenu_Trinket1HotKey:SetText("") 1311 | end 1312 | end 1313 | 1314 | --[[ Monitor Range ]] 1315 | 1316 | --[[function TrinketMenu.ReflectRedRange() 1317 | if TrinketMenuOptions.RedRange == "ON" then 1318 | TrinketMenu.StartTimer("RedRange") 1319 | else 1320 | TrinketMenu.StopTimer("RedRange") 1321 | TrinketMenu_Trinket0Icon:SetVertexColor(1, 1, 1) 1322 | TrinketMenu_Trinket1Icon:SetVertexColor(1, 1, 1) 1323 | end 1324 | end 1325 | 1326 | function TrinketMenu.RedRangeUpdate() 1327 | local item 1328 | for i = 13, 14 do 1329 | item = GetInventoryItemLink("player", i) 1330 | if item and C_Item.IsItemInRange(item, "target") == 0 then 1331 | _G["TrinketMenu_Trinket"..(i - 13).."Icon"]:SetVertexColor(1, .3, .3) 1332 | else 1333 | _G["TrinketMenu_Trinket"..(i - 13).."Icon"]:SetVertexColor(1, 1, 1) 1334 | end 1335 | end 1336 | end]] 1337 | --------------------------------------------------------------------------------