forked from Dusk/ShaguTweaks-ClassicAPI
241 lines
15 KiB
Lua
241 lines
15 KiB
Lua
local root=(arg[1] or '.') .. '/'
|
|
local function Check(reduced,actionOption,nativeEvents,timer)
|
|
local progressOption=actionOption
|
|
local modules,frames,pending={},{},{}
|
|
local methods={}
|
|
local noop=function() end
|
|
local function new(kind,name,parent)
|
|
local frame=setmetatable({name=name,parent=parent,scripts={},visible=true,width=200,height=36,scale=1,points={}},{__index=function(t,k) if methods[k] then return methods[k] elseif k~='ShaguTweaksMouseoverController' and string.find(k,'^[A-Z]') then return noop end end})
|
|
table.insert(frames,frame);if name then _G[name]=frame end;return frame
|
|
end
|
|
function methods:GetName() return self.name end
|
|
function methods:GetParent() return self.parent end
|
|
function methods:SetPoint(p,relative,rp,x,y) self.points={{p,relative,rp,x or 0,y or 0}} end
|
|
function methods:ClearAllPoints() self.points={} end
|
|
function methods:GetPoint(i) local p=self.points[i or 1];if p then return unpack(p) end end
|
|
function methods:GetNumPoints() return table.getn(self.points) end
|
|
function methods:GetLeft()
|
|
local p=self.points[1];if not p then return self.left or 0 end
|
|
return (p[2] and p[2]~=UIParent and p[2]:GetLeft() or 0)+p[4]
|
|
end
|
|
function methods:GetTop()
|
|
local p=self.points[1];if not p then return self.top or 0 end
|
|
return (p[2] and p[2]~=UIParent and p[2]:GetTop() or 0)+p[5]
|
|
end
|
|
function methods:GetWidth() return self.width end
|
|
function methods:GetHeight() return self.height end
|
|
function methods:SetWidth(w) self.width=w end
|
|
function methods:SetHeight(h) self.height=h end
|
|
function methods:SetScale(s) self.scale=s end
|
|
function methods:GetEffectiveScale() return self.scale end
|
|
function methods:SetAllPoints(f) self.allPoints=f end
|
|
function methods:SetScript(k,v) self.scripts[k]=v end
|
|
function methods:GetScript(k) return self.scripts[k] end
|
|
function methods:IsVisible() return self.visible and (not self.parent or self.parent:IsVisible()) end
|
|
function methods:Show() local changed=not self.visible;self.visible=true;if changed and self.scripts.OnShow then local before=this;this=self;self.scripts.OnShow();this=before end end
|
|
function methods:Hide() local changed=self.visible;self.visible=false;if changed and self.scripts.OnHide then local before=this;this=self;self.scripts.OnHide();this=before end end
|
|
function methods:StartMoving() self.moving=true end
|
|
function methods:SetMovable(value) self.movable=value end
|
|
function methods:SetUserPlaced(value)
|
|
assert(self.movable, 'Frame is not movable or resizable')
|
|
self.userPlaced=value
|
|
end
|
|
function methods:StopMovingOrSizing() self.moving=false end
|
|
function methods:CreateFontString() return new('FontString',nil,self) end
|
|
function methods:SetText(t) self.text=t end
|
|
CreateFrame=new
|
|
UIParent=new('Frame','UIParent')
|
|
local names={'MainMenuBar','MultiBarBottomLeft','MultiBarBottomRight','MultiBarRight','MultiBarLeft','PetActionBarFrame','ShapeshiftBarFrame','MainMenuExpBar','ReputationWatchBar'}
|
|
for i,name in ipairs(names) do new('Frame',name,UIParent):SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',10*i,100+i*20) end
|
|
MainMenuExpBar:SetPoint('TOPLEFT',MainMenuBar,'TOPLEFT',0,20)
|
|
ReputationWatchBar:SetPoint('TOPLEFT',MainMenuExpBar,'TOPLEFT',0,8)
|
|
MultiBarBottomLeft:SetPoint('TOPLEFT',MainMenuExpBar,'TOPLEFT',0,30)
|
|
MultiBarBottomRight:SetPoint('TOPLEFT',MultiBarBottomLeft,'TOPLEFT',0,40)
|
|
local nativeClick=function() end
|
|
ActionButton1=new('Button','ActionButton1',MainMenuBar);ActionButton1:SetScript('OnClick',nativeClick)
|
|
ActionButton12=new('Button','ActionButton12',MainMenuBar)
|
|
PetActionButton1=new('Button','PetActionButton1',PetActionBarFrame)
|
|
PetActionButton10=new('Button','PetActionButton10',PetActionBarFrame)
|
|
BonusActionBarFrame=new('Frame','BonusActionBarFrame',MainMenuBar);BonusActionBarFrame:Hide()
|
|
MainMenuExpBar:Hide();ReputationWatchBar:Hide()
|
|
MultiBarRight:Hide();MultiBarRight.ShaguTweaksMouseoverController={enabled=true}
|
|
local originalMainSetPoint=MainMenuBar.SetPoint
|
|
local keys=false
|
|
ShaguTweaks={mods=modules,T=setmetatable({},{__index=function(t,k) return k end}),API={timer=timer,modifierstate=nativeEvents}}
|
|
function ShaguTweaks.GetGlobalEnv() return _G end
|
|
dofile(root..'api.lua')
|
|
ShaguTweaks.API.timer=timer;ShaguTweaks.API.modifierstate=nativeEvents
|
|
function ShaguTweaks:register(m) modules[m.title]=m;return m end
|
|
ShaguTweaks.API.IsShiftKeyDown=function() return keys end
|
|
ShaguTweaks.API.IsControlKeyDown=ShaguTweaks.API.IsShiftKeyDown
|
|
ShaguTweaks.API.IsAltKeyDown=ShaguTweaks.API.IsShiftKeyDown
|
|
function ShaguTweaks.API.Defer(callback) table.insert(pending,callback) end
|
|
function ShaguTweaks.HookScript(frame,event,callback)
|
|
local original=frame:GetScript(event)
|
|
frame:SetScript(event,function() if original then original() end;callback() end)
|
|
end
|
|
local layouts=0
|
|
function UIParent_ManageFramePositions()
|
|
layouts=layouts+1
|
|
MainMenuBar:ClearAllPoints();MainMenuBar:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',10,120)
|
|
MultiBarBottomLeft:ClearAllPoints();MultiBarBottomLeft:SetPoint('TOPLEFT',MainMenuExpBar,'TOPLEFT',0,30)
|
|
end
|
|
function ReputationWatchBar_Update()
|
|
ReputationWatchBar:ClearAllPoints();ReputationWatchBar:SetPoint('TOPLEFT',MainMenuExpBar,'TOPLEFT',0,8)
|
|
end
|
|
local config={['Reduced Actionbar Size']=reduced and 1 or 0,ActionBarPositions={}}
|
|
ShaguTweaks_config=config
|
|
dofile(root..'mods/actionbar-move.lua')
|
|
local baseline=table.getn(frames)
|
|
assert(not modules['Movable Action Bars'])
|
|
if actionOption then ShaguTweaks.EnableActionBarMovers() end
|
|
assert(not modules['Movable XP & Reputation Bars'])
|
|
if not reduced or (not actionOption and not progressOption) then
|
|
assert(table.getn(frames)==baseline and MainMenuBar.SetPoint==originalMainSetPoint)
|
|
return
|
|
end
|
|
local ready=frames[table.getn(frames)]
|
|
local function fire(frame,script,button)
|
|
local priorThis,priorArg=this,arg1;this,arg1=frame,button
|
|
frame:GetScript(script)();this,arg1=priorThis,priorArg
|
|
end
|
|
fire(ready,'OnEvent');fire(ready,'OnUpdate')
|
|
if timer then pending[1]() end
|
|
local state=ShaguTweaks.ActionBarMovers
|
|
assert(state and table.getn(state.states)==((actionOption and reduced) and 7 or 0)+(progressOption and 2 or 0))
|
|
-- Snap to a neighbour's original relative placement; leave distant drops
|
|
-- and hidden targets alone. Coordinates are compared in UIParent units.
|
|
local snapTarget=new('Frame',nil,UIParent)
|
|
snapTarget:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',100,200)
|
|
local snapState={frame=MainMenuBar,snapOffsets={{target={frame=snapTarget},x=4,y=42}}}
|
|
local sx,sy=state.Snap(snapState,109,235)
|
|
assert(sx==104 and sy==242)
|
|
sx,sy=state.Snap(snapState,130,235);assert(sx==130 and sy==235)
|
|
snapTarget:Hide();sx,sy=state.Snap(snapState,109,235);assert(sx==109 and sy==235)
|
|
snapTarget:Show();snapTarget:SetScale(.5);MainMenuBar:SetScale(.5)
|
|
sx,sy=state.Snap(snapState,110,280);assert(sx==108 and sy==284)
|
|
MainMenuBar:SetScale(1)
|
|
snapTarget:SetScale(1)
|
|
local candidate=snapState.snapOffsets[1].target
|
|
local oldLevel,oldWatched,oldStatus=UnitLevel,GetWatchedFactionInfo,ReputationWatchStatusBar
|
|
candidate.name='MainMenuExpBar'
|
|
UnitLevel=function() return 60 end
|
|
sx,sy=state.Snap(snapState,109,235);assert(sx==109 and sy==235)
|
|
UnitLevel=function() return 40 end
|
|
sx,sy=state.Snap(snapState,109,235);assert(sx==104 and sy==242)
|
|
candidate.name='ReputationWatchBar'
|
|
GetWatchedFactionInfo=function() return nil end
|
|
ReputationWatchStatusBar=new('Frame',nil,snapTarget)
|
|
sx,sy=state.Snap(snapState,109,235);assert(sx==109 and sy==235)
|
|
GetWatchedFactionInfo=function() return 'Stormwind' end
|
|
sx,sy=state.Snap(snapState,109,235);assert(sx==104 and sy==242)
|
|
ReputationWatchStatusBar:Hide()
|
|
sx,sy=state.Snap(snapState,109,235);assert(sx==109 and sy==235)
|
|
ReputationWatchStatusBar:Show()
|
|
snapTarget.GetAlpha=function() return 0 end
|
|
sx,sy=state.Snap(snapState,109,235);assert(sx==109 and sy==235)
|
|
UnitLevel,GetWatchedFactionInfo,ReputationWatchStatusBar=oldLevel,oldWatched,oldStatus
|
|
assert(table.getn(state.states[1].snapOffsets)>0)
|
|
-- Native main-frame top sits 40 units above its buttons. Snapping must
|
|
-- leave six units between visible rows, not preserve that artwork gap.
|
|
local lower=new('Frame',nil,UIParent);lower:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',100,200)
|
|
local upper=new('Frame',nil,UIParent);upper:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',100,300)
|
|
local lowerButton=new('Button','SnapLower',lower)
|
|
lowerButton.GetLeft=function() return 110 end;lowerButton.GetTop=function() return 160 end
|
|
lowerButton.GetRight=function() return 210 end;lowerButton.GetBottom=function() return 124 end
|
|
local upperButton=new('Button','SnapUpper',upper)
|
|
upperButton.GetLeft=function() return 110 end;upperButton.GetTop=function() return 300 end
|
|
upperButton.GetRight=function() return 210 end;upperButton.GetBottom=function() return 264 end
|
|
local lowerState={name='MainMenuBar',frame=lower,first='SnapLower',last='SnapLower',snapOffsets={}}
|
|
local upperState={name='MultiBarBottomLeft',frame=upper,first='SnapUpper',last='SnapUpper',snapOffsets={}}
|
|
lowerState.snapOffsets={{target=upperState,x=0,y=-80}} -- incorrect legacy gap
|
|
local allStates=state.states;state.states={lowerState,upperState}
|
|
sx,sy=state.Snap(lowerState,103,295);assert(sx==100 and sy==298)
|
|
assert((264-(sy-40))==6)
|
|
sx,sy=state.Snap(lowerState,100,220);assert(sy==220) -- legacy gap cannot attract
|
|
state.states=allStates
|
|
assert(not ready:GetScript('OnUpdate'))
|
|
if nativeEvents then assert(not state.events:GetScript('OnUpdate')) end
|
|
assert(ActionButton1:GetScript('OnClick')==nativeClick)
|
|
local target=state.states[1]
|
|
assert(not target.marker.visible)
|
|
keys=true
|
|
fire(state.events,'OnEvent')
|
|
assert(target.marker.visible)
|
|
local oldX,oldY=target.frame:GetLeft(),target.frame:GetTop()
|
|
local oldXPX,oldRepX=MainMenuExpBar:GetLeft(),ReputationWatchBar:GetLeft()
|
|
-- Model a compact visible row offset inside a larger native artwork frame.
|
|
target.marker:ClearAllPoints();target.marker:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',oldX+25,oldY-18)
|
|
target.marker:SetWidth(120);target.marker:SetHeight(32)
|
|
ActionButton1:ClearAllPoints();ActionButton1:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',oldX+27,oldY-20)
|
|
ActionButton12.GetRight=function() return oldX+143 end
|
|
ActionButton12.GetBottom=function() return oldY-48 end
|
|
fire(target.marker,'OnDragStart')
|
|
assert(state.dragging==target and state.outline.moving)
|
|
assert(state.outline:GetWidth()==120 and state.outline:GetHeight()==32)
|
|
assert(state.outline:GetLeft()==oldX+25 and state.outline:GetTop()==oldY-18)
|
|
assert(target.frame:GetLeft()==oldX and target.frame:GetTop()==oldY) -- drag only the empty outline
|
|
state.outline:ClearAllPoints();state.outline:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',355,422)
|
|
keys=false;fire(state.events,'OnEvent')
|
|
assert(not state.dragging and not state.outline.visible and not state.outline.moving)
|
|
assert(target.frame:GetLeft()==330 and target.frame:GetTop()==440)
|
|
assert(config.ActionBarPositions[target.name][1]==330)
|
|
target.frame:ClearAllPoints();target.frame:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',1,2)
|
|
assert(target.frame:GetLeft()==330 and target.frame:GetTop()==440) -- native layout cannot erase a saved anchor
|
|
target.clear(target.frame);target.point(target.frame,'TOPLEFT',UIParent,'BOTTOMLEFT',0,0)
|
|
local savedEvent=event;event='PLAYER_ENTERING_WORLD';fire(state.events,'OnEvent');event=savedEvent
|
|
assert(target.frame:GetLeft()==330 and target.frame:GetTop()==440)
|
|
keys=true;fire(state.events,'OnEvent');fire(target.marker,'OnClick','RightButton')
|
|
assert(not config.ActionBarPositions[target.name] and layouts>0)
|
|
if progressOption then
|
|
local count=0
|
|
for _,s in ipairs(state.states) do if s.progress then count=count+1;assert(s.marker.visible) end end
|
|
assert(count==2) -- markers are available even at max level/no watched reputation
|
|
end
|
|
if actionOption and reduced then
|
|
for _,s in ipairs(state.states) do if s.name=='MultiBarRight' then assert(s.marker.visible) end end
|
|
if progressOption then assert(config.ActionBarPositions.MainMenuExpBar and MainMenuExpBar:GetLeft()==oldXPX and ReputationWatchBar:GetLeft()==oldRepX) end
|
|
local pet
|
|
for _,s in ipairs(state.states) do if s.name=='PetActionBarFrame' then pet=s end end
|
|
assert(pet and pet.marker.visible)
|
|
assert(pet.marker:GetPoint(1)=='BOTTOMRIGHT') -- mock retains the last anchor
|
|
PetActionBarFrame:Hide();assert(not pet.marker.visible)
|
|
PetActionBarFrame:Show();assert(pet.marker.visible)
|
|
pet.marker:ClearAllPoints();pet.marker:SetPoint('TOPLEFT',PetActionBarFrame,'TOPLEFT',0,0)
|
|
local petX,petY=PetActionBarFrame:GetLeft(),PetActionBarFrame:GetTop()
|
|
PetActionButton1:ClearAllPoints();PetActionButton1:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',petX+12,petY-8)
|
|
PetActionButton10.GetRight=function() return petX+168 end
|
|
PetActionButton10.GetBottom=function() return petY-38 end
|
|
fire(pet.marker,'OnDragStart')
|
|
assert(state.outline:GetWidth()==160 and state.outline:GetHeight()==34)
|
|
assert(state.outline:GetLeft()==petX+10 and state.outline:GetTop()==petY-6)
|
|
state.outline:ClearAllPoints();state.outline:SetPoint('TOPLEFT',UIParent,'BOTTOMLEFT',510,594)
|
|
fire(pet.marker,'OnDragStop')
|
|
assert(PetActionBarFrame:GetLeft()==500 and PetActionBarFrame:GetTop()==600)
|
|
assert(config.ActionBarPositions.PetActionBarFrame[1]==500)
|
|
fire(pet.marker,'OnClick','RightButton')
|
|
assert(not config.ActionBarPositions.PetActionBarFrame)
|
|
end
|
|
end
|
|
Check(false,true,true,true)
|
|
Check(true,false,true,true)
|
|
Check(true,true,true,true)
|
|
Check(true,true,false,false)
|
|
print('Action movers: reduced-layout prerequisite, single combined option, outline drag, saved-anchor protection, dependent pinning, reset, hidden progress/mouseover markers and idle setup passed')
|
|
-- A detached progress bar must not pull Reduced Actionbar's automatic stack
|
|
-- along with it. Execute that module's actual layout callback in isolation.
|
|
local f=assert(io.open(root..'mods/reduced-actionbar.lua','r'));local reducedSource=f:read('*a');f:close();assert(loadstring(reducedSource))
|
|
local a=assert(string.find(reducedSource,' local function UpdateActionBarPositions()',1,true))
|
|
local b=assert(string.find(reducedSource,' hooksecurefunc("UIParent_ManageFramePositions"',a,true))
|
|
local widgets={'MainMenuExpBar','ReputationWatchBar','MultiBarBottomLeft','MultiBarBottomRight','PetActionBarFrame','ShapeshiftBarFrame','MainMenuBarArtFrame','MainMenuBar','ActionButton1','CastingBarFrame'}
|
|
for _,name in ipairs(widgets) do
|
|
_G[name]={visible=true,IsVisible=function(self) return self.visible end,ClearAllPoints=function(self) self.point=nil end,SetPoint=function(self,...) self.point=arg end}
|
|
end
|
|
local moved={}
|
|
ShaguTweaks.ActionBarMovers={IsMoved=function(name) return moved[name] end}
|
|
local relayout=assert(loadstring(string.sub(reducedSource,a,b-1)..'return UpdateActionBarPositions'))()
|
|
relayout();assert(MultiBarBottomLeft.point[2]==ReputationWatchBar)
|
|
moved.ReputationWatchBar=true;relayout();assert(MultiBarBottomLeft.point[2]==MainMenuExpBar)
|
|
moved.MainMenuExpBar=true;relayout();assert(MultiBarBottomLeft.point[2]==MainMenuBar)
|
|
print('Reduced Actionbar: detached progress bars no longer become automatic action-stack anchors')
|