Add and optimize requested TokensWorth modules
Merge the audited TokensWorth-derived modules and ClassicAPI-focused optimizations into the default branch.
This commit is contained in:
@@ -670,3 +670,218 @@ Static audit is complete. Before merging to the stable branch, test:
|
|||||||
Do not merge this audit branch solely on static analysis. Treat the branch as a
|
Do not merge this audit branch solely on static analysis. Treat the branch as a
|
||||||
test candidate until the in-game matrix has passed without Lua errors or UI
|
test candidate until the in-game matrix has passed without Lua errors or UI
|
||||||
regressions.
|
regressions.
|
||||||
|
|
||||||
|
|
||||||
|
## TokensWorth requested modules — test branch audit
|
||||||
|
|
||||||
|
Branch: `tokensworth-mods-classicapi-test`
|
||||||
|
|
||||||
|
Seven requested modules were added for runtime testing. **Improved Roll Frames was
|
||||||
|
not duplicated** because an optimized version already exists in
|
||||||
|
ShaguTweaks-ClassicAPI.
|
||||||
|
|
||||||
|
### Mouseover Right / Mouseover Right 2
|
||||||
|
|
||||||
|
The original implementation created one independent mouse-catching overlay for
|
||||||
|
every action button plus the bar itself. The test version uses one invisible
|
||||||
|
reveal area per bar and one 100 ms controller that only runs while the bar is
|
||||||
|
visible. When hidden, there is no polling.
|
||||||
|
|
||||||
|
The helper preserves existing bar OnShow/OnHide scripts and tracks the native
|
||||||
|
`SHOW_MULTI_ACTIONBAR_3` / `SHOW_MULTI_ACTIONBAR_4` state through
|
||||||
|
`CVAR_UPDATE`.
|
||||||
|
|
||||||
|
### Hide Macro Text
|
||||||
|
|
||||||
|
One-time UI update only. No ClassicAPI replacement is useful for this FrameXML
|
||||||
|
operation and no periodic work is installed.
|
||||||
|
|
||||||
|
### Unit Frame Abbreviated Names
|
||||||
|
|
||||||
|
The original target-of-target implementation recalculated the name on every
|
||||||
|
rendered frame. The test version uses ClassicAPI event validation and
|
||||||
|
`UNIT_TARGET` when available. Only environments without that event use a
|
||||||
|
250 ms fallback ticker.
|
||||||
|
|
||||||
|
### Movable Unit Frames Extended
|
||||||
|
|
||||||
|
The permanent per-frame Ctrl+Shift check was removed. The module uses
|
||||||
|
`ShaguTweaks.API.IsShiftKeyDown`, `API.IsControlKeyDown` and
|
||||||
|
`MODIFIER_STATE_CHANGED` when ClassicAPI exposes modifier-state events.
|
||||||
|
|
||||||
|
The grid is created lazily on the first unlock. Positions are stored in the
|
||||||
|
existing `ShaguTweaks_config["MoveUnitframesExtended"]` table.
|
||||||
|
|
||||||
|
For the requested Turtle layout, the debuff anchor is **BuffButton32** instead
|
||||||
|
of the upstream BuffButton16.
|
||||||
|
|
||||||
|
### Cursor Tooltip
|
||||||
|
|
||||||
|
The original global `GameTooltip_SetDefaultAnchor` replacement was removed.
|
||||||
|
The test version keeps the native function intact through the ShaguTweaks safe
|
||||||
|
post-hook helper. Cursor tracking runs only while a default-anchored tooltip is
|
||||||
|
shown.
|
||||||
|
|
||||||
|
### Hide Combat Tooltip
|
||||||
|
|
||||||
|
The original combat-long per-frame Shift polling was removed. ClassicAPI's
|
||||||
|
modifier event updates the tooltip only when modifier state actually changes.
|
||||||
|
A 50 ms combat-only fallback exists for environments without that event.
|
||||||
|
|
||||||
|
The GameTooltip Show method is post-hooked so tooltips opened after entering
|
||||||
|
combat immediately inherit the correct hidden/Shift-visible state.
|
||||||
|
|
||||||
|
### Runtime validation required
|
||||||
|
|
||||||
|
Before merging this branch, test:
|
||||||
|
|
||||||
|
- login and `/reload` with the seven new modules disabled
|
||||||
|
- each module individually enabled
|
||||||
|
- both Mouseover Right modules together
|
||||||
|
- toggle the two right actionbars in Interface Options while mouseover modules are enabled
|
||||||
|
- stance/bonus actionbar changes with Hide Macro Text enabled
|
||||||
|
- long NPC target names and target-of-target changes
|
||||||
|
- Ctrl+Shift dragging of party frames, minimap, BuffButton0, BuffButton32 and TempEnchant1
|
||||||
|
- relog/reload persistence of moved positions
|
||||||
|
- Cursor Tooltip alone, Hide Combat Tooltip alone, and both enabled together
|
||||||
|
- combat tooltip Shift reveal/re-hide behavior
|
||||||
|
- interaction with DragonflightUI-Reforged's injected ShaguTweaks Extras list
|
||||||
|
- Lua errors and visible FPS regressions
|
||||||
|
|
||||||
|
Static code review is complete; this branch remains a runtime test candidate.
|
||||||
|
|
||||||
|
|
||||||
|
### Cursor Tooltip — focused audit / optimization
|
||||||
|
|
||||||
|
A focused audit compared the test implementation with the TokensWorth upstream
|
||||||
|
module.
|
||||||
|
|
||||||
|
Findings:
|
||||||
|
|
||||||
|
- the feature genuinely needs frame-by-frame cursor coordinates while the
|
||||||
|
tooltip is visible; there is no ClassicAPI event that can replace pointer
|
||||||
|
tracking
|
||||||
|
- the previous test implementation showed its cursor tracker as soon as
|
||||||
|
`GameTooltip_SetDefaultAnchor` ran, even though default anchoring normally
|
||||||
|
happens before `GameTooltip:Show()`
|
||||||
|
- `ClearAllPoints()` on the cursor tracker every rendered frame was
|
||||||
|
unnecessary
|
||||||
|
- moving the tracker while the mouse coordinates were unchanged caused
|
||||||
|
avoidable layout work
|
||||||
|
- replacing `GameTooltip_SetDefaultAnchor` for every possible tooltip caller
|
||||||
|
could affect non-`GameTooltip` frames unnecessarily
|
||||||
|
|
||||||
|
The optimized test version now:
|
||||||
|
|
||||||
|
- starts its `OnUpdate` work only while the actual `GameTooltip` is shown
|
||||||
|
- performs one immediate cursor-position update before Show to avoid a first
|
||||||
|
frame jump
|
||||||
|
- skips `SetPoint` when cursor coordinates and UI scale have not changed
|
||||||
|
- reuses the same CENTER anchor without per-frame `ClearAllPoints`
|
||||||
|
- keeps the original default-anchor helper for non-`GameTooltip` callers
|
||||||
|
- keeps `SetClampedToScreen(true)` so the cursor tooltip remains inside the
|
||||||
|
visible UI area
|
||||||
|
- retains the intentional default-anchor replacement because a post-hook alone
|
||||||
|
was not reliable on Vanilla/Turtle layout code
|
||||||
|
|
||||||
|
No ClassicAPI-specific replacement is useful here. `GetCursorPosition`,
|
||||||
|
tooltip ownership and frame anchoring are native UI operations. The optimized
|
||||||
|
design therefore keeps the unavoidable cursor-following `OnUpdate`, but only
|
||||||
|
for the time where that work is actually needed.
|
||||||
|
|
||||||
|
|
||||||
|
## Remaining TokensWorth modules — focused audit
|
||||||
|
|
||||||
|
The remaining requested TokensWorth-derived modules were reviewed against their
|
||||||
|
upstream implementations and the current ClassicAPI/ShaguTweaks architecture.
|
||||||
|
|
||||||
|
### Mouseover Right / Mouseover Right 2 — optimized
|
||||||
|
|
||||||
|
Both options continue to use one shared helper instead of duplicating the
|
||||||
|
upstream implementation.
|
||||||
|
|
||||||
|
Upstream creates one mouse-catching overlay for each of the 12 buttons plus an
|
||||||
|
additional bar overlay for each actionbar. The ClassicAPI test version keeps one
|
||||||
|
hotspot and one controller per bar.
|
||||||
|
|
||||||
|
The focused audit additionally:
|
||||||
|
|
||||||
|
- caches the native actionbar visibility flag from `CVAR_UPDATE` /
|
||||||
|
`PLAYER_ENTERING_WORLD` instead of looking it up on every watcher tick
|
||||||
|
- replaces repeated `GetTime()` deadline checks with a simple accumulated
|
||||||
|
two-second idle timer
|
||||||
|
- removes a duplicate watcher restart when the hidden bar is revealed
|
||||||
|
- leaves the watcher disabled while the bar is hidden
|
||||||
|
- preserves any pre-existing bar `OnShow` / `OnHide` scripts
|
||||||
|
|
||||||
|
The remaining 100 ms watcher only exists while the relevant actionbar is
|
||||||
|
actually visible and waiting to auto-hide. No ClassicAPI API can replace the
|
||||||
|
required mouse-over state check.
|
||||||
|
|
||||||
|
### Hide Macro Text — retained as-is
|
||||||
|
|
||||||
|
No hot-path issue was found.
|
||||||
|
|
||||||
|
The module performs a single pass over the native action-button FontStrings and
|
||||||
|
sets their alpha to zero. It installs no event handlers, no hooks and no
|
||||||
|
`OnUpdate`.
|
||||||
|
|
||||||
|
Using ClassicAPI would add abstraction without benefit because this is a
|
||||||
|
one-time FrameXML presentation change. The current implementation is already
|
||||||
|
effectively zero-cost after enable.
|
||||||
|
|
||||||
|
### Unit Frame Abbreviated Names — further optimized
|
||||||
|
|
||||||
|
The upstream module recalculates target-of-target text on every rendered frame.
|
||||||
|
|
||||||
|
The ClassicAPI version already prefers validated `UNIT_TARGET` and
|
||||||
|
`UNIT_NAME_UPDATE` events, with a 250 ms fallback only where `UNIT_TARGET`
|
||||||
|
is unavailable.
|
||||||
|
|
||||||
|
The focused audit additionally:
|
||||||
|
|
||||||
|
- caches the raw unit name and abbreviated result
|
||||||
|
- skips repeated abbreviation/string work while the underlying unit name is
|
||||||
|
unchanged
|
||||||
|
- skips `FontString:SetText` when the displayed text is already correct
|
||||||
|
- limits the legacy fallback to cases where `targettarget` actually exists
|
||||||
|
|
||||||
|
### Movable Unit Frames Extended — hardened
|
||||||
|
|
||||||
|
The upstream module polls Ctrl+Shift every rendered frame. The ClassicAPI
|
||||||
|
version uses `MODIFIER_STATE_CHANGED` plus the shared modifier helpers, with a
|
||||||
|
100 ms fallback only for environments without ClassicAPI modifier events.
|
||||||
|
|
||||||
|
The focused audit found a correctness issue in the first test conversion:
|
||||||
|
merely pressing and releasing Ctrl+Shift saved absolute positions for every
|
||||||
|
managed frame, even if the user had not dragged them. On later logins this
|
||||||
|
could turn untouched Blizzard-managed frames into explicit absolute-position
|
||||||
|
frames.
|
||||||
|
|
||||||
|
The hardened version now:
|
||||||
|
|
||||||
|
- saves a position only after that specific frame was actually dragged
|
||||||
|
- preserves and restores the original drag scripts
|
||||||
|
- preserves and restores the original mouse-enabled state
|
||||||
|
- preserves the original movable state
|
||||||
|
- restores the original user-placed state for untouched frames
|
||||||
|
- only marks a frame user-placed when a real drag starts
|
||||||
|
- keeps the grid lazily created on first unlock
|
||||||
|
- retains the requested Turtle WoW `BuffButton32` debuff anchor
|
||||||
|
|
||||||
|
### Current status
|
||||||
|
|
||||||
|
The focused static audit found no additional change worth making to
|
||||||
|
`actionbar-mouseover-bar-right.lua`,
|
||||||
|
`actionbar-mouseover-bar-right2.lua` or `actionbar-hide-macro.lua` beyond
|
||||||
|
their shared/helper behavior.
|
||||||
|
|
||||||
|
Runtime validation is still required before merge, especially for:
|
||||||
|
|
||||||
|
- enabling/disabling the two native right actionbars while mouseover hiding is
|
||||||
|
active
|
||||||
|
- repeated reveal/hide cycles with action buttons clicked normally
|
||||||
|
- abbreviated target-of-target names during rapid target switching
|
||||||
|
- Ctrl+Shift without dragging anything, followed by relog/reload
|
||||||
|
- dragging each supported frame individually, followed by relog/reload
|
||||||
|
- default party/buff/minimap layout remaining unchanged for frames never moved
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ Settings: **Esc → Advanced Options**.
|
|||||||
- Buy Em All uses ClassicAPI merchant, item count and bag-family data, including specialty bags.
|
- Buy Em All uses ClassicAPI merchant, item count and bag-family data, including specialty bags.
|
||||||
- Added modifier-aware Key-Down Casting with Shift/Ctrl/Alt binding support and an independent Alt Self-Cast option.
|
- Added modifier-aware Key-Down Casting with Shift/Ctrl/Alt binding support and an independent Alt Self-Cast option.
|
||||||
- Added Metric Range for metre labels in range tooltips without changing numeric values.
|
- Added Metric Range for metre labels in range tooltips without changing numeric values.
|
||||||
|
- Added optimized modules adapted from TokensWorth/ShaguTweaks-mods: Mouseover Right bars, Hide Macro Text, Unit Frame Abbreviated Names, Movable Unit Frames Extended, Cursor Tooltip and Hide Combat Tooltip.
|
||||||
|
- Movable Unit Frames Extended and Hide Combat Tooltip use ClassicAPI modifier-state events instead of permanent per-frame modifier polling.
|
||||||
- Various stability fixes across legacy ShaguTweaks Extras modules.
|
- Various stability fixes across legacy ShaguTweaks Extras modules.
|
||||||
|
|
||||||
## 🔷 Mods using ClassicAPI integration
|
## 🔷 Mods using ClassicAPI integration
|
||||||
@@ -55,12 +57,15 @@ Settings: **Esc → Advanced Options**.
|
|||||||
- Alt Self-Cast
|
- Alt Self-Cast
|
||||||
- Macro Icons
|
- Macro Icons
|
||||||
- Macro Tweaks
|
- Macro Tweaks
|
||||||
|
- Movable Unit Frames Extended
|
||||||
- Raid Frames
|
- Raid Frames
|
||||||
- Reagent Counter
|
- Reagent Counter
|
||||||
- Reveal World Map
|
- Reveal World Map
|
||||||
- Show Dispel Indicators
|
- Show Dispel Indicators
|
||||||
- Show Bags
|
- Show Bags
|
||||||
- Show Micro Menu
|
- Show Micro Menu
|
||||||
|
- Hide Combat Tooltip
|
||||||
|
- Unit Frame Abbreviated Names
|
||||||
|
|
||||||
Other modules can also benefit indirectly from ClassicAPI through shared ShaguTweaks libraries and helpers.
|
Other modules can also benefit indirectly from ClassicAPI through shared ShaguTweaks libraries and helpers.
|
||||||
|
|
||||||
@@ -76,6 +81,9 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
|
|||||||
- Show Micro Menu
|
- Show Micro Menu
|
||||||
- Key-Down Casting
|
- Key-Down Casting
|
||||||
- Alt Self-Cast
|
- Alt Self-Cast
|
||||||
|
- Mouseover Right
|
||||||
|
- Mouseover Right 2
|
||||||
|
- Hide Macro Text
|
||||||
|
|
||||||
### Bags & Inventory
|
### Bags & Inventory
|
||||||
|
|
||||||
@@ -90,6 +98,13 @@ Other modules can also benefit indirectly from ClassicAPI through shared ShaguTw
|
|||||||
### Tooltip & Items
|
### Tooltip & Items
|
||||||
|
|
||||||
- Metric Range
|
- Metric Range
|
||||||
|
- Cursor Tooltip
|
||||||
|
- Hide Combat Tooltip
|
||||||
|
|
||||||
|
### Unit Frames
|
||||||
|
|
||||||
|
- Unit Frame Abbreviated Names
|
||||||
|
- Movable Unit Frames Extended
|
||||||
|
|
||||||
### World Map
|
### World Map
|
||||||
|
|
||||||
@@ -127,10 +142,11 @@ Macro Tweaks adds convenient ClassicAPI-backed aliases:
|
|||||||
|
|
||||||
## 🧹 Removed duplicates
|
## 🧹 Removed duplicates
|
||||||
|
|
||||||
The following original Extras modules are not included because improved versions already exist in ShaguTweaks-ClassicAPI:
|
The following modules are not included because improved versions already exist in ShaguTweaks-ClassicAPI:
|
||||||
|
|
||||||
- **Chat History** → integrated into **Chat Tweaks**
|
- **Chat History** → integrated into **Chat Tweaks**
|
||||||
- **Show Energy Ticks** → integrated as **Energy & Mana Tick**
|
- **Show Energy Ticks** → integrated as **Energy & Mana Tick**
|
||||||
|
- **Improved Roll Frames** → already integrated and optimized in **ShaguTweaks-ClassicAPI**
|
||||||
|
|
||||||
## 🔧 Compatibility
|
## 🔧 Compatibility
|
||||||
|
|
||||||
@@ -147,4 +163,6 @@ Additional maintenance and Turtle WoW work by **paokkerkir**.
|
|||||||
|
|
||||||
ClassicAPI compatibility fork maintained by **Dusk-92**.
|
ClassicAPI compatibility fork maintained by **Dusk-92**.
|
||||||
|
|
||||||
|
Additional requested modules adapted from **TokensWorth/ShaguTweaks-mods**, originally released under MIT by **GryllsAddons**. See `THIRD_PARTY_NOTICES.md`.
|
||||||
|
|
||||||
Released under the original **MIT License**.
|
Released under the original **MIT License**.
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ mods\actionbar-float.lua
|
|||||||
mods\classic-snowfall.lua
|
mods\classic-snowfall.lua
|
||||||
mods\reduced-actionbar-bags.lua
|
mods\reduced-actionbar-bags.lua
|
||||||
mods\reduced-actionbar-micromenu.lua
|
mods\reduced-actionbar-micromenu.lua
|
||||||
|
mods\actionbar-mouseover-common.lua
|
||||||
|
mods\actionbar-mouseover-bar-right.lua
|
||||||
|
mods\actionbar-mouseover-bar-right2.lua
|
||||||
|
mods\actionbar-hide-macro.lua
|
||||||
|
|
||||||
# bags & inventory
|
# bags & inventory
|
||||||
mods\bag-item-click.lua
|
mods\bag-item-click.lua
|
||||||
@@ -37,6 +41,12 @@ mods\buy-em-all.lua
|
|||||||
|
|
||||||
# tooltip & items
|
# tooltip & items
|
||||||
mods\metric-range.lua
|
mods\metric-range.lua
|
||||||
|
mods\cursor-tooltip.lua
|
||||||
|
mods\hide-combat-tooltip.lua
|
||||||
|
|
||||||
|
# unit frames
|
||||||
|
mods\unitframes-abbrev-names.lua
|
||||||
|
mods\move-unitframes-extended.lua
|
||||||
|
|
||||||
# world map
|
# world map
|
||||||
mods\worldmap-reveal.lua
|
mods\worldmap-reveal.lua
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Third-Party Notices
|
||||||
|
|
||||||
|
## TokensWorth/ShaguTweaks-mods
|
||||||
|
|
||||||
|
The following modules in this fork contain code adapted from
|
||||||
|
`TokensWorth/ShaguTweaks-mods`:
|
||||||
|
|
||||||
|
- `mods/actionbar-mouseover-common.lua`
|
||||||
|
- `mods/actionbar-mouseover-bar-right.lua`
|
||||||
|
- `mods/actionbar-mouseover-bar-right2.lua`
|
||||||
|
- `mods/actionbar-hide-macro.lua`
|
||||||
|
- `mods/unitframes-abbrev-names.lua`
|
||||||
|
- `mods/move-unitframes-extended.lua`
|
||||||
|
- `mods/cursor-tooltip.lua`
|
||||||
|
- `mods/hide-combat-tooltip.lua`
|
||||||
|
|
||||||
|
Source:
|
||||||
|
https://github.com/TokensWorth/ShaguTweaks-mods
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 GryllsAddons
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local _G = ShaguTweaks.GetGlobalEnv()
|
||||||
|
local T = ShaguTweaks.T
|
||||||
|
|
||||||
|
local module = ShaguTweaks:register({
|
||||||
|
title = T["Hide Macro Text"],
|
||||||
|
description = T["Hides macro names on action buttons."],
|
||||||
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Action Bar"],
|
||||||
|
enabled = nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.enable = function(self)
|
||||||
|
local function HideMacroText(button)
|
||||||
|
if not button or not button.GetName then return end
|
||||||
|
|
||||||
|
local name = button:GetName()
|
||||||
|
local text = name and _G[name .. "Name"]
|
||||||
|
if text then text:SetAlpha(0) end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, 24 do
|
||||||
|
HideMacroText(_G["BonusActionButton" .. i])
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, 12 do
|
||||||
|
HideMacroText(_G["ActionButton" .. i])
|
||||||
|
HideMacroText(_G["MultiBarRightButton" .. i])
|
||||||
|
HideMacroText(_G["MultiBarLeftButton" .. i])
|
||||||
|
HideMacroText(_G["MultiBarBottomLeftButton" .. i])
|
||||||
|
HideMacroText(_G["MultiBarBottomRightButton" .. i])
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local T = ShaguTweaks.T
|
||||||
|
|
||||||
|
local module = ShaguTweaks:register({
|
||||||
|
title = T["Mouseover Right"],
|
||||||
|
description = T["Hide the right actionbar and show it on mouseover."],
|
||||||
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Action Bar"],
|
||||||
|
enabled = nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.enable = function(self)
|
||||||
|
ShaguTweaks.CreateMouseoverActionBar(MultiBarRight, "SHOW_MULTI_ACTIONBAR_3")
|
||||||
|
end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local T = ShaguTweaks.T
|
||||||
|
|
||||||
|
local module = ShaguTweaks:register({
|
||||||
|
title = T["Mouseover Right 2"],
|
||||||
|
description = T["Hide the second right actionbar and show it on mouseover."],
|
||||||
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Action Bar"],
|
||||||
|
enabled = nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.enable = function(self)
|
||||||
|
ShaguTweaks.CreateMouseoverActionBar(MultiBarLeft, "SHOW_MULTI_ACTIONBAR_4")
|
||||||
|
end
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
-- Shared mouseover actionbar helper.
|
||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local _G = ShaguTweaks.GetGlobalEnv()
|
||||||
|
|
||||||
|
if not ShaguTweaks.CreateMouseoverActionBar then
|
||||||
|
ShaguTweaks.CreateMouseoverActionBar = function(bar, visibilityFlag)
|
||||||
|
if not bar or not visibilityFlag then return end
|
||||||
|
if bar.ShaguTweaksMouseoverController then return end
|
||||||
|
|
||||||
|
local controller = CreateFrame("Frame", nil, UIParent)
|
||||||
|
local hotspot = CreateFrame("Frame", nil, UIParent)
|
||||||
|
|
||||||
|
controller.bar = bar
|
||||||
|
controller.hotspot = hotspot
|
||||||
|
controller.visibilityFlag = visibilityFlag
|
||||||
|
controller.enabled = false
|
||||||
|
controller.elapsed = 0
|
||||||
|
controller.idle = 0
|
||||||
|
|
||||||
|
bar.ShaguTweaksMouseoverController = controller
|
||||||
|
|
||||||
|
-- One invisible reveal area replaces the original per-button overlay
|
||||||
|
-- frames. It only accepts mouse input while the actionbar is hidden.
|
||||||
|
hotspot:SetAllPoints(bar)
|
||||||
|
hotspot:SetFrameStrata("DIALOG")
|
||||||
|
hotspot:EnableMouse(false)
|
||||||
|
hotspot:Hide()
|
||||||
|
|
||||||
|
local function ReadEnabled()
|
||||||
|
return _G[visibilityFlag] and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function StopWatching()
|
||||||
|
controller:SetScript("OnUpdate", nil)
|
||||||
|
controller.elapsed = 0
|
||||||
|
controller.idle = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function StartWatching()
|
||||||
|
if not controller.enabled or not bar:IsShown() then return end
|
||||||
|
|
||||||
|
hotspot:EnableMouse(false)
|
||||||
|
controller.elapsed = 0
|
||||||
|
controller.idle = 0
|
||||||
|
|
||||||
|
controller:SetScript("OnUpdate", function()
|
||||||
|
this.elapsed = this.elapsed + (arg1 or 0)
|
||||||
|
if this.elapsed < .10 then return end
|
||||||
|
|
||||||
|
local step = this.elapsed
|
||||||
|
this.elapsed = 0
|
||||||
|
|
||||||
|
if not this.enabled then
|
||||||
|
StopWatching()
|
||||||
|
hotspot:EnableMouse(false)
|
||||||
|
hotspot:Hide()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not bar:IsShown() then
|
||||||
|
StopWatching()
|
||||||
|
hotspot:Show()
|
||||||
|
hotspot:EnableMouse(true)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if MouseIsOver(bar) then
|
||||||
|
this.idle = 0
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
this.idle = this.idle + step
|
||||||
|
if this.idle >= 2 then
|
||||||
|
StopWatching()
|
||||||
|
bar:Hide()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Sync()
|
||||||
|
controller.enabled = ReadEnabled()
|
||||||
|
|
||||||
|
if not controller.enabled then
|
||||||
|
StopWatching()
|
||||||
|
hotspot:EnableMouse(false)
|
||||||
|
hotspot:Hide()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
hotspot:Show()
|
||||||
|
|
||||||
|
if bar:IsShown() then
|
||||||
|
StartWatching()
|
||||||
|
else
|
||||||
|
hotspot:EnableMouse(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hotspot:SetScript("OnEnter", function()
|
||||||
|
if not controller.enabled then return end
|
||||||
|
|
||||||
|
hotspot:EnableMouse(false)
|
||||||
|
bar:Show()
|
||||||
|
-- The bar's OnShow script starts the watcher. Avoid a second redundant
|
||||||
|
-- StartWatching() call here.
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Keep existing scripts intact while observing native/UI-addon visibility
|
||||||
|
-- changes. These wrappers are installed once per bar.
|
||||||
|
local oldOnShow = bar:GetScript("OnShow")
|
||||||
|
bar:SetScript("OnShow", function()
|
||||||
|
if oldOnShow then oldOnShow() end
|
||||||
|
if controller.enabled then StartWatching() end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local oldOnHide = bar:GetScript("OnHide")
|
||||||
|
bar:SetScript("OnHide", function()
|
||||||
|
if oldOnHide then oldOnHide() end
|
||||||
|
|
||||||
|
StopWatching()
|
||||||
|
|
||||||
|
if controller.enabled then
|
||||||
|
hotspot:Show()
|
||||||
|
hotspot:EnableMouse(true)
|
||||||
|
else
|
||||||
|
hotspot:EnableMouse(false)
|
||||||
|
hotspot:Hide()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
controller:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
|
controller:RegisterEvent("CVAR_UPDATE")
|
||||||
|
controller:SetScript("OnEvent", Sync)
|
||||||
|
|
||||||
|
Sync()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local _G = ShaguTweaks.GetGlobalEnv()
|
||||||
|
local T = ShaguTweaks.T
|
||||||
|
local hooksecurefunc = ShaguTweaks.hooksecurefunc
|
||||||
|
|
||||||
|
local module = ShaguTweaks:register({
|
||||||
|
title = T["Cursor Tooltip"],
|
||||||
|
description = T["Attaches default tooltips to the cursor."],
|
||||||
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Tooltip & Items"],
|
||||||
|
enabled = nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.enable = function(self)
|
||||||
|
if ShaguTweaks.CursorTooltipInstalled then return end
|
||||||
|
ShaguTweaks.CursorTooltipInstalled = true
|
||||||
|
|
||||||
|
-- Keep the native helper for non-GameTooltip callers. The feature only
|
||||||
|
-- needs to move the normal world/UI GameTooltip and should not unexpectedly
|
||||||
|
-- change other tooltip frames that may reuse the same helper.
|
||||||
|
local originalDefaultAnchor = ShaguTweaks.CursorTooltipOriginalDefaultAnchor
|
||||||
|
or _G.GameTooltip_SetDefaultAnchor
|
||||||
|
|
||||||
|
ShaguTweaks.CursorTooltipOriginalDefaultAnchor = originalDefaultAnchor
|
||||||
|
|
||||||
|
local cursor = CreateFrame("Frame", nil, UIParent)
|
||||||
|
cursor:SetWidth(1)
|
||||||
|
cursor:SetHeight(1)
|
||||||
|
cursor:Hide()
|
||||||
|
|
||||||
|
local following = false
|
||||||
|
local lastX, lastY, lastScale
|
||||||
|
|
||||||
|
local function UpdateCursor(force)
|
||||||
|
local scale = UIParent:GetEffectiveScale()
|
||||||
|
if not scale or scale == 0 then scale = UIParent:GetScale() end
|
||||||
|
if not scale or scale == 0 then scale = 1 end
|
||||||
|
|
||||||
|
local x, y = GetCursorPosition()
|
||||||
|
|
||||||
|
-- GetCursorPosition is cheap and required for following the pointer, but
|
||||||
|
-- avoid a frame-layout operation while the mouse is completely still.
|
||||||
|
if not force and x == lastX and y == lastY and scale == lastScale then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
lastX, lastY, lastScale = x, y, scale
|
||||||
|
|
||||||
|
-- Reusing the same CENTER anchor updates it in place; ClearAllPoints every
|
||||||
|
-- rendered frame is unnecessary.
|
||||||
|
cursor:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x / scale, y / scale)
|
||||||
|
end
|
||||||
|
|
||||||
|
cursor:SetScript("OnUpdate", function()
|
||||||
|
if not following or not GameTooltip:IsShown() then
|
||||||
|
this:Hide()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
UpdateCursor(false)
|
||||||
|
end)
|
||||||
|
|
||||||
|
function _G.GameTooltip_SetDefaultAnchor(tooltip, parent)
|
||||||
|
if tooltip ~= GameTooltip then
|
||||||
|
return originalDefaultAnchor(tooltip, parent)
|
||||||
|
end
|
||||||
|
|
||||||
|
tooltip:SetOwner(parent or UIParent, "ANCHOR_NONE")
|
||||||
|
tooltip:ClearAllPoints()
|
||||||
|
|
||||||
|
-- Position once before Show() so there is no first-frame jump from the
|
||||||
|
-- cursor frame's default origin.
|
||||||
|
UpdateCursor(true)
|
||||||
|
|
||||||
|
tooltip:SetPoint("BOTTOMLEFT", cursor, "TOPRIGHT", 12, 12)
|
||||||
|
tooltip:SetClampedToScreen(true)
|
||||||
|
tooltip.default = 1
|
||||||
|
|
||||||
|
following = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Default anchoring normally happens before GameTooltip:Show(). Start the
|
||||||
|
-- per-frame cursor tracker only once the tooltip is actually visible.
|
||||||
|
hooksecurefunc(GameTooltip, "Show", function()
|
||||||
|
if not following then return end
|
||||||
|
|
||||||
|
UpdateCursor(true)
|
||||||
|
cursor:Show()
|
||||||
|
end)
|
||||||
|
|
||||||
|
hooksecurefunc(GameTooltip, "Hide", function()
|
||||||
|
following = false
|
||||||
|
cursor:Hide()
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local T = ShaguTweaks.T
|
||||||
|
local API = ShaguTweaks.API
|
||||||
|
|
||||||
|
local module = ShaguTweaks:register({
|
||||||
|
title = T["Hide Combat Tooltip"],
|
||||||
|
description = T["Hides the tooltip in combat. Hold Shift to show it temporarily."],
|
||||||
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Tooltip & Items"],
|
||||||
|
enabled = nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.enable = function(self)
|
||||||
|
if ShaguTweaks.HideCombatTooltipInstalled then return end
|
||||||
|
ShaguTweaks.HideCombatTooltipInstalled = true
|
||||||
|
|
||||||
|
local controller = CreateFrame("Frame", nil, UIParent)
|
||||||
|
local inCombat = UnitAffectingCombat("player") and true or false
|
||||||
|
local shiftDown = API.IsShiftKeyDown() and true or false
|
||||||
|
local guardActive = false
|
||||||
|
local elapsed = 0
|
||||||
|
|
||||||
|
local function Apply()
|
||||||
|
if not inCombat then
|
||||||
|
if GameTooltip:GetAlpha() ~= 1 then
|
||||||
|
GameTooltip:SetAlpha(1)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local alpha = shiftDown and 1 or 0
|
||||||
|
if GameTooltip:GetAlpha() ~= alpha then
|
||||||
|
GameTooltip:SetAlpha(alpha)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GuardTick()
|
||||||
|
elapsed = elapsed + (arg1 or 0)
|
||||||
|
if elapsed < .05 then return end
|
||||||
|
elapsed = 0
|
||||||
|
|
||||||
|
-- ClassicAPI provides modifier events, so normal clients don't need to
|
||||||
|
-- query Shift here. This fallback is only for old environments.
|
||||||
|
if not API.modifierstate then
|
||||||
|
shiftDown = API.IsShiftKeyDown() and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
Apply()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function StartGuard()
|
||||||
|
if guardActive or not inCombat or not GameTooltip:IsShown() then return end
|
||||||
|
|
||||||
|
guardActive = true
|
||||||
|
elapsed = 0
|
||||||
|
controller:SetScript("OnUpdate", GuardTick)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function StopGuard()
|
||||||
|
if not guardActive then return end
|
||||||
|
|
||||||
|
guardActive = false
|
||||||
|
elapsed = 0
|
||||||
|
controller:SetScript("OnUpdate", nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function RefreshShift()
|
||||||
|
shiftDown = API.IsShiftKeyDown() and true or false
|
||||||
|
|
||||||
|
if inCombat and GameTooltip:IsShown() then
|
||||||
|
Apply()
|
||||||
|
StartGuard()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function EnterCombat()
|
||||||
|
inCombat = true
|
||||||
|
shiftDown = API.IsShiftKeyDown() and true or false
|
||||||
|
|
||||||
|
if GameTooltip:IsShown() then
|
||||||
|
Apply()
|
||||||
|
StartGuard()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function LeaveCombat()
|
||||||
|
inCombat = false
|
||||||
|
StopGuard()
|
||||||
|
Apply()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Vanilla/Turtle can restore GameTooltip alpha internally while updating a
|
||||||
|
-- visible unit tooltip. A purely event-driven implementation therefore does
|
||||||
|
-- not stay hidden reliably. The guard below exists only while BOTH combat
|
||||||
|
-- and an actual GameTooltip are active, and is throttled to 20 Hz instead of
|
||||||
|
-- running the full upstream logic every rendered frame.
|
||||||
|
local oldOnShow = GameTooltip:GetScript("OnShow")
|
||||||
|
GameTooltip:SetScript("OnShow", function()
|
||||||
|
if oldOnShow then oldOnShow() end
|
||||||
|
|
||||||
|
if inCombat then
|
||||||
|
shiftDown = API.IsShiftKeyDown() and true or false
|
||||||
|
Apply()
|
||||||
|
StartGuard()
|
||||||
|
else
|
||||||
|
Apply()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local oldOnHide = GameTooltip:GetScript("OnHide")
|
||||||
|
GameTooltip:SetScript("OnHide", function()
|
||||||
|
if oldOnHide then oldOnHide() end
|
||||||
|
StopGuard()
|
||||||
|
end)
|
||||||
|
|
||||||
|
controller:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
|
controller:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||||
|
controller:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||||
|
|
||||||
|
if API.modifierstate then
|
||||||
|
controller:RegisterEvent("MODIFIER_STATE_CHANGED")
|
||||||
|
end
|
||||||
|
|
||||||
|
controller:SetScript("OnEvent", function()
|
||||||
|
if event == "PLAYER_REGEN_DISABLED" then
|
||||||
|
EnterCombat()
|
||||||
|
elseif event == "PLAYER_REGEN_ENABLED" then
|
||||||
|
LeaveCombat()
|
||||||
|
elseif event == "MODIFIER_STATE_CHANGED" then
|
||||||
|
RefreshShift()
|
||||||
|
elseif event == "PLAYER_ENTERING_WORLD" then
|
||||||
|
if UnitAffectingCombat("player") then
|
||||||
|
EnterCombat()
|
||||||
|
else
|
||||||
|
LeaveCombat()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if inCombat then
|
||||||
|
EnterCombat()
|
||||||
|
else
|
||||||
|
LeaveCombat()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local _G = ShaguTweaks.GetGlobalEnv()
|
||||||
|
local T = ShaguTweaks.T
|
||||||
|
local API = ShaguTweaks.API
|
||||||
|
|
||||||
|
local module = ShaguTweaks:register({
|
||||||
|
title = T["Movable Unit Frames Extended"],
|
||||||
|
description = T["Party frames, minimap, buffs, weapon buffs and debuffs can be moved while Ctrl+Shift are held."],
|
||||||
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Unit Frames"],
|
||||||
|
enabled = nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.enable = function(self)
|
||||||
|
ShaguTweaks_config = ShaguTweaks_config or {}
|
||||||
|
ShaguTweaks_config["MoveUnitframesExtended"] = ShaguTweaks_config["MoveUnitframesExtended"] or {}
|
||||||
|
|
||||||
|
local movedb = ShaguTweaks_config["MoveUnitframesExtended"]
|
||||||
|
local unlocked = false
|
||||||
|
local states = {}
|
||||||
|
|
||||||
|
-- Turtle WoW places the first debuff at BuffButton32 in the layout this
|
||||||
|
-- module targets. BuffButton16 from the original mod is intentionally not
|
||||||
|
-- used here.
|
||||||
|
local targets = {
|
||||||
|
{ name = "PartyMemberFrame1" },
|
||||||
|
{ name = "PartyMemberFrame2" },
|
||||||
|
{ name = "PartyMemberFrame3" },
|
||||||
|
{ name = "PartyMemberFrame4" },
|
||||||
|
{ name = "Minimap", moveParent = true },
|
||||||
|
{ name = "BuffButton0" },
|
||||||
|
{ name = "BuffButton32" },
|
||||||
|
{ name = "TempEnchant1" },
|
||||||
|
}
|
||||||
|
|
||||||
|
local function Resolve(target)
|
||||||
|
local handle = _G[target.name]
|
||||||
|
if not handle then return end
|
||||||
|
|
||||||
|
local moveFrame = target.moveParent and handle:GetParent() or handle
|
||||||
|
if not moveFrame then return end
|
||||||
|
|
||||||
|
return handle, moveFrame
|
||||||
|
end
|
||||||
|
|
||||||
|
local function PositionKey(target, moveFrame)
|
||||||
|
return (moveFrame.GetName and moveFrame:GetName()) or target.name
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SavePosition(target, moveFrame)
|
||||||
|
if not moveFrame then
|
||||||
|
local _, resolved = Resolve(target)
|
||||||
|
moveFrame = resolved
|
||||||
|
end
|
||||||
|
if not moveFrame then return end
|
||||||
|
|
||||||
|
local left = moveFrame:GetLeft()
|
||||||
|
local top = moveFrame:GetTop()
|
||||||
|
if not left or not top then return end
|
||||||
|
|
||||||
|
movedb[PositionKey(target, moveFrame)] = { left, top }
|
||||||
|
end
|
||||||
|
|
||||||
|
local function RestorePosition(target)
|
||||||
|
local _, moveFrame = Resolve(target)
|
||||||
|
if not moveFrame then return end
|
||||||
|
|
||||||
|
local pos = movedb[PositionKey(target, moveFrame)]
|
||||||
|
if not pos or not pos[1] or not pos[2] then return end
|
||||||
|
|
||||||
|
moveFrame:SetMovable(true)
|
||||||
|
if moveFrame.SetUserPlaced then moveFrame:SetUserPlaced(true) end
|
||||||
|
moveFrame:ClearAllPoints()
|
||||||
|
moveFrame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", pos[1], pos[2])
|
||||||
|
end
|
||||||
|
|
||||||
|
local grid
|
||||||
|
local function CreateGrid()
|
||||||
|
if grid then return grid end
|
||||||
|
|
||||||
|
grid = CreateFrame("Frame", nil, WorldFrame)
|
||||||
|
grid:SetAllPoints(WorldFrame)
|
||||||
|
grid:Hide()
|
||||||
|
|
||||||
|
local size = 1
|
||||||
|
local width = GetScreenWidth()
|
||||||
|
local height = GetScreenHeight()
|
||||||
|
local ratio = width / height
|
||||||
|
local adjustedHeight = height * ratio
|
||||||
|
local wStep = width / 64
|
||||||
|
local hStep = adjustedHeight / 64
|
||||||
|
|
||||||
|
for i = 0, 64 do
|
||||||
|
local line = grid:CreateTexture(nil, i == 32 and "BORDER" or "BACKGROUND")
|
||||||
|
if i == 32 then
|
||||||
|
line:SetTexture(.8, .6, 0)
|
||||||
|
else
|
||||||
|
line:SetTexture(0, 0, 0, .2)
|
||||||
|
end
|
||||||
|
line:SetPoint("TOPLEFT", grid, "TOPLEFT", i * wStep - (size / 2), 0)
|
||||||
|
line:SetPoint("BOTTOMRIGHT", grid, "BOTTOMLEFT", i * wStep + (size / 2), 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local rows = floor(height / hStep)
|
||||||
|
local middle = floor(rows / 2)
|
||||||
|
|
||||||
|
for i = 1, rows do
|
||||||
|
local line = grid:CreateTexture(nil, i == middle and "BORDER" or "BACKGROUND")
|
||||||
|
if i == middle then
|
||||||
|
line:SetTexture(.8, .6, 0)
|
||||||
|
else
|
||||||
|
line:SetTexture(0, 0, 0, .2)
|
||||||
|
end
|
||||||
|
line:SetPoint("TOPLEFT", grid, "TOPLEFT", 0, -(i * hStep) + (size / 2))
|
||||||
|
line:SetPoint("BOTTOMRIGHT", grid, "TOPRIGHT", 0, -(i * hStep + size / 2))
|
||||||
|
end
|
||||||
|
|
||||||
|
return grid
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UnlockTarget(index, target)
|
||||||
|
local handle, moveFrame = Resolve(target)
|
||||||
|
if not handle or not moveFrame then return end
|
||||||
|
|
||||||
|
states[index] = states[index] or {}
|
||||||
|
local state = states[index]
|
||||||
|
if state.active then return end
|
||||||
|
|
||||||
|
state.active = true
|
||||||
|
state.dragged = false
|
||||||
|
state.handle = handle
|
||||||
|
state.moveFrame = moveFrame
|
||||||
|
state.onDragStart = handle:GetScript("OnDragStart")
|
||||||
|
state.onDragStop = handle:GetScript("OnDragStop")
|
||||||
|
|
||||||
|
if handle.IsMouseEnabled then
|
||||||
|
state.mouseEnabled = handle:IsMouseEnabled() and true or false
|
||||||
|
else
|
||||||
|
state.mouseEnabled = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if moveFrame.IsMovable then
|
||||||
|
state.movable = moveFrame:IsMovable() and true or false
|
||||||
|
else
|
||||||
|
state.movable = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if moveFrame.IsUserPlaced then
|
||||||
|
state.userPlaced = moveFrame:IsUserPlaced() and true or false
|
||||||
|
else
|
||||||
|
state.userPlaced = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
moveFrame:SetMovable(true)
|
||||||
|
handle:EnableMouse(true)
|
||||||
|
handle:RegisterForDrag("LeftButton")
|
||||||
|
|
||||||
|
handle:SetScript("OnDragStart", function()
|
||||||
|
state.dragged = true
|
||||||
|
|
||||||
|
if moveFrame.SetUserPlaced then
|
||||||
|
moveFrame:SetUserPlaced(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
moveFrame:StartMoving()
|
||||||
|
end)
|
||||||
|
|
||||||
|
handle:SetScript("OnDragStop", function()
|
||||||
|
moveFrame:StopMovingOrSizing()
|
||||||
|
|
||||||
|
if state.dragged then
|
||||||
|
SavePosition(target, moveFrame)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function LockTarget(index, target)
|
||||||
|
local state = states[index]
|
||||||
|
if not state or not state.active then return end
|
||||||
|
|
||||||
|
local handle = state.handle
|
||||||
|
local moveFrame = state.moveFrame
|
||||||
|
|
||||||
|
if moveFrame then
|
||||||
|
moveFrame:StopMovingOrSizing()
|
||||||
|
|
||||||
|
-- Only persist an anchor if the user actually dragged this frame. The
|
||||||
|
-- previous test version saved every frame whenever Ctrl+Shift was
|
||||||
|
-- released, which could turn untouched default-managed UI elements into
|
||||||
|
-- permanently absolute-positioned frames.
|
||||||
|
if state.dragged then
|
||||||
|
SavePosition(target, moveFrame)
|
||||||
|
end
|
||||||
|
|
||||||
|
if state.movable ~= nil then
|
||||||
|
moveFrame:SetMovable(state.movable)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not state.dragged
|
||||||
|
and state.userPlaced ~= nil
|
||||||
|
and moveFrame.SetUserPlaced then
|
||||||
|
moveFrame:SetUserPlaced(state.userPlaced)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if handle then
|
||||||
|
handle:SetScript("OnDragStart", state.onDragStart)
|
||||||
|
handle:SetScript("OnDragStop", state.onDragStop)
|
||||||
|
|
||||||
|
if state.mouseEnabled ~= nil then
|
||||||
|
handle:EnableMouse(state.mouseEnabled)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
state.active = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UnlockAll()
|
||||||
|
if unlocked then return end
|
||||||
|
unlocked = true
|
||||||
|
|
||||||
|
for i, target in ipairs(targets) do
|
||||||
|
UnlockTarget(i, target)
|
||||||
|
end
|
||||||
|
|
||||||
|
CreateGrid():Show()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function LockAll()
|
||||||
|
if not unlocked then return end
|
||||||
|
|
||||||
|
for i, target in ipairs(targets) do
|
||||||
|
LockTarget(i, target)
|
||||||
|
end
|
||||||
|
|
||||||
|
if grid then grid:Hide() end
|
||||||
|
unlocked = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateLockState()
|
||||||
|
if API.IsShiftKeyDown() and API.IsControlKeyDown() then
|
||||||
|
UnlockAll()
|
||||||
|
else
|
||||||
|
LockAll()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local events = CreateFrame("Frame")
|
||||||
|
events:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
|
|
||||||
|
if API.modifierstate then
|
||||||
|
events:RegisterEvent("MODIFIER_STATE_CHANGED")
|
||||||
|
end
|
||||||
|
|
||||||
|
events:SetScript("OnEvent", function()
|
||||||
|
if event == "PLAYER_ENTERING_WORLD" then
|
||||||
|
for _, target in ipairs(targets) do
|
||||||
|
RestorePosition(target)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
UpdateLockState()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ClassicAPI supplies MODIFIER_STATE_CHANGED. Only old/fallback environments
|
||||||
|
-- use a throttled state check.
|
||||||
|
if not API.modifierstate then
|
||||||
|
events.elapsed = 0
|
||||||
|
events:SetScript("OnUpdate", function()
|
||||||
|
this.elapsed = this.elapsed + (arg1 or 0)
|
||||||
|
if this.elapsed < .10 then return end
|
||||||
|
this.elapsed = 0
|
||||||
|
UpdateLockState()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, target in ipairs(targets) do
|
||||||
|
RestorePosition(target)
|
||||||
|
end
|
||||||
|
|
||||||
|
UpdateLockState()
|
||||||
|
end
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
-- Adapted from TokensWorth/ShaguTweaks-mods (MIT, original copyright GryllsAddons).
|
||||||
|
|
||||||
|
local _G = ShaguTweaks.GetGlobalEnv()
|
||||||
|
local T = ShaguTweaks.T
|
||||||
|
local API = ShaguTweaks.API
|
||||||
|
|
||||||
|
local module = ShaguTweaks:register({
|
||||||
|
title = T["Unit Frame Abbreviated Names"],
|
||||||
|
description = T["Abbreviates long target and target-of-target names."],
|
||||||
|
expansions = { ["vanilla"] = true, ["tbc"] = nil },
|
||||||
|
category = T["Unit Frames"],
|
||||||
|
enabled = nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
module.enable = function(self)
|
||||||
|
local maxLength = 15
|
||||||
|
local cache = {}
|
||||||
|
|
||||||
|
local function AbbrevWord(word)
|
||||||
|
return string.sub(word, 1, 1) .. ". "
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GetShortName(unit)
|
||||||
|
local name = UnitName(unit)
|
||||||
|
if not name then
|
||||||
|
cache[unit] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local cached = cache[unit]
|
||||||
|
if cached and cached.raw == name then
|
||||||
|
return cached.short
|
||||||
|
end
|
||||||
|
|
||||||
|
local short = name
|
||||||
|
|
||||||
|
if strlen(short) > maxLength then
|
||||||
|
short = string.gsub(short, "^(%S+) ", AbbrevWord)
|
||||||
|
end
|
||||||
|
|
||||||
|
if strlen(short) > maxLength then
|
||||||
|
short = string.gsub(short, "(%S+) ", AbbrevWord)
|
||||||
|
end
|
||||||
|
|
||||||
|
cache[unit] = {
|
||||||
|
raw = name,
|
||||||
|
short = short,
|
||||||
|
}
|
||||||
|
|
||||||
|
return short
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GetNameText(frame)
|
||||||
|
if not frame then return end
|
||||||
|
if frame.name then return frame.name end
|
||||||
|
|
||||||
|
if frame.GetName then
|
||||||
|
local frameName = frame:GetName()
|
||||||
|
if frameName then
|
||||||
|
return _G[frameName .. "Name"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateFrame(frame, unit)
|
||||||
|
local text = GetNameText(frame)
|
||||||
|
local name = GetShortName(unit)
|
||||||
|
if not text or not name then return end
|
||||||
|
|
||||||
|
-- Avoid forcing a FontString update when the displayed value is already
|
||||||
|
-- correct. This matters most for the legacy 250 ms target-of-target
|
||||||
|
-- fallback.
|
||||||
|
if not text.GetText or text:GetText() ~= name then
|
||||||
|
text:SetText(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateTarget()
|
||||||
|
UpdateFrame(TargetFrame, "target")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateTargetTarget()
|
||||||
|
if TargetofTargetFrame then
|
||||||
|
UpdateFrame(TargetofTargetFrame, "targettarget")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function EventValid(name)
|
||||||
|
return API.eventutils
|
||||||
|
and _G.C_EventUtils
|
||||||
|
and _G.C_EventUtils.IsEventValid
|
||||||
|
and _G.C_EventUtils.IsEventValid(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
local events = CreateFrame("Frame")
|
||||||
|
events:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
|
events:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||||
|
|
||||||
|
local hasUnitTarget = EventValid("UNIT_TARGET")
|
||||||
|
local hasUnitName = EventValid("UNIT_NAME_UPDATE")
|
||||||
|
|
||||||
|
if hasUnitTarget then events:RegisterEvent("UNIT_TARGET") end
|
||||||
|
if hasUnitName then events:RegisterEvent("UNIT_NAME_UPDATE") end
|
||||||
|
|
||||||
|
events:SetScript("OnEvent", function()
|
||||||
|
if event == "PLAYER_ENTERING_WORLD" or event == "PLAYER_TARGET_CHANGED" then
|
||||||
|
UpdateTarget()
|
||||||
|
UpdateTargetTarget()
|
||||||
|
elseif event == "UNIT_TARGET" then
|
||||||
|
if arg1 == "target" then UpdateTargetTarget() end
|
||||||
|
elseif event == "UNIT_NAME_UPDATE" then
|
||||||
|
if arg1 == "target" then
|
||||||
|
UpdateTarget()
|
||||||
|
elseif arg1 == "targettarget" then
|
||||||
|
UpdateTargetTarget()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ClassicAPI normally provides UNIT_TARGET. Keep a lightweight Vanilla
|
||||||
|
-- fallback only when that event isn't available instead of running every
|
||||||
|
-- rendered frame like the original module.
|
||||||
|
if not hasUnitTarget then
|
||||||
|
local fallback = CreateFrame("Frame")
|
||||||
|
fallback.elapsed = 0
|
||||||
|
|
||||||
|
fallback:SetScript("OnUpdate", function()
|
||||||
|
this.elapsed = this.elapsed + (arg1 or 0)
|
||||||
|
if this.elapsed < .25 then return end
|
||||||
|
this.elapsed = 0
|
||||||
|
|
||||||
|
if UnitName("targettarget") then
|
||||||
|
UpdateTargetTarget()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
UpdateTarget()
|
||||||
|
UpdateTargetTarget()
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user