# HG changeset patch
# User Flick
# Date 1301168108 25200
# Node ID 65f2805957a0de1b53732c2f781d9730dabab31d
# Parent f255cd69e890391a2a7e0d75f70bf968d94180ba
No real reason to store some of the code in a subdirectory.
diff -r f255cd69e890 -r 65f2805957a0 ActionButton.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ActionButton.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,806 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local IsUsableAction = IsUsableAction
+local IsEquippedAction = IsEquippedAction
+local IsConsumableAction = IsConsumableAction
+local IsStackableAction = IsStackableAction
+local GetActionText = GetActionText
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local IsCurrentAction = IsCurrentAction
+local IsAutoRepeatAction = IsAutoRepeatAction
+local IsUsableAction = IsUsableAction
+local IsAttackAction = IsAttackAction
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local GetActionCooldown = GetActionCooldown
+local GetActionTexture = GetActionTexture
+local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
+local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
+local IsActionInRange = IsActionInRange
+local InCombatLockdown = InCombatLockdown
+local HasAction = HasAction
+
+--
+-- Secure snippets
+-- These are run within the context of the bar's sandbox, as the
+-- buttons themselves do not have their own sandbox.
+--
+local _onstate_mc = -- function(self, stateid, newstate)
+[[
+ local oldMcVehicleState = mcVehicleState
+ mcVehicleState = newstate
+ control:ChildUpdate()
+ if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
+ control:ChildUpdate("vehicle")
+ end
+]]
+
+local _childupdate = -- function(self, snippetid, message)
+[[
+ local action = nil
+ if (doVehicle and mcVehicleState == "vehicle") or
+ (doMindControl and mcVehicleState == "mc") then
+ local idx = self:GetAttribute("bar-idx")
+ local maxN = (doVehicle and mcVehicleState == "vehicle") and 7 or 12
+ if idx and idx <= maxN then
+ action = 120 + idx
+ else
+ action = 0
+ end
+ elseif state and settings[state] and settings[state].page then
+ action = self:GetAttribute("action-"..settings[state].page)
+ end
+ if action == nil then
+ action = self:GetAttribute("default-action")
+ end
+
+ self:SetAttribute("action",action)
+
+ if not self:GetAttribute("showgrid") then
+ local tempShow = self:GetAttribute("showgrid-temp")
+ local evtShow = self:GetAttribute("showgrid-event")
+ if tempShow then tempShow = (tempShow > 0) end
+ if evtShow then evtShow = (evtShow > 0) end
+
+ if tempShow or evtShow or HasAction(action) then
+ self:Show()
+ else
+ self:Hide()
+ end
+ end
+]]
+
+local _childupdate_vehicleExit = -- function(self, snippetid, message)
+[[
+ local show = (mcVehicleState == "vehicle")
+ if show and doVehicle then
+ self:SetAttribute("type","macro")
+ self:Show()
+ else
+ self:SetAttribute("type","action")
+ end
+ control:CallMethod("ShowVehicleExit",show)
+]]
+
+local _childupdate_showgrid = -- function(self, snippetid, message)
+[[
+ showgrid_event = message
+ self:SetAttribute("showgrid-event",message)
+ if not self:GetAttribute("showgrid") then
+ local count = message + (self:GetAttribute("showgrid-temp") or 0)
+ if count <= 0 then
+ local action = self:GetAttribute("action")
+ -- note that HasAction is not updated on the target of a drag until after ACTIONBAR_HIDEGRID
+ -- so, we set a flag for this button in pre-click/receive-drag and check for it here
+ if HasAction(action) or self:GetAttribute("showgrid-clicked") then
+ if not self:IsShown() then
+ self:Show()
+ end
+ self:SetAttribute("showgrid-clicked",false)
+ else
+ if self:IsShown() then
+ self:Hide()
+ end
+ end
+ else
+ self:Show()
+ end
+ end
+]]
+
+local _onDragStart = -- function(self, button, kind, value, ...)
+[[
+ if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
+ return kind, value, ...
+ else
+ return "action", self:GetAttribute("action")
+ end
+]]
+
+local _onReceiveDrag = -- function(self, button, kind, value, ...)
+[[
+ if kind ~= "spell" and kind ~= "item" and kind ~= "macro" and kind ~= "flyout" then
+ return kind, value, ...
+ else
+ if showgrid_event and showgrid_event > 0 then
+ self:SetAttribute("showgrid-clicked",true)
+ end
+ return "action", self:GetAttribute("action")
+ end
+]]
+
+local _onClick = -- function(self, button, down)
+[[
+ if showgrid_event and showgrid_event > 0 then
+ self:SetAttribute("showgrid-clicked",true)
+ end
+ return button
+]]
+
+--
+-- private
+--
+local eventList = {
+ "PLAYER_ENTERING_WORLD",
+ "ACTIONBAR_PAGE_CHANGED",
+ "ACTIONBAR_SLOT_CHANGED",
+ "UPDATE_BINDINGS",
+ "ACTIONBAR_UPDATE_STATE",
+ "ACTIONBAR_UPDATE_USABLE",
+ "ACTIONBAR_UPDATE_COOLDOWN",
+ "UNIT_INVENTORY_CHANGED",
+ "LEARNED_SPELL_IN_TAB",
+ "UPDATE_INVENTORY_ALERTS",
+ "PLAYER_TARGET_CHANGED",
+ "TRADE_SKILL_SHOW",
+ "TRADE_SKILL_CLOSE",
+ "PLAYER_ENTER_COMBAT",
+ "PLAYER_LEAVE_COMBAT",
+ "START_AUTOREPEAT_SPELL",
+ "STOP_AUTOREPEAT_SPELL",
+ "UNIT_ENTERED_VEHICLE",
+ "UNIT_EXITED_VEHICLE",
+ "COMPANION_UPDATE",
+}
+
+--
+-- Action Button class
+--
+local buttonTypeID = "Action"
+local Super = ReAction.Button
+local Action = setmetatable(
+ {
+ defaultBarConfig = {
+ type = buttonTypeID,
+ btnWidth = 36,
+ btnHeight = 36,
+ btnRows = 1,
+ btnColumns = 12,
+ spacing = 3,
+ buttons = { },
+ },
+
+ barType = L["Action Bar"],
+ buttonTypeID = buttonTypeID
+ },
+ { __index = Super } )
+
+ReAction.Button.Action = Action
+ReAction:RegisterBarType(Action, true)
+
+function Action:New( config, bar, idx, idHint )
+ local name = format("ReAction_%s_Action_%d",bar:GetName(),idx)
+
+ self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+ self.barConfig = bar:GetConfig()
+
+ local f = self:GetFrame()
+ local barFrame = bar:GetFrame()
+
+ self.rangeTimer = TOOLTIP_UPDATE_TIME
+
+ -- set up the base action ID
+ self:SetActionIDPool("action",120)
+ config.actionID = self:AcquireActionID(config.actionID, idHint)
+ self.nPages = 1
+
+ -- attribute setup
+ f:SetAttribute("type","action")
+ f:SetAttribute("checkselfcast", true)
+ f:SetAttribute("checkfocuscast", true)
+ f:SetAttribute("action", config.actionID)
+ f:SetAttribute("default-action", config.actionID)
+ f:SetAttribute("bar-idx",idx)
+ f:SetAttribute("showgrid-temp",0)
+ f:SetAttribute("showgrid-event",0)
+ f:SetAttribute("showgrid",not self:GetBarConfig().hideEmpty)
+
+ -- non secure scripts
+ f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+ f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+ f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+ f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
+ f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
+ f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end)
+ f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
+ f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
+
+ -- event registration
+ f:EnableMouse(true)
+ f:RegisterForDrag("LeftButton", "RightButton")
+ f:RegisterForClicks("AnyUp")
+ for _, evt in pairs(eventList) do
+ f:RegisterEvent(evt)
+ end
+
+ f.action = config.actionID -- need this to support silly ActionButton_UpdateFlyout. Should not taint anything anymore.
+
+ -- secure handlers
+ f:SetAttribute("_childupdate", _childupdate)
+ f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid)
+ barFrame:WrapScript(f, "OnDragStart", _onDragStart)
+ barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
+ barFrame:WrapScript(f, "OnClick", _onClick)
+
+ -- attach to skinner
+ bar:SkinButton(self)
+
+ -- initial display
+ if ReAction:GetConfigMode() then
+ self:ShowGridTemp(true)
+ end
+
+ self:Refresh()
+
+ return self
+end
+
+function Action:Destroy()
+ local f = self:GetFrame()
+ local c = self:GetConfig()
+
+ f:SetAttribute("_childupdate-vehicle",nil)
+ f:SetAttribute("action",c.actionID) -- so that Super.Destroy releases the right one
+
+ if c.pageactions and #c.pageactions > 1 then
+ for i = 2, #c.pageactions do
+ self:ReleaseActionID(c.pageactions[i])
+ self:ReleaseActionID(id)
+ end
+ end
+
+ Super.Destroy(self)
+end
+
+function Action:GetBarConfig()
+ -- this is the per-bar Action module config structure,
+ -- not the config structure of the bar itself
+ return self.barConfig
+end
+
+function Action:Refresh()
+ Super.Refresh(self)
+ self:RefreshPages()
+ self:InstallVehicle()
+ self:ShowGrid(not self:GetBarConfig().hideEmpty)
+ self:UpdateAction()
+end
+
+function Action:InstallVehicle()
+ local f = self:GetFrame()
+ if self.idx == 7 and self:GetBarConfig().vehicle then
+ if not self.vehicleInstalled then
+ self.vehicleInstalled = true
+ -- install vehicle-exit button on 7th button (only)
+ f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit)
+ f:SetAttribute("macrotext","/run VehicleExit()")
+ self:GetBar():GetFrame().ShowVehicleExit = function(bar,show)
+ self:ShowVehicleExit(show)
+ end
+ end
+ -- setscale blows away tex coords
+ self:UpdateIcon()
+ elseif self.vehicleInstalled then
+ self.vehicleInstalled = false
+ f:SetAttribute("_childupdate-vehicle",nil)
+ f:SetAttribute("macrotext",nil)
+ end
+end
+
+function Action:ShowGrid( show )
+ if not InCombatLockdown() then
+ self.frame:SetAttribute("showgrid", show)
+ self:UpdateShowGrid()
+ end
+end
+
+function Action:ShowGridTemp( show )
+ -- This function only modifies the show-grid when out
+ -- of combat, and is ignored by the secure handler. Use
+ -- it for configuration modes.
+ if not InCombatLockdown() then
+ local count = self.showGridTempCount or 0
+ if show then
+ count = count + 1
+ else
+ count = count - 1
+ end
+ if count < 0 then count = 0 end
+ self.showGridTempCount = count
+ self:GetFrame():SetAttribute("showgrid-temp",count)
+ self:UpdateShowGrid()
+ end
+end
+
+function Action:UpdateAll()
+ self:UpdateActionIDLabel(ReAction:GetConfigMode())
+ self:UpdateHotkey()
+ self:UpdateShowGrid()
+ self:UpdateIcon()
+ self:UpdateBorder()
+ self:UpdateMacroText()
+ self:UpdateCount()
+ self:UpdateTooltip()
+ self:UpdateCheckedState()
+ self:UpdateUsable()
+ self:UpdateCooldown()
+ self:UpdateFlash()
+end
+
+function Action:UpdateAction()
+ local action = self:GetActionID()
+ if action ~= self.actionID then
+ self.actionID = action
+ self:UpdateAll()
+ end
+end
+
+function Action:UpdateShowGrid()
+ if not InCombatLockdown() then
+ local f = self:GetFrame()
+ local count = (f:GetAttribute("showgrid-event") or 0) +
+ (self.showGridTempCount or 0) +
+ (f:GetAttribute("showgrid") and 1 or 0)
+
+ if count <= 0 and not HasAction(self.actionID) then
+ if f:IsShown() then
+ f:Hide()
+ end
+ elseif not f:IsShown() then
+ f:Show()
+ end
+ end
+end
+
+function Action:UpdateIcon()
+ local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture()
+ local icon = self.frames.icon
+ local hotkey = self.frames.hotkey
+ local f = self:GetFrame()
+
+ if self.vehicleExitMode then
+ texture = "Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up"
+ icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
+ icon:SetVertexColor(1,1,1)
+ else
+ icon:SetTexCoord(0,1,0,1)
+ end
+
+ if texture then
+ icon:SetTexture(texture)
+ if tLeft then
+ icon:SetTexCoord(tLeft,tRight,tTop,tBottom)
+ end
+ icon:Show()
+ self.rangeTimer = -1
+ f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+ else
+ icon:Hide()
+ self.frames.cooldown:Hide()
+ self.rangeTimer = nil
+ f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+ end
+end
+
+function Action:GetIconTexture()
+ return GetActionTexture(self.actionID)
+end
+
+function Action:UpdateBorder()
+ local action = self.actionID
+ if ReAction:GetKeybindMode() then
+ self:UpdateKeybindModeDisplay(true)
+ elseif IsEquippedAction(action) then
+ self.frames.border:SetVertexColor(0, 1.0, 0, 0.35)
+ self.frames.border:Show()
+ else
+ self.frames.border:Hide()
+ end
+end
+
+function Action:UpdateMacroText()
+ local action = self.actionID
+ if not IsConsumableAction(action) and not IsStackableAction(action) then
+ self.frames.name:SetText(GetActionText(action))
+ else
+ self.frames.name:SetText("")
+ end
+end
+
+function Action:UpdateCount()
+ local action = self.actionID
+ if IsConsumableAction(action) or IsStackableAction(action) then
+ self.frames.count:SetText(GetActionCount(action))
+ else
+ self.frames.count:SetText("")
+ end
+end
+
+function Action:UpdateTooltip()
+ local f = self:GetFrame()
+ if GameTooltip:GetOwner() == f then
+ self:SetTooltip()
+ end
+end
+
+function Action:SetTooltip()
+ local f = self:GetFrame()
+ if GetCVar("UberTooltips") == "1" then
+ GameTooltip_SetDefaultAnchor(GameTooltip, f)
+ else
+ GameTooltip:SetOwner(f,"ANCHOR_RIGHT")
+ end
+ GameTooltip:SetAction(self.actionID)
+end
+
+function Action:UpdateCheckedState()
+ local action = self.actionID
+ if IsCurrentAction(action) or IsAutoRepeatAction(action) then
+ self:GetFrame():SetChecked(1)
+ else
+ self:GetFrame():SetChecked(0)
+ end
+end
+
+function Action:UpdateUsable()
+ local isUsable, notEnoughMana = self:GetUsable()
+ local noRange = self:GetInRange()
+
+ isUsable = self.vehicleExitMode or (isUsable and not noRange)
+
+ if isUsable then
+ if self.usableStatus ~= "usable" then
+ self.frames.icon:SetVertexColor(1.0, 1.0, 1.0)
+ self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+ self.usableStatus = "usable"
+ end
+ elseif noRange then
+ if self.usableStatus ~= "norange" then
+ self.frames.icon:SetVertexColor(1.0,0.1,0.1)
+ self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+ self.usableStatus = "norange"
+ end
+ elseif notEnoughMana then
+ if self.usableStatus ~= "oom" then
+ self.frames.icon:SetVertexColor(0.5, 0.5, 1.0)
+ self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0)
+ self.usableStatus = "oom"
+ end
+ else
+ if self.usableStatus ~= "unusable" then
+ self.frames.icon:SetVertexColor(0.4, 0.4, 0.4)
+ self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+ self.usableStatus = "unusable"
+ end
+ end
+end
+
+function Action:GetUsable()
+ return IsUsableAction(self.actionID)
+end
+
+function Action:GetInRange()
+ return IsActionInRange(self.actionID) == 0
+end
+
+function Action:UpdateCooldown()
+ CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown())
+end
+
+function Action:GetCooldown()
+ return GetActionCooldown(self.actionID)
+end
+
+function Action:UpdateFlash()
+ local action = self.actionID
+ self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) )
+end
+
+function Action:SetFlash(flash)
+ if self.flashing ~= flash then
+ self.flashing = flash
+ self.flashtime = 0
+ if not flash then
+ self.frames.flash:Hide()
+ end
+ self:UpdateCheckedState()
+ end
+end
+
+function Action:RunFlash(elapsed)
+ if self.flashing then
+ local flashtime = self.flashtime - elapsed
+ self.flashtime = flashtime
+ if flashtime <= 0 then
+ local overtime = -flashtime
+ if overtime >= ATTACK_BUTTON_FLASH_TIME then
+ overtime = 0
+ end
+ flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
+ local flash = self.frames.flash
+ if flash:IsShown() then
+ flash:Hide()
+ else
+ flash:Show()
+ end
+ end
+ end
+end
+
+function Action:RunRangeFinder(elapsed)
+ local rangeTimer = self.rangeTimer
+ if rangeTimer then
+ rangeTimer = rangeTimer - elapsed
+ self.rangeTimer = rangeTimer
+ if rangeTimer <= 0 then
+ self:UpdateUsable()
+ self.rangeTimer = TOOLTIP_UPDATE_TIME
+ end
+ end
+end
+
+function Action:GetActionID(page)
+ if page == nil then
+ -- get the effective ID
+ return self:GetFrame():GetAttribute("action")
+ else
+ if page == 1 then
+ return self.config.actionID
+ else
+ return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
+ end
+ end
+end
+
+function Action:SetActionID( id, page )
+ id = tonumber(id)
+ page = tonumber(page)
+ if id == nil or id < 1 or id > 120 then
+ ReAction:UserError(L["Action ID range is 1-120"])
+ return
+ end
+ if page and page ~= 1 then
+ if not self.config.pageactions then
+ self.config.pageactions = { }
+ end
+ self:ReleaseActionID(self.config.pageactions[page])
+ self.config.pageactions[page] = id
+ self:AcquireActionID(self.config.pageactions[page])
+ self.frame:SetAttribute("action-page"..page,id)
+ else
+ self:ReleaseActionID(self.config.actionID)
+ self.config.actionID = id
+ self:AcquireActionID(self.config.actionID)
+ self.frame:SetAttribute("action",id)
+ self.frame:SetAttribute("default-action",id)
+ if self.config.pageactions then
+ self.config.pageactions[1] = id
+ self.frame:SetAttribute("action-page1",id)
+ end
+ end
+end
+
+function Action:RefreshPages( force )
+ local nPages = self:GetBarConfig().nPages
+ if nPages and (nPages ~= self.nPages or force) then
+ local f = self:GetFrame()
+ local c = self.config.pageactions
+ if nPages > 1 and not c then
+ c = { }
+ self.config.pageactions = c
+ end
+ for i = 1, nPages do
+ if i > 1 then
+ c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
+ else
+ c[i] = self.config.actionID -- page 1 is the same as the base actionID
+ end
+ f:SetAttribute("action-page"..i,c[i])
+ end
+ for i = nPages+1, #c do
+ self:ReleaseActionID(c[i])
+ c[i] = nil
+ f:SetAttribute("action-page"..i,nil)
+ end
+ self.nPages = nPages
+ end
+end
+
+function Action:SetupBar( bar )
+ Super.SetupBar(self,bar)
+
+ local f = bar:GetFrame()
+ local config = bar:GetConfig()
+ f:SetAttribute("mindcontrol",config.mindcontrol)
+ f:SetAttribute("vehicle",config.vehicle)
+ f:Execute(
+ [[
+ doMindControl = self:GetAttribute("mindcontrol")
+ doVehicle = self:GetAttribute("vehicle")
+ control:ChildUpdate()
+ ]])
+
+ f:SetAttribute("_onstate-mc", _onstate_mc)
+ RegisterStateDriver(f, "mc", "[vehicleui] vehicle; [bonusbar:5] mc; none")
+
+ f:SetAttribute("lockbuttons",config.lockButtons)
+ f:SetAttribute("lockbuttonscombat",config.lockButtonsCombat)
+ f:Execute(
+ [[
+ lockButtons = self:GetAttribute("lockbuttons")
+ lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+ ]])
+end
+
+
+function Action:SetButtonLock( bar, lock, lockCombat )
+ local f = bar:GetFrame()
+ f:SetAttribute("lockbuttons",lock)
+ f:SetAttribute("lockbuttonscombat",lockCombat)
+ f:Execute(
+ [[
+ lockButtons = self:GetAttribute("lockbuttons")
+ lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+ ]])
+end
+
+
+function Action:ShowVehicleExit(show)
+ self.vehicleExitMode = show and self:GetBarConfig().vehicle
+ self:UpdateIcon()
+end
+
+function Action:OnEnter( )
+ self:SetTooltip()
+end
+
+function Action:OnLeave( )
+ GameTooltip:Hide()
+end
+
+function Action:OnAttributeChanged( attr, value )
+ if attr ~= "statehidden" then
+ self:UpdateAction()
+ end
+ local f = self:GetFrame()
+ f.action = f:GetAttribute("action") -- support ActionButton_UpdateFlyout
+end
+
+function Action:PostClick( )
+ self:UpdateCheckedState()
+end
+
+function Action:OnUpdate( elapsed )
+ self:RunFlash(elapsed)
+ self:RunRangeFinder(elapsed)
+end
+
+function Action:OnDragStart()
+ self:UpdateCheckedState()
+ self:UpdateFlash()
+end
+
+function Action:OnReceiveDrag()
+ self:UpdateCheckedState()
+ self:UpdateFlash()
+end
+
+function Action:OnEvent(event, ...)
+ if self[event] then
+ self[event](self, event, ...)
+ end
+end
+
+function Action:ACTIONBAR_SLOT_CHANGED(event, action)
+ if action == 0 or action == self.actionID then
+ self:UpdateAll()
+ end
+end
+
+function Action:PLAYER_ENTERING_WORLD()
+ self:UpdateAction()
+end
+
+function Action:ACTIONBAR_PAGE_CHANGED()
+ self:UpdateAction()
+end
+
+function Action:UPDATE_BONUS_ACTIONBAR()
+ self:UpdateAction()
+end
+
+function Action:UPDATE_BINDINGS()
+ self:UpdateHotkey()
+end
+
+function Action:PLAYER_TARGET_CHANGED()
+ self.rangeTimer = -1
+end
+
+function Action:ACTIONBAR_UPDATE_STATE()
+ self:UpdateCheckedState()
+end
+
+function Action:TRADE_SKILL_SHOW()
+ self:UpdateCheckedState()
+end
+Action.TRADE_SKILL_CLOSE = Action.TRADE_SKILL_CLOSE
+
+function Action:UNIT_ENTERED_VEHICLE(event,unit)
+ if unit == "player" then
+ self:UpdateCheckedState()
+ end
+end
+Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE
+
+function Action:COMPANION_UPDATE(event,unit)
+ if unit == "mount" then
+ self:UpdateCheckedState()
+ end
+end
+
+function Action:ACTIONBAR_UPDATE_USABLE()
+ self:UpdateUsable()
+end
+
+function Action:ACTIONBAR_UPDATE_COOLDOWN()
+ self:UpdateCooldown()
+end
+
+function Action:PLAYER_ENTER_COMBAT()
+ if IsAttackAction(self.actionID) then
+ self:SetFlash(true)
+ end
+end
+
+function Action:PLAYER_LEAVE_COMBAT()
+ if IsAttackAction(self.actionID) then
+ self:SetFlash(false)
+ end
+end
+
+function Action:START_AUTOREPEAT_SPELL()
+ if IsAutoRepeatAction(self.actionID) then
+ self:SetFlash(true)
+ end
+end
+
+function Action:STOP_AUTOREPEAT_SPELL()
+ if not IsAttackAction(self.actionID) then
+ self:SetFlash(false)
+ end
+end
+
+function Action:UNIT_INVENTORY_CHANGED(unit)
+ if unit == "player" then
+ self:UpdateTooltip()
+ end
+end
+
+function Action:LEARNED_SPELL_IN_TAB()
+ self:UpdateTooltip()
+end
diff -r f255cd69e890 -r 65f2805957a0 BagButton.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BagButton.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,499 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local GetCVar = GetCVar
+local ContainerIDToInventoryID = ContainerIDToInventoryID
+local NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES
+local IsModifiedClick = IsModifiedClick
+local CursorHasItem = CursorHasItem
+local GetInventoryItemTexture = GetInventoryItemTexture
+local GetInventorySlotInfo = GetInventorySlotInfo
+local PickupBagFromSlot = PickupBagFromSlot
+local CursorCanGoInSlot = CursorCanGoInSlot
+
+-- class declarations
+local buttonTypeID = "Bag"
+local weak = { __mode = "k" }
+local Super = ReAction.Button
+local BagBase = setmetatable(
+ {
+ defaultBarConfig = {
+ type = buttonTypeID,
+ btnWidth = 30,
+ btnHeight = 30,
+ btnRows = 1,
+ btnColumns = 6,
+ spacing = 4,
+ buttons = { }
+ },
+
+ barType = L["Bag Bar"],
+ buttonTypeID = buttonTypeID,
+
+ allButtons = setmetatable( { }, weak )
+ },
+ { __index = Super } )
+
+local Bag = setmetatable( { }, { __index = BagBase } )
+local Backpack = setmetatable( { }, { __index = BagBase } )
+local Keyring = setmetatable( { }, { __index = BagBase } )
+
+ReAction.Button.Bag = BagBase
+ReAction:RegisterBarType(BagBase)
+
+--
+-- Bag Button base class
+--
+
+function BagBase:New( btnCfg, bar, idx, idHint )
+ local name = format("ReAction_%s_Bag_%d",bar:GetName(),idx)
+
+ -- use a variable private leaf implementation class
+ -- unlike traditional OO programming, we can initialize the leaf
+ -- class before initializing its parent
+ local class = Bag
+ if idx == 1 then
+ class = Backpack
+ elseif idx == 6 then
+ class = Keyring
+ end
+ self = class:New(name, btnCfg, bar, idx)
+
+ local f = self:GetFrame()
+ local config = self:GetConfig()
+
+ -- set up the bag ID pool
+ self:SetActionIDPool("bag",6)
+ config.bagID = self:AcquireActionID(config.bagID, idHint, true)
+
+ -- non secure scripts
+ f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+ f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+ f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+ f:SetScript("OnReceiveDrag", function(frame, ...) self:OnReceiveDrag(...) end)
+ f:SetScript("OnClick", function(frame, ...) self:OnClick(...) end)
+
+ -- secure handlers
+ -- (none)
+
+ -- event registration
+ f:EnableMouse(true)
+ f:RegisterForClicks("LeftButtonUp","RightButtonUp")
+ f:RegisterEvent("UPDATE_BINDINGS")
+
+ -- frame setup
+ f:SetID(self:GetBagID())
+
+ if not f.hotkey then
+ local h = f:CreateFontString(name.."HotKey","ARTWORK","NumberFontNormalSmallGray")
+ h:SetWidth(30)
+ h:SetHeight(10)
+ h:SetJustifyH("RIGHT")
+ h:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
+ h:Show()
+ f.hotkey = h
+ end
+
+ if not _G[name.."ItemAnim"] then
+ local anim = CreateFrame("Model",name.."ItemAnim",f,"ItemAnimTemplate")
+ anim:SetPoint("BOTTOMRIGHT",f,"BOTTOMRIGHT",-10,0)
+ anim:Hide()
+ end
+
+ if not f.border then
+ local b = f:CreateTexture(name.."Border","OVERLAY")
+ b:SetAllPoints()
+ b:SetWidth(f:GetWidth()*(62/36))
+ b:SetHeight(f:GetHeight()*(62/36))
+ b:SetTexture("Interface\\Buttons\UI-ActionButton-Border")
+ b:SetBlendMode("ADD")
+ b:Hide()
+ f.border = b
+ end
+
+ self.frames.count:SetDrawLayer("ARTWORK")
+
+ self.frames.hotkey = f.hotkey
+ self.frames.border = _G[name.."Border"]
+ self.frames.icon = _G[name.."IconTexture"]
+ self.frames.anim = _G[name.."ItemAnim"]
+
+ -- initial display
+ if ReAction:GetConfigMode() then
+ self:GetFrame():Show()
+ end
+
+ self:Refresh()
+
+ BagBase.allButtons[self] = true
+
+ return self
+end
+
+function BagBase:Destroy()
+ BagBase.allButtons[self] = nil
+ Super.Destroy(self)
+end
+
+
+function BagBase:GetActionID()
+ return self.config.bagID
+end
+
+function BagBase:GetBagID()
+ return self:GetActionID() - 1
+end
+
+function BagBase:Refresh()
+ Super.Refresh(self)
+ self:UpdateHotkey()
+ self:Update()
+end
+
+function BagBase:Update()
+ self:UpdateChecked()
+end
+
+function BagBase:UpdateChecked(force)
+ if force == nil then
+ for i=1, NUM_CONTAINER_FRAMES do
+ local c = _G["ContainerFrame"..i]
+ if c:GetID() == self:GetBagID() and c:IsShown() then
+ self:GetFrame():SetChecked(1)
+ return
+ end
+ end
+ self:GetFrame():SetChecked(0)
+ end
+ self:GetFrame():SetChecked(force)
+end
+
+function BagBase:OnEvent(evt, ...)
+ if self[evt] then
+ self[evt](self, ...)
+ end
+end
+
+function BagBase:OnEnter()
+ self:SetTooltip()
+end
+
+function BagBase:OnLeave()
+ GameTooltip:Hide()
+end
+
+function BagBase:UPDATE_BINDINGS()
+ self:UpdateHotkey()
+end
+
+function BagBase:IterateAllButtons()
+ return pairs(self.allButtons)
+end
+
+
+--
+-- Bag Button class
+--
+function Bag:New(name, cfg, bar, idx)
+ self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
+
+ local f = self:GetFrame()
+
+ f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
+
+ f:RegisterEvent("CURSOR_UPDATE")
+ f:RegisterEvent("BAG_UPDATE")
+ f:RegisterEvent("BAG_CLOSED")
+ f:SetScript("OnDragStart", function(frame, ...) self:OnDragStart(...) end)
+ f:RegisterForDrag("LeftButton")
+
+ -- attach to skinner
+ bar:SkinButton(self,
+ {
+ Icon = _G[name.."IconTexture"]
+ }
+ )
+
+ return self
+end
+
+function Bag:GetInventorySlot()
+ return ContainerIDToInventoryID(self:GetBagID())
+end
+
+function Bag:GetInventorySlotName()
+ return "Bag"..(self:GetBagID()-1).."Slot"
+end
+
+function Bag:SetTooltip()
+ GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
+ if not GameTooltip:SetInventoryItem("player", self:GetInventorySlot()) then
+ GameTooltip:SetText(EQUIP_CONTAINER, 1.0, 1.0, 1.0)
+ end
+end
+
+function Bag:Update()
+ local texture = GetInventoryItemTexture("player", self:GetInventorySlot())
+ if texture then
+ self.frames.icon:SetTexture(texture)
+ self.frames.icon:Show()
+ self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+ else
+ local _, bgTex = GetInventorySlotInfo(self:GetInventorySlotName())
+ self.frames.icon:SetTexture(bgTex)
+ self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+ end
+ self:UpdateChecked()
+end
+
+function Bag:OnClick()
+ if IsModifiedClick("OPENALLBAGS") then
+ OpenAllBags()
+ else
+ if not PutItemInBag(self:GetInventorySlot()) then
+ ToggleBag(self:GetBagID())
+ end
+ end
+ self:UpdateChecked()
+end
+
+function Bag:OnReceiveDrag()
+ if CursorHasItem() then
+ PutItemInBag(self:GetInventorySlot())
+ end
+end
+
+function Bag:OnDragStart()
+ PickupBagFromSlot(self:GetInventorySlot())
+ self:Update()
+end
+
+function Bag:BAG_UPDATE(bag)
+ if bag == self:GetBagID() then
+ self:Update()
+ end
+end
+
+function Bag:CURSOR_UPDATE()
+ if CursorCanGoInSlot(self:GetInventorySlot()) then
+ self:GetFrame():LockHighlight()
+ else
+ self:GetFrame():UnlockHighlight()
+ end
+end
+
+function Bag:BAG_CLOSED(bag)
+ if bag == self:GetBagID() then
+ self:Update()
+ end
+end
+
+
+--
+-- Backpack Button class
+--
+function Backpack:New(name, cfg, bar, idx)
+ self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
+
+ local f = self:GetFrame()
+ local icon = _G[name.."IconTexture"]
+ icon:SetTexture("Interface\\Buttons\\Button-Backpack-Up")
+ icon:Show()
+ f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
+ f:RegisterEvent("PLAYER_ENTERING_WORLD");
+ f:RegisterEvent("CVAR_UPDATE");
+ f:SetScript("OnShow", function(frame, ...) self:OnShow(...) end)
+
+ -- attach to skinner
+ bar:SkinButton(self,
+ {
+ Icon = _G[name.."IconTexture"]
+ }
+ )
+
+ return self
+end
+
+function Backpack:Update()
+ self:UpdateFreeSlots()
+ self:UpdateChecked()
+end
+
+function Backpack:UpdateFreeSlots()
+ if GetCVar("displayFreeBagSlots") == "1" then
+ local total = 0
+ for i = BACKPACK_CONTAINER, NUM_BAG_SLOTS do
+ local free, family = GetContainerNumFreeSlots(i)
+ if family == 0 then
+ total = total + free
+ end
+ end
+
+ self.freeSlots = total
+ self.frames.count:SetText(format("(%s)", self.freeSlots))
+ self.frames.count:Show()
+ elseif self.frames.count:IsShown() then
+ self.frames.count:Hide()
+ end
+end
+
+function Backpack:SetTooltip()
+ GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
+ GameTooltip:SetText(BACKPACK_TOOLTIP, 1.0, 1.0, 1.0)
+ GameTooltip:AddLine(string.format(NUM_FREE_SLOTS, (self.freeSlots or 0)))
+ GameTooltip:Show();
+end
+
+function Backpack:OnShow()
+ self:UpdateFreeSlots()
+end
+
+function Backpack:OnClick()
+ if IsModifiedClick("OPENALLBAGS") then
+ OpenAllBags()
+ else
+ if not PutItemInBackpack() then
+ ToggleBackpack()
+ end
+ end
+ self:UpdateChecked()
+end
+
+function Backpack:OnReceiveDrag()
+ if CursorHasItem() then
+ PutItemInBackpack()
+ end
+end
+
+function Backpack:PLAYER_ENTERING_WORLD()
+ self:CVAR_UPDATE("DISPLAY_FREE_BAG_SLOTS", GetCVar("displayFreeBagSlots"))
+end
+
+function Backpack:CVAR_UPDATE( cvar, value )
+ if cvar == "DISPLAY_FREE_BAG_SLOTS" then
+ if value == "1" then
+ self:GetFrame():RegisterEvent("BAG_UPDATE")
+ else
+ self:GetFrame():UnregisterEvent("BAG_UPDATE")
+ end
+ self:UpdateFreeSlots()
+ end
+end
+
+function Backpack:BAG_UPDATE(bag)
+ if bag >= BACKPACK_CONTAINER and bag <= NUM_BAG_SLOTS then
+ self:UpdateFreeSlots()
+ end
+end
+
+
+--
+-- Keyring Button class
+--
+function Keyring:New(name, cfg, bar, idx)
+ self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
+
+ local f = self:GetFrame()
+
+ f:SetWidth(18)
+ f:SetHeight(39)
+
+ local tex = f:GetNormalTexture()
+ tex:ClearAllPoints()
+ tex:SetAllPoints()
+
+ f:SetNormalTexture("Interface\\Buttons\\UI-Button-KeyRing")
+ f:SetHighlightTexture("Interface\\Buttons\\UI-Button-KeyRing-Highlight")
+ f:SetPushedTexture("Interface\\Buttons\\UI-Button-KeyRing-Down")
+ f:GetNormalTexture():SetTexCoord(0,0.5625,0,0.609375)
+ f:GetHighlightTexture():SetTexCoord(0,0.5625,0,0.609375)
+ f:GetPushedTexture():SetTexCoord(0,0.5625,0,0.609375)
+
+ if not HasKey() then
+ f:Hide()
+ end
+
+ -- DO NOT attach to skinner
+
+ return self
+end
+
+function Keyring:GetBagID()
+ return KEYRING_CONTAINER
+end
+
+function Keyring:Refresh()
+ local f = self:GetFrame()
+ self.bar:PlaceButton( self, f:GetHeight(), f:GetHeight() ) -- use height x height since it's an odd size
+ self:UpdateHotkey()
+ self:Update()
+end
+
+function Keyring:SetTooltip()
+ GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT");
+ GameTooltip:SetText(KEYRING, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine();
+end
+
+function Keyring:OnReceiveDrag()
+ if CursorHasItem() then
+ PutKeyInKeyRing()
+ end
+end
+
+function Keyring:OnClick()
+ if CursorHasItem() then
+ PutKeyInKeyRing()
+ else
+ ToggleKeyRing()
+ end
+ self:UpdateChecked()
+end
+
+function Keyring:ShowGridTemp(show)
+ if not HasKey() then
+ if show then
+ self:GetFrame():Show()
+ else
+ self:GetFrame():Hide()
+ end
+ end
+end
+
+
+
+-- hook some functions to propagate to our bag buttons
+hooksecurefunc("Disable_BagButtons",
+ function()
+ for b in BagBase:IterateAllButtons() do
+ local f = b:GetFrame()
+ f:Disable()
+ SetDesaturation(b.frames.icon,1)
+ end
+ end)
+
+hooksecurefunc("Enable_BagButtons",
+ function()
+ for b in BagBase:IterateAllButtons() do
+ local f = b:GetFrame()
+ f:Enable()
+ SetDesaturation(b.frames.icon,nil)
+ end
+ end)
+
+hooksecurefunc("ContainerFrame_OnHide",
+ function()
+ for b in BagBase:IterateAllButtons() do
+ b:Update()
+ end
+ end)
+
+hooksecurefunc("ContainerFrame_OnShow",
+ function()
+ for b in BagBase:IterateAllButtons() do
+ b:Update()
+ end
+ end)
diff -r f255cd69e890 -r 65f2805957a0 Bar.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Bar.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,854 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local LKB = ReAction.LKB
+local _G = _G
+local CreateFrame = CreateFrame
+local floor = math.floor
+local fmod = math.fmod
+local format = string.format
+local tfetch = addonTable.tfetch
+local tbuild = addonTable.tbuild
+local fieldsort = addonTable.fieldsort
+
+local LSG = LibStub("ReAction-LibShowActionGrid-1.0")
+
+---- Secure snippets ----
+local _reaction_init =
+[[
+ anchorKeys = newtable("point","relPoint","x","y")
+
+ state = nil
+ set_state = nil
+ state_override = nil
+ unit_exists = nil
+
+ showAll = false
+ hidden = false
+
+ defaultAlpha = 1.0
+ defaultScale = 1.0
+ defaultAnchor = newtable()
+
+ activeStates = newtable()
+ settings = newtable()
+ extensions = newtable()
+]]
+
+local _reaction_refresh =
+[[
+ local oldState = state
+ state = state_override or set_state or state
+
+ local hide = nil
+ if state then
+ local settings = settings[state]
+ if settings then
+ -- show/hide
+ hide = settings.hide
+ -- re-anchor
+ local old_anchor = activeStates.anchor
+ activeStates.anchor = settings.anchorEnable and state
+ if old_anchor ~= activeStates.anchor or not set_state then
+ if activeStates.anchor then
+ if settings.anchorPoint then
+ self:ClearAllPoints()
+ local f = self:GetAttribute("frameref-anchor-"..state)
+ if f then
+ self:SetPoint(settings.anchorPoint, f, settings.anchorRelPoint, settings.anchorX, settings.anchorY)
+ end
+ end
+ elseif defaultAnchor.point then
+ self:ClearAllPoints()
+ self:SetPoint(defaultAnchor.point, defaultAnchor.frame,
+ defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
+ end
+ end
+ -- re-scale
+ local old_scale = activeStates.scale
+ activeStates.scale = settings.enableScale and state
+ if old_scale ~= activeStates.scale or not set_state then
+ self:SetScale(activeStates.scale and settings.scale or defaultScale)
+ end
+ -- alpha
+ local old_alpha = activeStates.alpha
+ activeStates.alpha = settings.enableAlpha and state
+ if old_alpha ~= activeStates.alpha or not set_state then
+ self:SetAlpha(activeStates.alpha and settings.alpha or defaultAlpha)
+ end
+ end
+ end
+
+ -- hide if state or unit_exists says to
+ hide = not showAll and (hide or unithide)
+ if hide ~= hidden then
+ hidden = hide
+ if hide then
+ self:Hide()
+ else
+ self:Show()
+ end
+ end
+
+ for _, attr in pairs(extensions) do
+ control:RunAttribute(attr)
+ end
+
+ control:ChildUpdate()
+
+ if showAll then
+ control:CallMethod("UpdateHiddenLabel", state and settings[state] and settings[state].hide)
+ end
+
+ if oldState ~= state then
+ control:CallMethod("StateRefresh", state)
+ end
+]]
+
+local _onstate_reaction = -- function( self, stateid, newstate )
+[[
+ set_state = newstate
+]] .. _reaction_refresh
+
+local _onstate_showgrid = -- function( self, stateid, newstate )
+[[
+ control:ChildUpdate(stateid,newstate)
+ control:CallMethod("UpdateShowGrid")
+]]
+
+local _onstate_unitexists = -- function( self, stateid, newstate )
+[[
+ unithide = not newstate or newstate == "hide"
+]] .. _reaction_refresh
+
+local _onclick = -- function( self, button, down )
+[[
+ if state_override == button then
+ state_override = nil -- toggle
+ else
+ state_override = button
+ end
+]] .. _reaction_refresh
+
+-- For reference
+-- the option field names must match the field names of the options table, below
+local stateProperties = {
+ hide = true,
+ --keybindState = true, TODO: broken
+ anchorEnable = true,
+ anchorFrame = true,
+ anchorPoint = true,
+ anchorRelPoint = true,
+ anchorX = true,
+ anchorY = true,
+ enableScale = true,
+ scale = true,
+ enableAlpha = true,
+ alpha = true,
+}
+
+
+
+---- Bar class ----
+local Bar = { }
+local frameList = { }
+
+ReAction.Bar = Bar -- export to ReAction
+
+function Bar:New( name, config, buttonClass )
+ if type(config) ~= "table" then
+ error("ReAction.Bar: config table required")
+ end
+
+ -- create new self
+ self = setmetatable(
+ {
+ config = config,
+ name = name,
+ buttons = { },
+ buttonClass = buttonClass,
+ width = config.width or 480,
+ height = config.height or 40,
+ },
+ {__index = self} )
+
+ -- The frame type is 'Button' in order to have an OnClick handler. However, the frame itself is
+ -- not mouse-clickable by the user.
+ local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
+ name = name and "ReAction-"..name
+ local f = name and frameList[name]
+ if not f then
+ f = CreateFrame("Button", name, parent, "SecureHandlerStateTemplate, SecureHandlerClickTemplate")
+ if name then
+ frameList[name] = f
+ end
+ end
+ f:SetFrameStrata("MEDIUM")
+ f:SetWidth(self.width)
+ f:SetHeight(self.height)
+ f:SetAlpha(config.alpha or 1.0)
+ f:Show()
+ f:EnableMouse(false)
+ f:SetClampedToScreen(true)
+ LSG:AddFrame(f)
+
+ -- secure handlers
+ f:Execute(_reaction_init)
+ f:SetAttribute("_onstate-reaction", _onstate_reaction)
+ f:SetAttribute("_onstate-showgrid", _onstate_showgrid)
+ f:SetAttribute("_onstate-unitexists", _onstate_unitexists)
+ f:SetAttribute("_onclick", _onclick)
+
+ -- secure handler CallMethod()s
+ f.UpdateShowGrid = function() self:UpdateShowGrid() end
+ f.StateRefresh = function() self:RefreshControls() end
+ f.UpdateHiddenLabel = function(f,hidden) self:SetLabelSubtext(hidden and L["Hidden"]) end
+
+ -- Override the default frame accessor to provide strict read-only access
+ function self:GetFrame()
+ return f
+ end
+
+ self:ApplyAnchor()
+ self:SetConfigMode(ReAction:GetConfigMode())
+ self:SetKeybindMode(ReAction:GetKeybindMode())
+
+ if ReAction.LBF then
+ local g = ReAction.LBF:Group(L["ReAction"], self.name)
+ self.config.ButtonFacade = self.config.ButtonFacade or {
+ skinID = "Blizzard",
+ backdrop = true,
+ gloss = 0,
+ colors = {},
+ }
+ local c = self.config.ButtonFacade
+ g:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
+ self.LBFGroup = g
+ end
+
+ ReAction.RegisterCallback(self, "OnConfigModeChanged")
+
+ buttonClass:SetupBar(self)
+ self:ApplyStates()
+
+ return self
+end
+
+function Bar:Destroy()
+ local f = self:GetFrame()
+ self:CleanupStates()
+ for idx, b in self:IterateButtons() do
+ b:Destroy()
+ end
+ f:UnregisterAllEvents()
+ self:ShowControls(false)
+ ReAction.UnregisterAllCallbacks(self)
+ LKB.UnregisterAllCallbacks(self)
+ if self.LBFGroup then
+ self.LBFGroup:Delete(true)
+ end
+ LSG:RemoveFrame(f)
+ f:SetParent(UIParent)
+ f:ClearAllPoints()
+ f:Hide()
+end
+
+--
+-- Events
+--
+
+function Bar:OnConfigModeChanged(event, mode)
+ self:SetConfigMode(mode)
+end
+
+--
+-- Accessors
+--
+
+function Bar:GetName()
+ return self.name
+end
+
+-- only ReAction:RenameBar() should call this function. Calling from any other
+-- context will desync the bar list in the ReAction class.
+function Bar:SetName(name)
+ if self.LBFGroup then
+ -- LBF doesn't offer a method of renaming a group, so delete and remake the group.
+ local c = self.config.ButtonFacade
+ local g = ReAction.LBF:Group(L["ReAction"], name)
+ for idx, b in self:IterateButtons() do
+ self.LBFGroup:RemoveButton(b:GetFrame(), true)
+ g:AddButton(b:GetFrame())
+ end
+ self.LBFGroup:Delete(true)
+ self.LBFGroup = g
+ self.LBFGroup:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
+ end
+ self.name = name
+ if self.overlay then
+ self.overlay:SetLabel(self.name)
+ end
+end
+
+function Bar:GetFrame()
+ -- this method is included for documentation purposes. It is overridden
+ -- for each object in the :New() method.
+ error("Invalid Bar object: used without initialization")
+end
+
+function Bar:GetButton(idx)
+ return self.buttons[idx]
+end
+
+function Bar:GetButtonClass()
+ return self.buttonClass
+end
+
+function Bar:GetConfig()
+ return self.config
+end
+
+function Bar:GetAnchor()
+ local c = self.config
+ return (c.point or "CENTER"),
+ (c.anchor or self:GetFrame():GetParent():GetName()),
+ (c.relpoint or c.point or "CENTER"),
+ (c.x or 0),
+ (c.y or 0)
+end
+
+function Bar:SetAnchor(point, frame, relativePoint, x, y)
+ local c = self.config
+ c.point = point or c.point
+ c.anchor = frame or c.anchor
+ c.relpoint = relativePoint or c.relpoint
+ c.x = x or c.x
+ c.y = y or c.y
+ self:ApplyAnchor()
+end
+
+function Bar:GetSize()
+ local f = self:GetFrame()
+ return f:GetWidth(), f:GetHeight()
+end
+
+function Bar:SetSize(w,h)
+ local f = self:GetFrame()
+ self.config.width = w
+ self.config.height = h
+ f:SetWidth(w)
+ f:SetHeight(h)
+end
+
+function Bar:GetButtonSize()
+ local w = self.config.btnWidth or 32
+ local h = self.config.btnHeight or 32
+ -- TODO: get from modules?
+ return w,h
+end
+
+function Bar:SetButtonSize(w,h)
+ if w > 0 and h > 0 then
+ self.config.btnWidth = w
+ self.config.btnHeight = h
+ end
+end
+
+function Bar:GetNumButtons()
+ local r,c = self:GetButtonGrid()
+ return r*c
+end
+
+function Bar:GetButtonGrid()
+ local cfg = self.config
+ local r = cfg.btnRows or 1
+ local c = cfg.btnColumns or 1
+ local s = cfg.spacing or 4
+ return r,c,s
+end
+
+function Bar:SetButtonGrid(r,c,s)
+ if r > 0 and c > 0 and s > 0 then
+ local cfg = self.config
+ cfg.btnRows = r
+ cfg.btnColumns = c
+ cfg.spacing = s
+ end
+ self.buttonClass:SetupBar(self)
+end
+
+function Bar:GetAlpha()
+ return self.config.alpha or 1.0
+end
+
+function Bar:SetAlpha(value)
+ self.config.alpha = value
+ self:GetFrame():SetAlpha(value or 1.0)
+ self:UpdateDefaultStateAlpha()
+end
+
+function Bar:IterateButtons()
+ -- iterator returns idx, button, but does NOT iterate in index order
+ return pairs(self.buttons)
+end
+
+--
+-- Methods
+--
+
+function Bar:SetConfigMode(mode)
+ self:SetSecureData("showAll",mode)
+ self:ShowControls(mode)
+ for idx, b in self:IterateButtons() do
+ b:ShowGridTemp(mode)
+ b:UpdateActionIDLabel(mode)
+ end
+end
+
+function Bar:SetKeybindMode(mode)
+ self:SetSecureData("showAll",mode)
+ for idx, b in self:IterateButtons() do
+ b:SetKeybindMode(mode)
+ end
+end
+
+function Bar:ApplyAnchor()
+ local f = self:GetFrame()
+ local c = self.config
+ local p = c.point
+
+ f:SetWidth(c.width)
+ f:SetHeight(c.height)
+ f:ClearAllPoints()
+
+ if p then
+ local a = f:GetParent()
+ if c.anchor then
+ local bar = ReAction:GetBar(c.anchor)
+ if bar then
+ a = bar:GetFrame()
+ else
+ a = _G[c.anchor]
+ end
+ end
+ local fr = a or f:GetParent()
+ f:SetPoint(p, a or f:GetParent(), c.relpoint, c.x or 0, c.y or 0)
+ else
+ f:SetPoint("CENTER")
+ end
+
+ self:UpdateDefaultStateAnchor()
+end
+
+function Bar:ClipNButtons( n )
+ local cfg = self.config
+ local r = cfg.btnRows or 1
+ local c = cfg.btnColumns or 1
+
+ cfg.btnRows = ceil(n/c)
+ cfg.btnColumns = min(n,c)
+end
+
+function Bar:AddButton(idx, button)
+ local f = self:GetFrame()
+
+ self.buttons[idx] = button
+
+ -- Store a properly wrapped reference to the child frame as an attribute
+ -- (accessible via "frameref-btn#")
+ f:SetFrameRef(format("btn%d",idx), button:GetFrame())
+
+ -- button constructors are responsible for calling SkinButton
+end
+
+function Bar:RemoveButton(button)
+ local idx = button:GetIndex()
+ if idx then
+ self:GetFrame():SetAttribute(format("frameref-btn%d",idx),nil)
+ self.buttons[idx] = nil
+ end
+ if self.LBFGroup then
+ self.LBFGroup:RemoveButton(button:GetFrame(),true)
+ end
+end
+
+function Bar:PlaceButton(button, baseW, baseH)
+ local idx = button:GetIndex()
+ if idx then
+ local r, c, s = self:GetButtonGrid()
+ local bh, bw = self:GetButtonSize()
+ local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
+ local x, y = col*bw + (col+0.5)*s, -(row*bh + (row+0.5)*s)
+ local scale = bw/baseW
+ local b = button:GetFrame()
+
+ b:ClearAllPoints()
+ b:SetPoint("TOPLEFT",x/scale,y/scale)
+ b:SetScale(scale)
+ end
+end
+
+function Bar:SkinButton( button, data )
+ if self.LBFGroup then
+ self.LBFGroup:AddButton(button:GetFrame(), data)
+ end
+end
+
+function Bar:UpdateShowGrid()
+ for idx, button in self:IterateButtons() do
+ button:UpdateShowGrid()
+ end
+end
+
+function Bar:ShowControls(show)
+ if show then
+ if not self.overlay then
+ self.overlay = Bar.Overlay:New(self) -- see Overlay.lua
+ end
+ self.overlay:Show()
+ self:RefreshSecureState()
+ elseif self.overlay then
+ self.overlay:Hide()
+ end
+end
+
+function Bar:RefreshControls()
+ if self.overlay and self.overlay:IsShown() then
+ self.overlay:RefreshControls()
+ end
+end
+
+function Bar:SetLabelSubtext(text)
+ if self.overlay then
+ self.overlay:SetLabelSubtext(text)
+ end
+end
+
+--
+-- Secure state functions
+--
+
+function Bar:GetSecureState()
+ local env = GetManagedEnvironment(self:GetFrame())
+ return env and env.state
+end
+
+function Bar:GetStateProperty(state, propname)
+ return tfetch(self:GetConfig(), "states", state, propname)
+end
+
+function Bar:SetStateProperty(state, propname, value)
+ local s = tbuild(self:GetConfig(), "states", state)
+ s[propname] = value
+ self:SetSecureStateData(state, propname, value)
+end
+
+function Bar:ApplyStates()
+ local states = tfetch(self:GetConfig(), "states")
+ if states then
+ self:SetStateDriver(states)
+ end
+end
+
+function Bar:CleanupStates()
+ self:SetStateDriver(nil)
+end
+
+function Bar:RefreshSecureState()
+ self:GetFrame():Execute(_reaction_refresh)
+end
+
+-- usage: SetSecureData(globalname, [tblkey1, tblkey2, ...], value)
+function Bar:SetSecureData( ... )
+ local n = select('#',...)
+ if n < 2 then
+ error("ReAction.Bar:SetSecureData() requires at least 2 arguments")
+ end
+ local f = self:GetFrame()
+ f:SetAttribute("data-depth",n-1)
+ f:SetAttribute("data-value",select(n,...))
+ for i = 1, n-1 do
+ local key = select(i,...)
+ if key == nil then
+ error("ReAction.Bar:SetSecureData() - nil table key in argument list (#"..i..")")
+ end
+ f:SetAttribute("data-key-"..i, key)
+ end
+ f:Execute(
+ [[
+ local n = self:GetAttribute("data-depth")
+ if n > 0 then
+ local value = self:GetAttribute("data-value")
+ local t = _G
+ for i = 1, n do
+ local key = self:GetAttribute("data-key-"..i)
+ if not key then return end
+ if not t[key] then
+ t[key] = newtable()
+ end
+ if i == n then
+ t[key] = value
+ else
+ t = t[key]
+ end
+ end
+ end
+ ]])
+ self:RefreshSecureState()
+end
+
+function Bar:SetSecureStateData( state, key, value )
+ self:SetSecureData("settings",state,key,value)
+end
+
+-- sets a snippet to be run as an extension to _onstate-reaction
+function Bar:SetSecureStateExtension( id, snippet )
+ if id == nil then
+ error("ReAction.Bar:SetSecureStateExtension() requires an id")
+ end
+ local f = self:GetFrame()
+ f:SetAttribute("input-secure-ext-id",id)
+ f:SetAttribute("secure-ext-"..id,snippet)
+ f:Execute(
+ [[
+ local id = self:GetAttribute("input-secure-ext-id")
+ if id then
+ extensions[id] = self:GetAttribute("secure-ext-"..id) or nil
+ end
+ ]])
+ self:RefreshSecureState()
+end
+
+function Bar:SetFrameRef( name, refFrame )
+ if refFrame then
+ local _, explicit = refFrame:IsProtected()
+ if not explicit then
+ refFrame = nil
+ end
+ end
+ if refFrame then
+ self:GetFrame():SetFrameRef(name,refFrame)
+ else
+ self:GetFrame():SetAttribute("frameref-"..name,nil)
+ end
+end
+
+function Bar:SetStateDriver( states )
+ if states then
+ for state, props in pairs(states) do
+ self:SetSecureStateData(state, "active_", true) -- make sure there's a 'settings' field for this state
+ for propname, value in pairs(props) do
+ if propname == "anchorFrame" then
+ self:SetFrameRef("anchor-"..state, _G[value])
+ elseif propname == "rule" then
+ -- do nothing
+ else
+ self:SetSecureStateData(state, propname, value)
+ end
+ end
+ end
+ end
+ local rule = states and self:BuildStateRule(states)
+ if rule then
+ RegisterStateDriver(self:GetFrame(),"reaction",rule)
+ elseif self.statedriver then
+ UnregisterStateDriver(self:GetFrame(),"reaction")
+ end
+ self.statedriver = rule
+ self:BuildStateKeybinds(states)
+ self:RefreshSecureState()
+end
+
+-- pass unit=nil to set up the unit elsewhere, if you want something more complex
+function Bar:RegisterUnitWatch( unit, enable )
+ local f = self:GetFrame()
+ if unit then
+ f:SetAttribute("unit",unit)
+ end
+ if enable then
+ if not self.unitwatch then
+ RegisterUnitWatch(self:GetFrame(),true)
+ end
+ elseif self.unitwatch then
+ UnregisterUnitWatch(self:GetFrame())
+ end
+ self.unitwatch = enable
+ self:RefreshSecureState()
+end
+
+function Bar:SetStateKeybind( key, state )
+ local f = self:GetFrame()
+ local binds = self.statebinds
+ if not binds then
+ binds = { }
+ self.statebinds = binds
+ end
+
+ -- clear the old binding, if any
+ if binds[state] then
+ SetOverrideBinding(f, false, binds[state], nil)
+ end
+
+ if key then
+ SetOverrideBindingClick(f, false, key, f:GetName(), state) -- state name is virtual mouse button
+ end
+ binds[state] = key
+end
+
+function Bar:GetStateKeybind( state )
+ if self.statebinds and state then
+ return self.statebinds[state]
+ end
+end
+
+function Bar:UpdateDefaultStateAnchor()
+ local point, frame, relPoint, x, y = self:GetAnchor()
+ local f = self:GetFrame()
+ f:SetAttribute("defaultAnchor-point",point)
+ f:SetAttribute("defaultAnchor-relPoint",relPoint)
+ f:SetAttribute("defaultAnchor-x",x)
+ f:SetAttribute("defaultAnchor-y",y)
+ self:SetFrameRef("defaultAnchor",_G[frame or "UIParent"])
+ f:Execute([[
+ for _, k in pairs(anchorKeys) do
+ defaultAnchor[k] = self:GetAttribute("defaultAnchor-"..k)
+ end
+ defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
+ ]])
+end
+
+function Bar:UpdateDefaultStateAlpha()
+ local f = self:GetFrame()
+ f:SetAttribute("defaultAlpha",self:GetAlpha())
+ f:Execute([[
+ defaultAlpha = self:GetAttribute("defaultAlpha")
+ ]])
+end
+
+---- secure state driver rules ----
+
+local playerClass = select(2, UnitClass("player"))
+local function ClassFilter(...)
+ for i = 1, select('#',...) do
+ if playerClass == select(i,...) then
+ return false
+ end
+ end
+ return true
+end
+
+local ruleformats = {
+ stealth = { format = "stealth", filter = ClassFilter("ROGUE","DRUID") },
+ nostealth = { format = "nostealth", filter = ClassFilter("ROGUE","DRUID") },
+ shadowdance = { format = "bonusbar:2", filter = ClassFilter("ROGUE") },
+ shadowform = { format = "form:1", filter = ClassFilter("PRIEST") },
+ noshadowform = { format = "noform", filter = ClassFilter("PRIEST") },
+ battle = { format = "stance:1", filter = ClassFilter("WARRIOR") },
+ defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") },
+ berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") },
+ caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") },
+ bear = { format = "form:1", filter = ClassFilter("DRUID") },
+ cat = { format = "form:3", filter = ClassFilter("DRUID") },
+ tree = { format = "form:5", filter = ClassFilter("DRUID") },
+ moonkin = { format = "form:5", filter = ClassFilter("DRUID") },
+ demon = { format = "form:2", filter = ClassFilter("WARLOCK") },
+ nodemon = { format = "noform", filter = ClassFilter("WARLOCK") },
+ pet = { format = "pet" },
+ nopet = { format = "nopet" },
+ harm = { format = "@target,harm" },
+ help = { format = "@target,help" },
+ notarget = { format = "@target,noexists" },
+ focusharm = { format = "@focus,harm" },
+ focushelp = { format = "@focus,help" },
+ nofocus = { format = "@focus,noexists" },
+ raid = { format = "group:raid" },
+ party = { format = "group:party" },
+ solo = { format = "nogroup" },
+ combat = { format = "combat" },
+ nocombat = { format = "nocombat" },
+ possess = { format = "@vehicle,noexists,bonusbar:5" },
+ vehicle = { format = "@vehicle,exists,bonusbar:5" },
+}
+
+function Bar.InitRuleFormats()
+ local forms = { }
+ for i = 1, GetNumShapeshiftForms() do
+ local _, name = GetShapeshiftFormInfo(i)
+ forms[name] = i;
+ end
+ -- use 9 if not found since 9 is never a valid stance/form
+ local defensive = forms[GetSpellInfo(71)] or 9
+ local berserker = forms[GetSpellInfo(2458)] or 9
+ local bear = forms[GetSpellInfo(5487)] or 9
+ local aquatic = forms[GetSpellInfo(1066)] or 9
+ local cat = forms[GetSpellInfo(768)] or 9
+ local travel = forms[GetSpellInfo(783)] or 9
+ local tree = forms[GetSpellInfo(33891)] or 9
+ local moonkin = forms[GetSpellInfo(24858)] or 9
+ local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9
+
+ ruleformats.defensive.format = "stance:"..defensive
+ ruleformats.berserker.format = "stance:"..berserker
+ ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight)
+ ruleformats.bear.format = "form:"..bear
+ ruleformats.cat.format = "form:"..cat
+ ruleformats.tree.format = "form:"..tree
+ ruleformats.moonkin.format = "form:"..moonkin
+end
+
+function Bar:BuildStateRule(states)
+ -- states is a table :
+ -- states[statename].rule = {
+ -- order = #,
+ -- type = "default"/"custom"/"any"/"all",
+ -- values = { ... }, -- keys of ruleformats[]
+ -- custom = "...",
+ -- }
+ local rules = { }
+ local default
+
+ for idx, state in ipairs(fieldsort(states, "rule", "order")) do
+ local c = states[state].rule
+ local type = c.type
+ if type == "default" then
+ default = default or state
+ elseif type == "custom" then
+ if c.custom then
+ -- strip out all spaces from the custom rule
+ table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state))
+ end
+ elseif type == "any" or type == "all" then
+ if c.values then
+ local clauses = { }
+ for key, value in pairs(c.values) do
+ if ruleformats[key] and not ruleformats[key].filter then
+ table.insert(clauses, ruleformats[key].format)
+ end
+ end
+ if #clauses > 0 then
+ local sep = (type == "any") and "][" or ","
+ table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state))
+ end
+ end
+ end
+ end
+ -- make sure that the default, if any, is last
+ if default then
+ table.insert(rules, default)
+ end
+ return table.concat(rules,";")
+end
+
+function Bar:BuildStateKeybinds( states )
+ if states then
+ for name, state in pairs(states) do
+ local rule = tfetch(state, "rule")
+ if rule and rule.type == "keybind" then
+ self:SetStateKeybind(rule.keybind, name)
+ else
+ self:SetStateKeybind(nil, name) -- this clears an existing keybind
+ end
+ end
+ end
+end
+
diff -r f255cd69e890 -r 65f2805957a0 Button.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Button.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,359 @@
+--[[
+ ReAction Button base class
+--]]
+
+-- local imports
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local LKB = ReAction.LKB
+local _G = _G
+local CreateFrame = CreateFrame
+local GetBindingKey = GetBindingKey
+local format = string.format
+
+-- private
+local trash = CreateFrame("Frame")
+local frameList = { }
+local idPools = { }
+
+local function kb_onEnter( frame )
+ LKB:Set(frame)
+end
+
+-- Button class
+local buttonTypeID = "Button"
+local Button = {
+ defaultBarConfig = {
+ type = buttonTypeID,
+ btnWidth = 36,
+ btnHeight = 36,
+ btnRows = 1,
+ btnColumns = 12,
+ spacing = 3
+ },
+ barType = L["Button Bar"]
+}
+
+ReAction.Button = Button -- export to ReAction
+
+function Button:New( name, config, bar, idx, inherits, buttonType )
+ buttonType = buttonType or "CheckButton"
+
+ -- create new self
+ self = setmetatable(
+ {
+ bar = bar,
+ idx = idx,
+ config = config,
+ name = name,
+ },
+ { __index = self } )
+
+ -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
+ -- existing globals. Can't set to nil in the global because it's then tainted.
+ -- Caller is responsible for ensuring global uniqueness of names.
+ local f = name and frameList[name]
+ if f then
+ f:SetParent(bar:GetFrame())
+ else
+ f = CreateFrame(buttonType, name, bar:GetFrame(), inherits)
+ if name then
+ frameList[name] = f
+ end
+ end
+
+ self.frame = f
+
+ local frames = { }
+ self.frames = frames
+ frames.icon = _G[name.."Icon"]
+ frames.flash = _G[name.."Flash"]
+ frames.hotkey = _G[name.."HotKey"]
+ frames.count = _G[name.."Count"]
+ frames.name = _G[name.."Name"]
+ frames.border = _G[name.."Border"]
+ frames.cooldown = _G[name.."Cooldown"]
+ frames.normalTexture = _G[name.."NormalTexture"]
+
+ if config then
+ config.name = name
+ end
+
+ -- install LibKeyBound handlers onto frame
+ function f:GetActionName()
+ return format("%s:%s", bar:GetName(), idx)
+ end
+
+ local clickBinding = format("CLICK %s:LeftButton", name)
+ function f:GetHotkey()
+ return LKB:ToShortKey(GetBindingKey(clickBinding))
+ end
+
+ return self
+end
+
+function Button:Destroy()
+ local f = self:GetFrame()
+ f:UnregisterAllEvents()
+ self:ReleaseActionID(self:GetActionID())
+ if f then
+ f:Hide()
+ f:SetParent(trash)
+ f:ClearAllPoints()
+ end
+end
+
+function Button:GetBar()
+ return self.bar
+end
+
+function Button:GetFrame()
+ return self.frame
+end
+
+function Button:GetIndex()
+ return self.idx
+end
+
+function Button:GetName()
+ return self.name
+end
+
+function Button:GetDefaultBarConfig()
+ return self.defaultBarConfig
+end
+
+function Button:GetBarType()
+ return self.barType
+end
+
+function Button:GetButtonTypeID()
+ return self.buttonTypeID
+end
+
+function Button:GetConfig()
+ return self.config
+end
+
+function Button:GetActionID()
+ -- derived classes should override this
+ return nil
+end
+
+function Button:SetActionIDPool( poolID, maxID )
+ self.actionPoolID = poolID
+ self.actionMaxID = maxID
+end
+
+function Button:SetupBar( bar )
+ local config = bar:GetConfig()
+ if not config.buttons then
+ config.buttons = { }
+ end
+ local btnCfg = config.buttons
+
+ local r, c = bar:GetButtonGrid()
+ local n = r*c
+ local cfgN = n
+
+ local hint = nil
+ local i = 1
+ repeat
+ local b = bar:GetButton(i)
+ if b then
+ if i > n then
+ bar:RemoveButton(b)
+ b:Destroy()
+ if i > cfgN then
+ btnCfg[i] = nil
+ end
+ else
+ b:Refresh()
+ hint = b:GetActionID()
+ end
+ elseif i <= n then
+ local cfg = btnCfg[i] or { }
+ local success, r = pcall(self.New, self, cfg, bar, i, hint) -- note call semantics for derived class constructors
+ if success and r then
+ b = r
+ bar:AddButton(i,b)
+ btnCfg[i] = cfg
+ b:Refresh()
+ hint = b:GetActionID()
+ else
+ n = i - 1
+ if not success then
+ bar:ClipNButtons(n)
+ cfgN = n
+ geterrorhandler()(r)
+ end
+ end
+ end
+ i = i + 1
+ until b == nil
+end
+
+function Button:AcquireActionID( id, hint, unique )
+ local poolID = self.actionPoolID
+ local maxID = self.actionMaxID
+ if not poolID or not maxID then
+ error("AcquireActionID: must setup pool first with SetActionIDPool")
+ end
+ local pool = idPools[poolID]
+ if not pool then
+ pool = { nWraps = 0, useCount = { } }
+ for i = 1, maxID do
+ pool.useCount[i] = 0
+ end
+ idPools[poolID] = pool
+ end
+ local useCount = pool.useCount
+ if id == nil then
+ repeat
+ local nWraps = pool.nWraps or 0
+ if hint and (useCount[hint] == nil or useCount[hint] == nWraps) then
+ id = hint
+ else
+ local start = hint or 1
+ for i = start, maxID do
+ if useCount[i] == nil or useCount[i] == nWraps then
+ id = i
+ break
+ end
+ end
+ if not id then
+ for i = 1, start do
+ if useCount[i] == nil or useCount[i] == nWraps then
+ id = i
+ break
+ end
+ end
+ end
+ end
+ if id == nil then
+ if unique then
+ return nil
+ end
+ pool.nWraps = nWraps + 1
+ end
+ until id ~= nil
+ end
+ useCount[id] = (useCount[id] or 0) + 1
+ return id
+end
+
+function Button:ReleaseActionID( id )
+ local poolID = self.actionPoolID
+ if not poolID then
+ error("ReleaseActionID: must setup pool first with SetActionIDPool")
+ end
+ local pool = idPools[poolID]
+ if pool and id and pool.useCount[id] then
+ pool.useCount[id] = pool.useCount[id] - 1
+ pool.nWraps = min(pool.useCount[id], pool.nWraps)
+ end
+end
+
+function Button:Refresh()
+ local f = self:GetFrame()
+ self.bar:PlaceButton( self, f:GetWidth(), f:GetHeight() )
+end
+
+function Button:SetKeybindMode( mode )
+ local f = self.frame
+ if mode then
+ self.oldOnEnter = f:GetScript("OnEnter")
+ f:SetScript("OnEnter", kb_onEnter)
+ elseif self.oldOnEnter then
+ f:SetScript("OnEnter", self.oldOnEnter)
+ self.oldOnEnter = nil
+ end
+ self:ShowGridTemp(mode)
+ self:UpdateKeybindModeDisplay( mode )
+end
+
+function Button:UpdateKeybindModeDisplay( mode )
+ local border = self.frames.border or _G[format("%sBorder",tostring(self:GetName()))]
+ if border then
+ if mode then
+ border:SetVertexColor(LKB:GetColorKeyBoundMode())
+ border:Show()
+ else
+ border:Hide()
+ end
+ end
+end
+
+function Button:UpdateHotkey( hotkey )
+ hotkey = hotkey or self.frames.hotkey
+ if not hotkey then
+ hotkey = _G[self:GetName().."HotKey"]
+ self.frames.hotkey = hotkey
+ end
+ if hotkey then
+ local txt = self.frame:GetHotkey()
+ hotkey:SetText( txt )
+ if txt == nil or txt == "" then
+ hotkey:Hide()
+ else
+ hotkey:Show()
+ end
+ end
+end
+
+function Button:GetActionIDLabel( create )
+ local f = self:GetFrame()
+ if not f.actionIDLabel and create then
+ local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
+ label:SetAllPoints()
+ label:SetJustifyH("CENTER")
+ label:SetShadowColor(0,0,0,1)
+ label:SetShadowOffset(2,-2)
+ f.actionIDLabel = label -- store the label with the frame for recycling
+ end
+ return f.actionIDLabel
+end
+
+function Button:UpdateActionIDLabel( show )
+ local label = self:GetActionIDLabel( show )
+ if label then
+ if show then
+ local id = self:GetActionID()
+ if id then
+ label:SetText(tostring(id))
+ label:Show()
+ return
+ end
+ end
+ label:Hide()
+ end
+end
+
+function Button:SetNormalVertexColor( r, g, b, a )
+ if ReAction.LBF then
+ ReAction.LBF:SetNormalVertexColor(self:GetFrame(), r, g, b, a)
+ else
+ self:GetFrame():GetNormalTexture():SetVertexColor(r,g,b,a)
+ end
+end
+
+function Button:GetNormalVertexColor()
+ if ReAction.LBF then
+ return ReAction.LBF:GetNormalVertexColor(self:GetFrame())
+ else
+ return self:GetFrame():GetNormalTexture():GetVertexColor()
+ end
+end
+
+function Button:UpdateShowGrid()
+ -- does nothing by default
+end
+
+function Button:ShowGridTemp(show)
+ -- does nothing by default
+end
+
+function Button:ShowGrid(show)
+ -- does nothing by default
+end
diff -r f255cd69e890 -r 65f2805957a0 MultiCastButton.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MultiCastButton.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,779 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local unpack = unpack
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local InCombatLockdown = InCombatLockdown
+local IsUsableSpell = IsUsableSpell
+local IsUsableAction = IsUsableAction
+local IsSpellKnown = IsSpellKnown
+local IsSpellInRange = IsSpellInRange
+local IsActionInRange = IsActionInRange
+local GetSpellInfo = GetSpellInfo
+local GetSpellCooldown = GetSpellCooldown
+local GetActionCooldown = GetActionCooldown
+local GetSpellTexture = GetSpellTexture
+local GetActionTexture = GetActionTexture
+local GetMultiCastTotemSpells = GetMultiCastTotemSpells
+
+--[[
+ Blizzard Constants:
+ - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4
+ - NUM_MULTI_CAST_PAGES = 3
+ - SHAMAN_TOTEM_PRIORITIES = { } -- sets the order of the totems
+ - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs
+ - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs
+
+ Blizzard Events:
+ - UPDATE_MULTI_CAST_ACTIONBAR
+
+ Blizzard APIs:
+ - GetMultiCastBarOffset() : returns 6
+
+ - SetMultiCastSpell(actionID, spellID) (protected) OR
+ SetAttribute("type","multispell")
+ SetAttribute("action",actionID)
+ SetAttribute("spell",spellID)
+
+ note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(),
+ so that's action ID 132-144.
+
+ - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot)
+ returns spellIDs for all known totems that fit that slot. This function is available in
+ the secure environment.
+
+ Blizzard textures:
+ All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single
+ texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose
+ this is to slightly optimize texture load performance, but it makes the UI code more clumsy.
+
+ Each totem button and arrow has a colored border indicating its elemental type.
+
+ TODO:
+ - make whether to show the colored border configurable (looks really bad with ButtonFacade:Zoomed)
+ - apply ButtonFacade to the flyout buttons? Or at least zoom the textures slightly?
+ - use a multiplier with SetTexCoord on totem bar texture?
+
+ Design Notes:
+ - Only the header has a secure context. All other frames execute in its context.
+
+ - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are
+ GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by
+ the summon flyout, which is also paged with the summon spells (the recall button is not paged)
+
+ - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new
+ spells) with the list of spells known for each slot.
+
+ - Each button (except recall) has an arrow button which appears on mouseover and when clicked
+ opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not
+ appear.
+
+ - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child
+ of the bar. Each time the flyout panel is opened, the individual buttons grab their corresponding
+ spell/type from the list, according to the slot which opened the flyout. Each button either sets
+ the current page (summon) or sets a multispell to an actionID via type="multispell". None of them
+ actually cast any spells (though, I suppose we could modify this so that e.g. configurable
+ right-click casts the spell). The flyout also has a close button which closes the flyout: the
+ flyout-open code positions the close button anchored to the last button in the flyout (which
+ changes dynamically because each slot has a different number of items in the list).
+
+ - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of
+ the summon spells is cast from elsewhere.
+
+ - The default UI has Call of the Elements always selected on UI load. This module remembers the last
+ selected one and restores it.
+
+
+]]--
+
+
+--
+-- Secure snippets
+--
+
+-- bar
+local _bar_init = -- function(self)
+[[
+ -- set up some globals in the secure environment
+ flyout = self:GetFrameRef("flyout")
+ flyoutSlot = nil
+ summonSlot = self:GetAttribute("summonSlot")
+ recallSlot = self:GetAttribute("recallSlot")
+ baseActionID = self:GetAttribute("baseActionID")
+ slotsPerPage = self:GetAttribute("slotsPerPage")
+ currentPage = currentPage or self:GetAttribute("lastSummon") or 1
+
+ totemIDsBySlot = newtable()
+ for i = 1, slotsPerPage do
+ totemIDsBySlot[i] = self:GetAttribute("TOTEM_PRIORITY_"..i)
+ end
+
+ -- these are set up in bar:SetupBar()
+ flyoutChildren = flyoutChildren or newtable()
+ summonSpells = summonSpells or newtable()
+]]
+
+local _onstate_multispellpage = -- function(self, stateid, newstate)
+[[
+ currentPage = tonumber(newstate)
+ control:CallMethod("UpdateLastSummon",currentPage)
+ control:ChildUpdate()
+]]
+
+
+-- buttons
+local _childupdate = -- function(self, snippetid, message)
+[[
+ local t = self:GetAttribute("type")
+ self:SetAttribute(t, self:GetAttribute(t.."-page"..currentPage))
+]]
+
+local _onEnter = -- function(self)
+ -- for whatever reason, RegisterAutoHide is unreliable
+ -- unless you re-anchor the frame prior to calling it.
+ -- Even then, it's still not terribly reliable.
+[[
+ local slot = self:GetAttribute("bar-idx")
+ local arrow = owner:GetFrameRef("arrow-"..slot)
+ if arrow and not arrow:IsShown() and not (flyout:IsVisible() and flyoutSlot == slot) then
+ arrow:ClearAllPoints()
+ arrow:SetPoint("BOTTOM",self,"TOP",0,0)
+ arrow:Show()
+ arrow:RegisterAutoHide(0)
+ arrow:AddToAutoHide(self)
+ end
+]]
+
+
+-- flyout arrow
+local _arrow_openFlyout = -- function(self)
+[[
+ local slot = self:GetAttribute("bar-idx")
+ local totemID = totemIDsBySlot[slot - (summonSlot or 0)]
+ if totemID == 0 then
+ totemID = "summon"
+ end
+
+ local lastButton, lastPage
+ for page, b in ipairs(flyoutChildren) do
+ b:Hide()
+ b:SetAttribute("totemSlot",totemID)
+ if slot == summonSlot then
+ local spellID = self:GetParent():GetAttribute("spell-page"..page)
+ if spellID then
+ b:SetAttribute("type","changePage")
+ b:SetAttribute("spell",spellID)
+ b:Show()
+ lastButton = b
+ lastPage = page
+ end
+ else
+ local spell = select(page, 0, GetMultiCastTotemSpells(totemID) )
+ if spell then
+ b:SetAttribute("type","multispell")
+ b:SetAttribute("action", baseActionID + (currentPage - 1)*slotsPerPage + totemID)
+ b:SetAttribute("spell", spell)
+ b:Show()
+ lastButton = b
+ lastPage = page
+ end
+ end
+ end
+
+ local close = owner:GetFrameRef("close")
+ if lastButton and close then
+ close:ClearAllPoints()
+ close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring
+ close:Show()
+ control:CallMethod("UpdateFlyoutTextures",totemID)
+ end
+
+ flyout:ClearAllPoints()
+ flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring
+ if lastPage then
+ flyout:SetHeight(lastPage * 27 + (close and close:GetHeight() or 0))
+ end
+ flyout:Show()
+ flyout:RegisterAutoHide(1) -- TODO: configurable
+ flyout:AddToAutoHide(owner)
+ flyoutSlot = slot
+ self:Hide()
+]]
+
+local _closeFlyout = -- function(self)
+[[
+ flyout:Hide()
+]]
+
+
+-- flyout child buttons
+local _flyout_child_preClick = -- function(self, button, down)
+[[
+ local button = button
+ if self:GetAttribute("type") == "changePage" then
+ owner:SetAttribute("state-multispellpage",self:GetAttribute("index"))
+ self:GetParent():Hide()
+ return false
+ else
+ return nil, "close"
+ end
+]]
+
+local _flyout_child_postClick = -- function(self, message, button, down)
+[[
+ if message == "close" then
+ self:GetParent():Hide() -- hide flyout after selecting
+ end
+]]
+
+
+--
+-- The Blizzard totem bar textures are all actually one big texture,
+-- with texcoord offsets. Shamelessly stolen from FrameXML/MultiCastActionBarFrame.lua
+--
+local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar"
+local FLYOUT_UP_BUTTON_HL_TCOORDS = { 72/128, 92/128, 88/256, 98/256 }
+local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128, 92/128, 69/256, 79/256 }
+
+local SLOT_EMPTY_TCOORDS = {
+ [EARTH_TOTEM_SLOT] = { 66/128, 96/128, 3/256, 33/256 },
+ [FIRE_TOTEM_SLOT] = { 67/128, 97/128, 100/256, 130/256 },
+ [WATER_TOTEM_SLOT] = { 39/128, 69/128, 209/256, 239/256 },
+ [AIR_TOTEM_SLOT] = { 66/128, 96/128, 36/256, 66/256 },
+}
+
+local SLOT_OVERLAY_TCOORDS = {
+ [EARTH_TOTEM_SLOT] = { 1/128, 35/128, 172/256, 206/256 },
+ [FIRE_TOTEM_SLOT] = { 36/128, 70/128, 172/256, 206/256 },
+ [WATER_TOTEM_SLOT] = { 1/128, 35/128, 207/256, 240/256 },
+ [AIR_TOTEM_SLOT] = { 36/128, 70/128, 137/256, 171/256 },
+}
+
+local FLYOUT_UP_BUTTON_TCOORDS = {
+ ["summon"] = { 99/128, 127/128, 84/256, 102/256 },
+ [EARTH_TOTEM_SLOT] = { 99/128, 127/128, 160/256, 178/256 },
+ [FIRE_TOTEM_SLOT] = { 99/128, 127/128, 122/256, 140/256 },
+ [WATER_TOTEM_SLOT] = { 99/128, 127/128, 199/256, 217/256 },
+ [AIR_TOTEM_SLOT] = { 99/128, 127/128, 237/256, 255/256 },
+}
+
+local FLYOUT_DOWN_BUTTON_TCOORDS = {
+ ["summon"] = { 99/128, 127/128, 65/256, 83/256 },
+ [EARTH_TOTEM_SLOT] = { 99/128, 127/128, 141/256, 159/256 },
+ [FIRE_TOTEM_SLOT] = { 99/128, 127/128, 103/256, 121/256 },
+ [WATER_TOTEM_SLOT] = { 99/128, 127/128, 180/256, 198/256 },
+ [AIR_TOTEM_SLOT] = { 99/128, 127/128, 218/256, 236/256 },
+}
+
+local FLYOUT_TOP_TCOORDS = {
+ ["summon"] = { 33/128, 65/128, 1/256, 23/256 },
+ [EARTH_TOTEM_SLOT] = { 0/128, 32/128, 46/256, 68/256 },
+ [FIRE_TOTEM_SLOT] = { 33/128, 65/128, 46/256, 68/256 },
+ [WATER_TOTEM_SLOT] = { 0/128, 32/128, 1/256, 23/256 },
+ [AIR_TOTEM_SLOT] = { 0/128, 32/128, 91/256, 113/256 },
+}
+
+local FLYOUT_MIDDLE_TCOORDS = {
+ ["summon"] = { 33/128, 65/128, 23/256, 43/256 },
+ [EARTH_TOTEM_SLOT] = { 0/128, 32/128, 68/256, 88/256 },
+ [FIRE_TOTEM_SLOT] = { 33/128, 65/128, 68/256, 88/256 },
+ [WATER_TOTEM_SLOT] = { 0/128, 32/128, 23/256, 43/256 },
+ [AIR_TOTEM_SLOT] = { 0/128, 32/128, 113/256, 133/256 },
+}
+
+local eventList = {
+ "ACTIONBAR_SLOT_CHANGED",
+ "ACTIONBAR_UPDATE_STATE",
+ "ACTIONBAR_UPDATE_USABLE",
+ "ACTIONBAR_UPDATE_COOLDOWN",
+ "UPDATE_BINDINGS",
+ "UPDATE_MULTI_CAST_ACTIONBAR",
+}
+
+--
+-- MultiCast Button class
+-- Inherits implementation methods from Action button class, but circumvents the constructor
+-- and redefines/removes some methods.
+--
+local buttonTypeID = "Totem"
+local Super = ReAction.Button
+local Action = ReAction.Button.Action
+local MultiCast = setmetatable(
+ {
+ defaultBarConfig = {
+ type = buttonTypeID,
+ btnWidth = 36,
+ btnHeight = 36,
+ btnRows = 1,
+ btnColumns = 6,
+ spacing = 3,
+ buttons = { }
+ },
+
+ barType = L["Totem Bar"],
+ buttonTypeID = buttonTypeID
+ },
+ { __index = Action } )
+
+ReAction.Button.MultiCast = MultiCast
+ReAction:RegisterBarType(MultiCast)
+
+function MultiCast:New( btnConfig, bar, idx )
+ local maxIndex = bar.nTotemSlots or 0
+ if bar.summonSlot then
+ maxIndex = maxIndex + 1
+ end
+ if bar.recallSlot then
+ maxIndex = maxIndex + 1
+ end
+
+ if not bar.hasMulticast or idx > maxIndex then
+ return false
+ end
+
+ if idx < 1 then
+ error("invalid index")
+ end
+
+ local name = format("ReAction_%s_Totem_%d",bar:GetName(),idx)
+
+ self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+
+ local barFrame = bar:GetFrame()
+ local f = self:GetFrame()
+
+ -- attributes
+ local page = (idx == bar.recallSlot) and 1 or bar:GetConfig().lastSummon or 1
+ if idx == bar.recallSlot or idx == bar.summonSlot then
+ f:SetAttribute("type","spell")
+ local spells = (idx == bar.summonSlot) and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS
+ f:SetAttribute("spell",spells[page])
+ for i, spell in ipairs(spells) do
+ if spell and IsSpellKnown(spell) then
+ f:SetAttribute("spell-page"..i, spell)
+ end
+ end
+ else
+ local offset = bar.summonSlot and 1 or 0
+ local slot = SHAMAN_TOTEM_PRIORITIES[idx - offset]
+ local baseAction = barFrame:GetAttribute("baseActionID") + slot
+ self.totemSlot = slot
+ f:SetAttribute("type","action")
+ f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
+ for i = 1, NUM_MULTI_CAST_PAGES do
+ f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
+ end
+ if not f.overlayTex then
+ local tx = f:CreateTexture("OVERLAY")
+ tx:SetTexture(TOTEM_TEXTURE)
+ tx:SetTexCoord(unpack(SLOT_OVERLAY_TCOORDS[self.totemSlot]))
+ tx:SetWidth(34)
+ tx:SetHeight(34)
+ tx:SetPoint("CENTER")
+ tx:Show()
+ f.overlayTex = tx
+ end
+ end
+ f:SetAttribute("bar-idx",idx)
+
+ -- non secure scripts
+ f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+ f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+ f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+ f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
+ f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
+
+ -- secure handlers
+ if idx ~= bar.recallSlot then
+ f:SetAttribute("_childupdate",_childupdate)
+ end
+ barFrame:WrapScript(f, "OnEnter", _onEnter)
+
+ -- event registration
+ f:EnableMouse(true)
+ f:RegisterForClicks("AnyUp")
+ for _, evt in pairs(eventList) do
+ f:RegisterEvent(evt)
+ end
+
+ -- Set up a proxy for the icon texture for use with ButtonFacade
+ local SetTexCoordRaw = self.frames.icon.SetTexCoord
+ self.frames.icon.SetTexCoord = function( tx, ... )
+ if self:GetIconTexture() == TOTEM_TEXTURE then
+ SetTexCoordRaw(tx,select(2,self:GetIconTexture()))
+ else
+ SetTexCoordRaw(tx,...)
+ end
+ end
+
+ -- attach to skinner
+ bar:SkinButton(self)
+
+ f:Show()
+
+ -- open arrow and flyout background textures
+ if idx ~= bar.recallSlot then
+ local arrow = f._arrowFrame or CreateFrame("Button", nil, f, "SecureFrameTemplate")
+ f._arrowFrame = arrow
+ arrow:SetWidth(28)
+ arrow:SetHeight(18)
+ arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring
+ arrow:SetNormalTexture(TOTEM_TEXTURE)
+ local slot = self.totemSlot or "summon"
+ arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS[slot]) )
+ arrow:SetHighlightTexture(TOTEM_TEXTURE)
+ arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) )
+ arrow:SetAttribute("bar-idx",idx)
+ arrow:Hide()
+ barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout)
+ barFrame:SetFrameRef("arrow-"..idx,arrow)
+ end
+
+ self:Refresh()
+
+ return self
+end
+
+function MultiCast:Destroy()
+ local barFrame = self.bar:GetFrame()
+ local f = self:GetFrame()
+ pcall( barFrame.UnwrapScript, barFrame, f, "OnEnter" ) -- ignore errors
+ if f._arrowFrame then
+ pcall( barFrame.UnwrapScript, barFrame, f._arrowFrame,"OnClick" ) -- ignore errors
+ end
+ Super.Destroy(self)
+end
+
+function MultiCast:Refresh()
+ Super.Refresh(self)
+ self:UpdateAction()
+end
+
+function MultiCast:ShowGrid( show )
+end
+
+function MultiCast:ShowGridTemp( show )
+end
+
+function MultiCast:AcquireActionID()
+end
+
+function MultiCast:ReleaseActionID()
+end
+
+function MultiCast:UpdateShowGrid()
+end
+
+function MultiCast:UpdateBorder()
+end
+
+function MultiCast:UpdateMacroText()
+end
+
+function MultiCast:UpdateCount()
+end
+
+function MultiCast:UpdateCheckedState()
+ local action = self:GetActionID()
+ if action and IsCurrentAction(action) then
+ self:GetFrame():SetChecked(1)
+ else
+ self:GetFrame():SetChecked(0)
+ end
+end
+
+function MultiCast:RefreshHasActionAttributes()
+end
+
+function MultiCast:UpdateFlash()
+end
+
+function MultiCast:GetIconTexture()
+ local tx
+ if self.spellID then
+ tx = GetSpellTexture(GetSpellInfo(self.spellID))
+ elseif self.actionID then
+ tx = GetActionTexture(self.actionID)
+ end
+ if tx then
+ return tx
+ else
+ return TOTEM_TEXTURE, unpack(SLOT_EMPTY_TCOORDS[self.totemSlot or 1])
+ end
+end
+
+function MultiCast:UpdateAction()
+ local action = self:GetActionID()
+ if action then
+ if action ~= self.actionID then
+ self.actionID = action
+ self:UpdateAll()
+ end
+ else
+ local spellID = self:GetSpellID()
+ if spellID ~= self.spellID then
+ self.spellID = spellID
+ self:UpdateAll()
+ end
+ end
+end
+
+function MultiCast:GetActionID(page)
+ return self:GetFrame():GetAttribute("action")
+end
+
+function MultiCast:GetSpellID(page)
+ return self:GetFrame():GetAttribute("spell")
+end
+
+function MultiCast:SetActionID( id )
+ error("Can not set action ID of multicast buttons")
+end
+
+function MultiCast:SetTooltip()
+ local barFrame = self:GetFrame()
+ if GetCVar("UberTooltips") == "1" then
+ GameTooltip_SetDefaultAnchor(GameTooltip, barFrame)
+ else
+ GameTooltip:SetOwner(barFrame)
+ end
+ if self.spellID then
+ GameTooltip:SetSpellByID(self.spellID,false,true)
+ elseif self.actionID then
+ GameTooltip:SetAction(self.actionID)
+ end
+end
+
+function MultiCast:GetUsable()
+ if self.spellID then
+ return IsUsableSpell((GetSpellInfo(self.spellID)))
+ elseif self.actionID then
+ return IsUsableAction(self.actionID)
+ end
+end
+
+function MultiCast:GetInRange()
+ if self.spellID then
+ return IsSpellInRange((GetSpellInfo(self.spellID))) == 0
+ elseif self.actionID then
+ return IsActionInRange(self.actionID) == 0
+ end
+end
+
+function MultiCast:GetCooldown()
+ if self.spellID then
+ return GetSpellCooldown((GetSpellInfo(self.spellID)))
+ elseif self.actionID then
+ return GetActionCooldown(self.actionID)
+ else
+ return 0, 0, 0
+ end
+end
+
+function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR()
+ self:UpdateAll()
+end
+
+
+--
+-- flyout setup
+--
+local function ShowFlyoutTooltip(frame)
+ if GetCVar("UberTooltips") == "1" then
+ GameTooltip_SetDefaultAnchor(GameTooltip, frame)
+ else
+ GameTooltip:SetOwner(frame)
+ end
+ local spell = frame:GetAttribute("spell")
+ if spell == nil or spell == 0 then
+ GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
+ else
+ GameTooltip:SetSpellByID(spell,false,true)
+ end
+end
+
+local function HideFlyoutTooltip()
+ GameTooltip:Hide()
+end
+
+local function UpdateFlyoutIcon(frame)
+ local spellID = frame:GetAttribute("spell")
+ if spellID == 0 or spellID == nil then
+ frame.icon:SetTexture(TOTEM_TEXTURE)
+ local slot = tonumber(frame:GetAttribute("totemSlot")) or 1
+ frame.icon:SetTexCoord( unpack(SLOT_EMPTY_TCOORDS[slot]) )
+ else
+ frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID)))
+ frame.icon:SetTexCoord(0,1,0,1)
+ end
+end
+
+function MultiCast:SetupBar( bar )
+ Super.SetupBar(self,bar)
+
+ local slot = 0
+ local nTotemSlots = 0
+ local summonSlot = nil
+ local recallSlot = nil
+
+ -- figure out the capabilities of the character
+ for i, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do
+ if spell and IsSpellKnown(spell) then
+ slot = 1
+ summonSlot = 1
+ end
+ end
+
+ for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do
+ local totem = SHAMAN_TOTEM_PRIORITIES[i];
+ if GetTotemInfo(totem) and GetMultiCastTotemSpells(totem) then
+ nTotemSlots = nTotemSlots + 1
+ slot = slot + 1
+ end
+ end
+
+ slot = slot + 1
+ for i, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do
+ if spell and IsSpellKnown(spell) then
+ recallSlot = slot
+ end
+ end
+
+ if nTotemSlots == 0 then
+ bar.hasMulticast = false -- no multicast capability
+ return
+ end
+
+ bar.hasMulticast = true
+ bar.summonSlot = summonSlot
+ bar.recallSlot = recallSlot
+ bar.nTotemSlots = nTotemSlots
+
+
+ local f = bar:GetFrame()
+
+ -- init bar secure environment
+ f:SetAttribute("lastSummon", bar:GetConfig().lastSummon)
+ f:SetAttribute("summonSlot", summonSlot)
+ f:SetAttribute("recallSlot", recallSlot)
+ f:SetAttribute("slotsPerPage", NUM_MULTI_CAST_BUTTONS_PER_PAGE)
+ f:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS)
+ for i, p in ipairs(SHAMAN_TOTEM_PRIORITIES) do
+ f:SetAttribute("TOTEM_PRIORITY_"..i,p)
+ end
+ f:SetAttribute("_onstate-multispellpage", _onstate_multispellpage)
+
+ function f:UpdateLastSummon(value)
+ bar:GetConfig().lastSummon = value
+ end
+
+ -- create flyout container frame and close arrow
+ local flyout = bar._flyoutFrame
+ if not flyout then
+ flyout = CreateFrame("Frame", nil, f, "SecureFrameTemplate")
+ bar._flyoutFrame = flyout
+ f:SetFrameRef("flyout",flyout)
+ flyout.buttons = { }
+ flyout:Hide()
+ flyout:SetWidth(24)
+ flyout:SetHeight(1)
+ flyout:SetPoint("BOTTOM",f,"TOP",0,0)
+
+ local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate")
+ close:SetWidth(28)
+ close:SetHeight(18)
+ close:SetPoint("BOTTOM",flyout,"TOP")
+ close:SetNormalTexture(TOTEM_TEXTURE)
+ close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS["summon"]))
+ close:SetHighlightTexture(TOTEM_TEXTURE)
+ close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) )
+ f:SetFrameRef("close",close)
+ f:WrapScript(close, "OnClick", _closeFlyout)
+ close:Show()
+
+ local midTx = flyout:CreateTexture("BACKGROUND")
+ midTx:SetWidth(32)
+ midTx:SetHeight(20)
+ midTx:SetPoint("BOTTOM")
+ midTx:SetTexture(TOTEM_TEXTURE)
+ midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS["summon"]))
+ midTx:Show()
+
+ local topTx = flyout:CreateTexture("BACKGROUND")
+ topTx:SetWidth(32)
+ topTx:SetHeight(20)
+ topTx:SetTexture(TOTEM_TEXTURE)
+ midTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS["summon"]))
+ topTx:SetPoint("BOTTOM",midTx,"TOP",0,-10)
+ topTx:Show()
+
+ function flyout:UpdateTextures(slot)
+ slot = slot or "summon"
+ close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS[slot]))
+ midTx:ClearAllPoints()
+ midTx:SetPoint("BOTTOM")
+ midTx:SetPoint("TOP",close,"BOTTOM",0,0)
+ midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS[slot]))
+ topTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS[slot]))
+ end
+
+ -- create flyout buttons
+ for i = 1, 10 do -- maximum 9 spells + 1 empty slot
+ local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate")
+ b:SetWidth(24)
+ b:SetHeight(24)
+ local prev = flyout.buttons[i-1]
+ b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring
+ b.icon = b:CreateTexture("BACKGROUND")
+ b.icon:SetAllPoints()
+ b.icon:Show()
+ b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
+ b:GetHighlightTexture():SetBlendMode("ADD")
+ b:RegisterForClicks("AnyUp")
+ b:SetScript("OnShow",UpdateFlyoutIcon)
+ b:SetScript("OnEnter",ShowFlyoutTooltip)
+ b:SetScript("OnLeave",HideFlyoutTooltip)
+ b:SetAttribute("index",i)
+ f:SetAttribute("flyout-child-idx",i)
+ f:SetFrameRef("flyout-child",b)
+ f:Execute([[
+ flyoutChildren = flyoutChildren or newtable()
+ flyoutChildren[self:GetAttribute("flyout-child-idx")] = self:GetFrameRef("flyout-child")
+ ]])
+ f:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick)
+ b:Show()
+ flyout.buttons[i] = b
+ end
+ end
+
+ -- scale flyout frame
+ local scale = bar:GetButtonSize() / 36
+ flyout:SetScale(scale)
+
+ function f:UpdateFlyoutTextures(slot)
+ flyout:UpdateTextures(slot)
+ end
+
+ -- re-execute setup when new spells are loaded
+ if not f.events_registered then
+ f:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR")
+ f:RegisterEvent("PLAYER_ENTERING_WORLD")
+ -- Bar.frame does not use OnEvent
+ f:SetScript("OnEvent",
+ function()
+ if not InCombatLockdown() then
+ self:SetupBar(bar)
+ end
+ end)
+ f.events_registered = true
+ end
+
+
+ f:Execute(_bar_init)
+end
+
diff -r f255cd69e890 -r 65f2805957a0 Overlay.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Overlay.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,754 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local LKB = ReAction.LKB
+local CreateFrame = CreateFrame
+local InCombatLockdown = InCombatLockdown
+local floor = math.floor
+local min = math.min
+local format = string.format
+local GameTooltip = GameTooltip
+local Bar = ReAction.Bar
+local GetSize = Bar.GetSize
+local SetSize = Bar.SetSize
+local GetButtonSize = Bar.GetButtonSize
+local GetButtonGrid = Bar.GetButtonGrid
+local SetButtonSize = Bar.SetButtonSize
+local SetButtonGrid = Bar.SetButtonGrid
+local ApplyAnchor = Bar.ApplyAnchor
+local GameTooltipTextRight1 = GameTooltipTextRight1
+local GameTooltipTextRight2 = GameTooltipTextRight2
+local GameTooltipTextRight3 = GameTooltipTextRight3
+
+--
+-- Wrap some of the bar manipulators to make them state-aware
+--
+local function SetAnchor( bar, point, frame, relPoint, x, y )
+ local state = bar:GetSecureState()
+ if state then
+ local anchorstate = bar:GetStateProperty(state, "anchorEnable")
+ if anchorstate then
+ bar:SetStateProperty(state, "anchorFrame", frame)
+ bar:SetStateProperty(state, "anchorPoint", point)
+ bar:SetStateProperty(state, "anchorRelPoint", relPoint)
+ bar:SetStateProperty(state, "anchorX", x or 0)
+ bar:SetStateProperty(state, "anchorY", y or 0)
+ bar:SetAnchor(bar:GetAnchor())
+ return
+ end
+ end
+ bar:SetAnchor(point, frame, relPoint, x, y)
+end
+
+local function GetStateScale( bar )
+ local state = bar:GetSecureState()
+ if state and bar:GetStateProperty(state, "enableScale") then
+ return bar:GetStateProperty(state, "scale")
+ end
+end
+
+local function SetStateScale( bar, scale )
+ local state = bar:GetSecureState()
+ if state and bar:GetStateProperty(state, "enableScale") then
+ bar:SetStateProperty(state, "scale", scale)
+ end
+end
+
+
+--
+-- Bar config overlay
+--
+
+local function GetNormalTextColor()
+ return 1.0, 1.0, 1.0, 1.0
+end
+
+local function GetAnchoredTextColor()
+ return 1.0, 1.0, 1.0, 1.0
+end
+
+local function GetNormalBgColor()
+ return 0.7, 0.7, 1.0, 0.3
+end
+
+local function GetAnchoredBgColor()
+ return 0.9, 0.2, 0.7, 0.3
+end
+
+local function StoreSize(bar)
+ local f = bar:GetFrame()
+ SetSize( bar, f:GetWidth(), f:GetHeight() )
+end
+
+local function StoreExtents(bar)
+ local f = bar:GetFrame()
+ local p, fr, rp, x, y = f:GetPoint(1)
+ fr = fr and fr:GetName() or "UIParent"
+ SetAnchor( bar, p, fr, rp, x, y )
+ SetSize( bar, f:GetWidth(), f:GetHeight() )
+end
+
+local function RecomputeButtonSize(bar)
+ local w, h = GetSize(bar)
+ local bw, bh = GetButtonSize(bar)
+ local r, c, s = GetButtonGrid(bar)
+
+ local scaleW = (floor(w/c) - s) / bw
+ local scaleH = (floor(h/r) - s) / bh
+ local scale = min(scaleW, scaleH)
+
+ SetButtonSize(bar, scale * bw, scale * bh, s)
+end
+
+local function ComputeBarScale(bar, overlay)
+ local w, h = overlay:GetWidth() - 8, overlay:GetHeight() - 8
+ local bw, bh = GetButtonSize(bar)
+ local r, c, s = GetButtonGrid(bar)
+
+ local scaleW = w / (c*(bw+s))
+ local scaleH = h / (r*(bh+s))
+ local scale = min(scaleW, scaleH)
+
+ if scale > 2.5 then
+ scale = 2.5
+ elseif scale < 0.25 then
+ scale = 0.25
+ end
+
+ return scale
+end
+
+local function RecomputeButtonSpacing(bar)
+ local w, h = GetSize(bar)
+ local bw, bh = GetButtonSize(bar)
+ local r, c, s = GetButtonGrid(bar)
+
+ SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh))
+end
+
+local function RecomputeGrid(bar)
+ local w, h = GetSize(bar)
+ local bw, bh = GetButtonSize(bar)
+ local r, c, s = GetButtonGrid(bar)
+
+ SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s)
+end
+
+local function ClampToButtons(bar)
+ local bw, bh = GetButtonSize(bar)
+ local r, c, s = GetButtonGrid(bar)
+ SetSize(bar, (bw+s)*c + 1, (bh+s)*r + 1)
+end
+
+local function HideGameTooltip()
+ GameTooltip:Hide()
+end
+
+local anchorInside = { inside = true }
+local anchorOutside = { outside = true }
+local edges = { "BOTTOM", "TOP", "LEFT", "RIGHT" }
+local oppositeEdges = {
+ TOP = "BOTTOM",
+ BOTTOM = "TOP",
+ LEFT = "RIGHT",
+ RIGHT = "LEFT"
+}
+local pointsOnEdge = {
+ BOTTOM = { "BOTTOM", "BOTTOMLEFT", "BOTTOMRIGHT", },
+ TOP = { "TOP", "TOPLEFT", "TOPRIGHT", },
+ RIGHT = { "RIGHT", "BOTTOMRIGHT", "TOPRIGHT", },
+ LEFT = { "LEFT", "BOTTOMLEFT", "TOPLEFT", },
+}
+local edgeSelector = {
+ BOTTOM = 1, -- select x of x,y
+ TOP = 1, -- select x of x,y
+ LEFT = 2, -- select y of x,y
+ RIGHT = 2, -- select y of x,y
+}
+local snapPoints = {
+ [anchorOutside] = {
+ BOTTOMLEFT = {"BOTTOMRIGHT","TOPLEFT","TOPRIGHT"},
+ BOTTOM = {"TOP"},
+ BOTTOMRIGHT = {"BOTTOMLEFT","TOPRIGHT","TOPLEFT"},
+ RIGHT = {"LEFT"},
+ TOPRIGHT = {"TOPLEFT","BOTTOMRIGHT","BOTTOMLEFT"},
+ TOP = {"BOTTOM"},
+ TOPLEFT = {"TOPRIGHT","BOTTOMLEFT","BOTTOMRIGHT"},
+ LEFT = {"RIGHT"},
+ CENTER = {"CENTER"}
+ },
+ [anchorInside] = {
+ BOTTOMLEFT = {"BOTTOMLEFT"},
+ BOTTOM = {"BOTTOM"},
+ BOTTOMRIGHT = {"BOTTOMRIGHT"},
+ RIGHT = {"RIGHT"},
+ TOPRIGHT = {"TOPRIGHT"},
+ TOP = {"TOP"},
+ TOPLEFT = {"TOPLEFT"},
+ LEFT = {"LEFT"},
+ CENTER = {"CENTER"}
+ }
+}
+local insidePointOffsetFuncs = {
+ BOTTOMLEFT = function(x, y) return x, y end,
+ BOTTOM = function(x, y) return 0, y end,
+ BOTTOMRIGHT = function(x, y) return -x, y end,
+ RIGHT = function(x, y) return -x, 0 end,
+ TOPRIGHT = function(x, y) return -x, -y end,
+ TOP = function(x, y) return 0, -y end,
+ TOPLEFT = function(x, y) return x, -y end,
+ LEFT = function(x, y) return x, 0 end,
+ CENTER = function(x, y) return x, y end,
+}
+local pointCoordFuncs = {
+ BOTTOMLEFT = function(f) return f:GetLeft(), f:GetBottom() end,
+ BOTTOM = function(f) return nil, f:GetBottom() end,
+ BOTTOMRIGHT = function(f) return f:GetRight(), f:GetBottom() end,
+ RIGHT = function(f) return f:GetRight(), nil end,
+ TOPRIGHT = function(f) return f:GetRight(), f:GetTop() end,
+ TOP = function(f) return nil, f:GetTop() end,
+ TOPLEFT = function(f) return f:GetLeft(), f:GetTop() end,
+ LEFT = function(f) return f:GetLeft(), nil end,
+ CENTER = function(f) return f:GetCenter() end,
+}
+local edgeBoundsFuncs = {
+ BOTTOM = function(f) return f:GetLeft(), f:GetRight() end,
+ LEFT = function(f) return f:GetBottom(), f:GetTop() end
+}
+edgeBoundsFuncs.TOP = edgeBoundsFuncs.BOTTOM
+edgeBoundsFuncs.RIGHT = edgeBoundsFuncs.LEFT
+local cornerTexCoords = {
+ -- ULx, ULy, LLx, LLy, URx, URy, LRx, LRy
+ TOPLEFT = { 1, 1, 1, 0, 0, 1, 0, 0 },
+ TOPRIGHT = { 1, 0, 0, 0, 1, 1, 0, 1 },
+ BOTTOMLEFT = { 0, 1, 1, 1, 0, 0, 1, 0 },
+ BOTTOMRIGHT = { 0, 0, 0, 1, 1, 0, 1, 1 },
+}
+
+-- Returns absolute coordinates x,y of the named point 'p' of frame 'f'
+local function GetPointCoords( f, p )
+ local x, y = pointCoordFuncs[p](f)
+ if not(x and y) then
+ local cx, cy = f:GetCenter()
+ x = x or cx
+ y = y or cy
+ end
+ return x, y
+end
+
+
+-- Returns true if frame 'f1' can be anchored to frame 'f2'
+local function CheckAnchorable( f1, f2 )
+ -- can't anchor a frame to itself or to nil
+ if f1 == f2 or f2 == nil then
+ return false
+ end
+
+ -- can always anchor to UIParent
+ if f2 == UIParent then
+ return true
+ end
+
+ -- also can't do circular anchoring of frames
+ -- walk the anchor chain, which generally shouldn't be that expensive
+ -- (who nests draggables that deep anyway?)
+ for i = 1, f2:GetNumPoints() do
+ local _, f = f2:GetPoint(i)
+ if not f then f = f2:GetParent() end
+ return CheckAnchorable(f1,f)
+ end
+
+ return true
+end
+
+-- Returns true if frames f1 and f2 specified edges overlap
+local function CheckEdgeOverlap( f1, f2, e )
+ local l1, u1 = edgeBoundsFuncs[e](f1)
+ local l2, u2 = edgeBoundsFuncs[e](f2)
+ return l1 <= l2 and l2 <= u1 or l2 <= l1 and l1 <= u2
+end
+
+-- Returns true if point p1 on frame f1 overlaps edge e2 on frame f2
+local function CheckPointEdgeOverlap( f1, p1, f2, e2 )
+ local l, u = edgeBoundsFuncs[e2](f2)
+ local x, y = GetPointCoords(f1,p1)
+ x = select(edgeSelector[e2], x, y)
+ return l <= x and x <= u
+end
+
+-- Returns the distance between corresponding edges. It is
+-- assumed that the passed in edges e1 and e2 are the same or opposites
+local function GetEdgeDistance( f1, f2, e1, e2 )
+ local x1, y1 = pointCoordFuncs[e1](f1)
+ local x2, y2 = pointCoordFuncs[e2](f2)
+ return math.abs((x1 or y1) - (x2 or y2))
+end
+
+local globalSnapTargets = { [UIParent] = anchorInside }
+
+local function GetClosestFrameEdge(f1,f2,a)
+ local dist, edge, opp
+ if f2:IsVisible() and CheckAnchorable(f1,f2) then
+ for _, e in pairs(edges) do
+ local o = a.inside and e or oppositeEdges[e]
+ if CheckEdgeOverlap(f1,f2,e) then
+ local d = GetEdgeDistance(f1, f2, e, o)
+ if not dist or (d < dist) then
+ dist, edge, opp = d, e, o
+ end
+ end
+ end
+ end
+ return dist, edge, opp
+end
+
+local function GetClosestVisibleEdge( f )
+ local r, o, e1, e2
+ local a = anchorOutside
+ for _, b in ReAction:IterateBars() do
+ local d, e, opp = GetClosestFrameEdge(f,b:GetFrame(),a)
+ if d and (not r or d < r) then
+ r, o, e1, e2 = d, b:GetFrame(), e, opp
+ end
+ end
+ for f2, a2 in pairs(globalSnapTargets) do
+ local d, e, opp = GetClosestFrameEdge(f,f2,a2)
+ if d and (not r or d < r) then
+ r, o, e1, e2, a = d, f2, e, opp, a2
+ end
+ end
+ return o, e1, e2, a
+end
+
+local function GetClosestVisiblePoint(f1)
+ local f2, e1, e2, a = GetClosestVisibleEdge(f1)
+ if f2 then
+ local rsq, p, rp, x, y
+ -- iterate pointsOnEdge in order and use < to prefer edge centers to corners
+ for _, p1 in ipairs(pointsOnEdge[e1]) do
+ if CheckPointEdgeOverlap(f1,p1,f2,e2) then
+ for _, p2 in pairs(snapPoints[a][p1]) do
+ local x1, y1 = GetPointCoords(f1,p1)
+ local x2, y2 = GetPointCoords(f2,p2)
+ local dx = x1 - x2
+ local dy = y1 - y2
+ local rsq2 = dx*dx + dy*dy
+ if not rsq or rsq2 < rsq then
+ rsq, p, rp, x, y = rsq2, p1, p2, dx, dy
+ end
+ end
+ end
+ end
+ return f2, p, rp, x, y
+ end
+end
+
+local function GetClosestPointSnapped(f1, rx, ry, xOff, yOff)
+ local o, p, rp, x, y = GetClosestVisiblePoint(f1)
+ local s = false
+
+ local insideOffsetFunc = p and insidePointOffsetFuncs[p]
+ local coordFunc = p and pointCoordFuncs[p]
+ if not insideOffsetFunc or not coordFunc then
+ return
+ end
+
+ local sx, sy = insideOffsetFunc(xOff or 0, yOff or 0)
+ local xx, yy = coordFunc(f1)
+ if xx and yy then
+ if math.abs(x) <= rx then
+ if math.abs(y) <= ry then
+ x = sx
+ y = sy
+ s = true
+ elseif CheckEdgeOverlap(f1,o,"LEFT") then
+ x = sx
+ s = true
+ end
+ elseif math.abs(y) <= ry and CheckEdgeOverlap(f1,o,"TOP") then
+ y = sy
+ s = true
+ end
+ elseif xx then
+ if math.abs(x) <= rx then
+ x = sx
+ s = true
+ if math.abs(y) <= ry then
+ y = sy
+ end
+ end
+ elseif yy then
+ if math.abs(y) <= ry then
+ y = sy
+ s = true
+ if math.abs(x) <= rx then
+ x = sx
+ end
+ end
+ end
+
+ -- correct for some Lua oddities with doubles
+ if x == -0 then x = 0 end
+ if y == -0 then y = 0 end
+
+ if s then
+ return o, p, rp, math.floor(x), math.floor(y)
+ end
+end
+
+local function CreateSnapIndicator()
+ local si = CreateFrame("Frame",nil,UIParent)
+ si:SetFrameStrata("HIGH")
+ si:SetHeight(16)
+ si:SetWidth(16)
+ local tex = si:CreateTexture()
+ tex:SetAllPoints()
+ tex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
+ tex:SetBlendMode("ADD")
+ tex:SetDrawLayer("OVERLAY")
+ return si
+end
+
+local si1 = CreateSnapIndicator()
+local si2 = CreateSnapIndicator()
+
+local function DisplaySnapIndicator( f, rx, ry, xOff, yOff )
+ local o, p, rp, x, y, snap = GetClosestPointSnapped(f, rx, ry, xOff, yOff)
+ if o then
+ si1:ClearAllPoints()
+ si2:ClearAllPoints()
+ si1:SetPoint("CENTER", f, p, 0, 0)
+ local xx, yy = pointCoordFuncs[rp](o)
+ x = math.abs(x) <=rx and xx and 0 or x
+ y = math.abs(y) <=ry and yy and 0 or y
+ si2:SetPoint("CENTER", o, rp, x, y)
+ si1:Show()
+ si2:Show()
+ else
+ if si1:IsVisible() then
+ si1:Hide()
+ si2:Hide()
+ end
+ end
+ return o, p
+end
+
+local function HideSnapIndicator()
+ if si1:IsVisible() then
+ si1:Hide()
+ si2:Hide()
+ end
+end
+
+local function UpdateLabelString(overlay)
+ local label = overlay.labelString
+ if label then
+ local name = overlay.labelName
+ if name and overlay.labelSubtext then
+ name = format("%s (%s)", name, overlay.labelSubtext)
+ end
+ label:SetText(name or "")
+ end
+end
+
+local function CreateControls(bar)
+ local f = bar:GetFrame()
+
+ f:SetMovable(true)
+ f:SetResizable(true)
+
+ -- child of UIParent so that alpha and scale doesn't propagate to it
+ local overlay = CreateFrame("Button", nil, UIParent)
+ overlay:EnableMouse(true)
+ overlay:SetFrameLevel(10) -- set it above the buttons
+ overlay:SetPoint("TOPLEFT", f, "TOPLEFT", -4, 4)
+ overlay:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 4, -4)
+ overlay:SetBackdrop({
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true,
+ tileSize = 16,
+ edgeSize = 16,
+ insets = { left = 0, right = 0, top = 0, bottom = 0 },
+ })
+
+ -- textures
+ local bgTex = overlay:CreateTexture(nil,"BACKGROUND")
+ bgTex:SetTexture(0.7,0.7,1.0,0.2)
+ bgTex:SetPoint("TOPLEFT",4,-4)
+ bgTex:SetPoint("BOTTOMRIGHT",-4,4)
+ local hTex = overlay:CreateTexture(nil,"HIGHLIGHT")
+ hTex:SetTexture(0.7,0.7,1.0,0.2)
+ hTex:SetPoint("TOPLEFT",4,-4)
+ hTex:SetPoint("BOTTOMRIGHT",-4,4)
+ hTex:SetBlendMode("ADD")
+ local aTex = overlay:CreateTexture(nil,"ARTWORK")
+ aTex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
+ aTex:SetWidth(16)
+ aTex:SetHeight(16)
+ aTex:Hide()
+
+ -- label
+ local label = overlay:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
+ label:SetAllPoints()
+ label:SetJustifyH("CENTER")
+ label:SetShadowColor(0,0,0,1)
+ label:SetShadowOffset(3,-3)
+ label:SetTextColor(GetNormalTextColor())
+ label:SetText(bar:GetName())
+ label:Show()
+ overlay.labelString = label
+ overlay.labelName = bar:GetName()
+
+ local function UpdateAnchorDecoration()
+ local point, anchor, relPoint, x, y = f:GetPoint(1)
+ if point then
+ local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
+ if (anchor and anchor ~= UIParent) or (ofsx == 0 and ofsy == 0) then
+ bgTex:SetTexture( GetAnchoredBgColor() )
+ hTex:SetTexture( GetAnchoredBgColor() )
+ label:SetTextColor( GetAnchoredTextColor() )
+ aTex:ClearAllPoints()
+ aTex:SetPoint(point)
+ aTex:Show()
+ return
+ end
+ end
+ bgTex:SetTexture( GetNormalBgColor() )
+ hTex:SetTexture( GetNormalBgColor() )
+ label:SetTextColor( GetNormalTextColor() )
+ aTex:Hide()
+ end
+
+ local function StopResize()
+ f:StopMovingOrSizing()
+ f.isMoving = false
+ f:SetScript("OnUpdate",nil)
+ StoreSize(bar)
+ ClampToButtons(bar)
+ ReAction:RefreshEditor()
+ end
+
+ local function CornerUpdate()
+ local bw, bh = GetButtonSize(bar)
+ local r, c, s = GetButtonGrid(bar)
+ local ss = GetStateScale(bar)
+ if IsShiftKeyDown() then
+ if ss then
+ f:SetMinResize( ((s+bw)*c*0.25)/ss, ((s+bh)*r*0.25)/ss )
+ f:SetMaxResize( ((s+bw)*c*2.5 + 1)/ss, ((s+bh)*r*2.5 + 1)/ss )
+ scale = ComputeBarScale(bar, overlay)
+ else
+ f:SetMinResize( (s+12)*c+1, (s+12)*r+1 )
+ f:SetMaxResize( (s+128)*c+1, (s+128)*r+1 )
+ RecomputeButtonSize(bar)
+ end
+ elseif not ss and IsAltKeyDown() then
+ f:SetMinResize( bw*c, bh*r )
+ f:SetMaxResize( 2*bw*c, 2*bh*r )
+ RecomputeButtonSpacing(bar)
+ else
+ f:SetMinResize( bw+s+1, bh+s+1 )
+ f:SetMaxResize( 50*(bw+s)+1, 50*(bh+s)+1 )
+ RecomputeGrid(bar)
+ end
+ GameTooltipTextRight2:SetText(format("%d x %d",r,c))
+
+ local ss = GetStateScale(bar)
+ if ss then
+ GameTooltipTextRight4:SetText(format("%d%%", scale*100))
+ else
+ local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
+ GameTooltipTextRight3:SetText(size)
+ GameTooltipTextRight4:SetText(tostring(s))
+ end
+ end
+
+ -- corner drag handles
+ for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do
+ local corner = CreateFrame("Frame",nil,overlay)
+ corner:EnableMouse(true)
+ corner:SetWidth(16)
+ corner:SetHeight(16)
+ corner:SetPoint(point)
+
+ local tex = corner:CreateTexture(nil,"HIGHLIGHT")
+ tex:SetTexture("Interface\\AddOns\\ReAction\\img\\corner")
+ tex:SetTexCoord(unpack(cornerTexCoords[point]))
+ tex:SetBlendMode("ADD")
+ tex:SetAlpha(0.6)
+ tex:SetAllPoints()
+
+ corner:SetScript("OnMouseDown",
+ function(_,btn)
+ f:SetScript("OnUpdate", CornerUpdate)
+ f:StartSizing(point)
+ end
+ )
+ corner:SetScript("OnMouseUp",
+ function()
+ local ss = GetStateScale(bar)
+ if ss then
+ SetStateScale(bar, ComputeBarScale(bar, overlay))
+ end
+ StopResize()
+ end)
+ corner:SetScript("OnEnter",
+ function()
+ local bw, bh = GetButtonSize(bar)
+ local r, c, s = bar:GetButtonGrid()
+ local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
+ local ss = GetStateScale(bar)
+ local state = bar:GetSecureState()
+ GameTooltip:SetOwner(f, "ANCHOR_"..point)
+ if ss then
+ GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
+ else
+ GameTooltip:AddLine(bar:GetName())
+ end
+ GameTooltip:AddDoubleLine(format("|cffcccccc%s|r %s",L["Drag"],L["to add/remove buttons:"]), format("%d x %d",r,c))
+ if ss then
+ GameTooltip:AddLine(L["State Scale Override"])
+ GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to change scale:"]), format("%d%%", bar:GetStateProperty(state,"scale")*100))
+ else
+ GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to resize buttons:"]), tostring(floor(size)))
+ GameTooltip:AddDoubleLine(format("|cff0033cc%s|r %s",L["Hold Alt"], L["to change spacing:"]), tostring(floor(s)))
+ end
+ GameTooltip:Show()
+ end
+ )
+ corner:SetScript("OnLeave",
+ function()
+ GameTooltip:Hide()
+ f:SetScript("OnUpdate",nil)
+ end
+ )
+ end
+
+ overlay:RegisterForDrag("LeftButton")
+ overlay:RegisterForClicks("RightButtonUp")
+
+ overlay:SetScript("OnDragStart",
+ function()
+ f:StartMoving()
+ f.isMoving = true
+ local w,h = bar:GetButtonSize()
+ f:ClearAllPoints()
+ UpdateAnchorDecoration()
+ f:SetScript("OnUpdate", function()
+ if IsShiftKeyDown() then
+ local f, p = DisplaySnapIndicator(f,w,h)
+ else
+ HideSnapIndicator()
+ end
+ end)
+ end
+ )
+
+ local function UpdateDragTooltip()
+ GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT")
+ local ss = GetStateScale(bar)
+ local state = bar:GetSecureState()
+ if ss then
+ GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
+ else
+ GameTooltip:AddLine(bar:GetName())
+ end
+ GameTooltip:AddLine(format("|cffcccccc%s|r %s",L["Drag"],L["to move"]))
+ GameTooltip:AddLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to anchor to nearby frames"]))
+ GameTooltip:AddLine(format("|cff00cccc%s|r %s",L["Right-click"],L["for options..."]))
+ local point, frame, relpoint, x, y = bar:GetFrame():GetPoint(1)
+ if point then
+ local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
+ if (frame and frame ~= UIParent) or (ofsx == 0 and ofsy == 0) then
+ frame = frame or UIParent
+ GameTooltip:AddLine(format("%s <%s>",L["Currently anchored to"],frame:GetName()))
+ end
+ end
+ GameTooltip:Show()
+ end
+
+ overlay:SetScript("OnDragStop",
+ function()
+ f:StopMovingOrSizing()
+ f.isMoving = false
+ f:SetScript("OnUpdate",nil)
+
+ if IsShiftKeyDown() then
+ local w, h = bar:GetButtonSize()
+ local a, p, rp, x, y = GetClosestPointSnapped(f,w,h)
+ if a then
+ f:ClearAllPoints()
+ f:SetPoint(p,a,rp,x,y)
+ end
+ HideSnapIndicator()
+ end
+
+ StoreExtents(bar)
+ ReAction:RefreshEditor()
+ UpdateDragTooltip()
+ UpdateAnchorDecoration()
+ end
+ )
+
+ overlay:SetScript("OnEnter",
+ function()
+ UpdateDragTooltip()
+ end
+ )
+
+ overlay:SetScript("OnLeave", HideGameTooltip)
+
+ overlay:SetScript("OnClick",
+ function()
+ ReAction:ShowEditor(bar)
+ end
+ )
+
+ function overlay:RefreshControls()
+ UpdateAnchorDecoration()
+ end
+
+ overlay:SetScript("OnShow", overlay.RefreshControls)
+
+ if ReAction:GetKeybindMode() then
+ overlay:SetFrameLevel(1)
+ end
+
+ UpdateLabelString(overlay)
+ UpdateAnchorDecoration()
+
+ return overlay
+end
+
+
+-- export methods to the Bar prototype
+Bar.Overlay = { }
+function Bar.Overlay:New( bar )
+ return setmetatable( {frame = CreateControls(bar)}, {__index=self} )
+end
+
+function Bar.Overlay:SetLabel(name)
+ self.frame.labelName = name
+ UpdateLabelString(self.frame)
+end
+
+function Bar.Overlay:SetLabelSubtext(text)
+ self.frame.labelSubtext = text
+ UpdateLabelString(self.frame)
+end
+
+function Bar.Overlay:Show()
+ self.frame:Show()
+end
+
+function Bar.Overlay:Hide()
+ self.frame:Hide()
+end
+
+function Bar.Overlay:IsShown()
+ return self.frame:IsShown()
+end
+
+function Bar.Overlay:RefreshControls()
+ self.frame:RefreshControls()
+end
\ No newline at end of file
diff -r f255cd69e890 -r 65f2805957a0 PetActionButton.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PetActionButton.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,324 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local GetCVar = GetCVar
+local InCombatLockdown = InCombatLockdown
+local GetPetActionInfo = GetPetActionInfo
+local GetPetActionSlotUsable = GetPetActionSlotUsable
+local GetPetActionCooldown = GetPetActionCooldown
+local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart
+local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop
+local SetDesaturation = SetDesaturation
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+
+--
+-- Secure snippets
+-- These are run within the context of the bar's sandbox, as the
+-- buttons themselves do not have their own sandbox.
+--
+local _onDragStart = -- function(self, button, kind, value, ...)
+[[
+ if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
+ return kind, value, ...
+ else
+ return "petaction", self:GetAttribute("action")
+ end
+]]
+
+local _onReceiveDrag = -- function(self, button, kind, value, ...)
+[[
+ if kind then -- pet spells on the cursor return nil from GetCursorInfo(), which is very strange
+ return kind, value, ...
+ end
+ return "petaction", self:GetAttribute("action")
+]]
+
+--
+-- private
+--
+local eventList = {
+"PLAYER_CONTROL_LOST",
+"PLAYER_CONTROL_GAINED",
+"PLAYER_FARSIGHT_FOCUS_CHANGED",
+"UNIT_PET",
+"UNIT_FLAGS",
+"UNIT_AURA",
+"PET_BAR_UPDATE",
+"PET_BAR_UPDATE_COOLDOWN",
+"PET_BAR_UPDATE_USABLE",
+"UPDATE_BINDINGS",
+}
+
+--
+-- Pet Action Button class
+--
+local buttonTypeID = "PetAction"
+local Super = ReAction.Button
+local Pet = setmetatable(
+ {
+ defaultBarConfig = {
+ type = buttonTypeID,
+ btnWidth = 30,
+ btnHeight = 30,
+ btnRows = 1,
+ btnColumns = 10,
+ spacing = 8,
+ buttons = { }
+ },
+
+ barType = L["Pet Action Bar"],
+ buttonTypeID = buttonTypeID
+ },
+ { __index = Super } )
+
+ReAction.Button.PetAction = Pet
+ReAction:RegisterBarType(Pet)
+
+function Pet:New( config, bar, idx, idHint )
+ local name = format("ReAction_%s_PetAction_%d",bar:GetName(),idx)
+
+ self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+
+ local f = self:GetFrame()
+ if not f.autoCastTexture then
+ -- store autocast stuff with the frame for recycling
+ local tex = f:CreateTexture(nil,"OVERLAY")
+ tex:SetTexture([[Interface\Buttons\UI-AutoCastableOverlay]])
+ tex:SetHeight(58)
+ tex:SetWidth(58)
+ tex:SetPoint("CENTER")
+ f.autoCastTexture = tex
+ f.autoCastShine = CreateFrame("Frame",name.."Shine",f,"AutoCastShineTemplate") -- create after autocast texture so it's on top
+ -- move the cooldown around
+ local cd = self.frames.cooldown
+ cd:ClearAllPoints()
+ cd:SetWidth(33)
+ cd:SetHeight(33)
+ cd:SetPoint("CENTER", f, "CENTER", -2, -1)
+ -- resize to 30x30
+ f:SetHeight(30)
+ f:SetWidth(30)
+ local nt = _G[name.."NormalTexture"]
+ nt:SetHeight(54)
+ nt:SetWidth(54)
+ end
+ local barFrame = bar:GetFrame()
+
+ -- set up the base action ID
+ self:SetActionIDPool("pet",10)
+ config.actionID = self:AcquireActionID(config.actionID, idHint, true)
+
+ -- attribute setup
+ -- There's no secure way to do PetAutoCastToggle by actionID, so use
+ -- a click-through proxy to the Blizzard pet buttons for right-click
+ -- Note that technically this doesn't do PetStopAttack() when
+ -- IsPetAttackActive() is true: however that's only true when using
+ -- Eyes of the Beast and appears not to really do anything (at least
+ -- I can't find any difference)
+ f:SetAttribute("type","pet")
+ f:SetAttribute("type2","click")
+ f:SetAttribute("clickbutton2",_G["PetActionButton"..config.actionID])
+ f:SetAttribute("action",config.actionID)
+ f:SetAttribute("checkselfcast", true)
+ f:SetAttribute("checkfocuscast", true)
+
+ -- non secure scripts
+ f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+ f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+ f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+ f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
+ f:SetScript("PreClick", function(frame) self:PreClick() end)
+ f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
+ f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
+
+ -- secure handlers
+ barFrame:WrapScript(f, "OnDragStart", _onDragStart)
+ barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
+
+ -- event registration
+ f:EnableMouse(true)
+ f:RegisterForDrag("LeftButton", "RightButton")
+ f:RegisterForClicks("AnyUp")
+ for _, evt in pairs(eventList) do
+ f:RegisterEvent(evt)
+ end
+
+ -- attach to skinner
+ bar:SkinButton(self,
+ {
+ AutoCast = f.autoCastShine,
+ AutoCastable = f.autoCastTexture
+ })
+
+ self:Refresh()
+ f:Show()
+
+ return self
+end
+
+function Pet:SetupBar(bar)
+ Super.SetupBar(self,bar)
+
+ -- auto show/hide when pet exists
+ bar:RegisterUnitWatch("pet",true)
+
+ self:UpdateButtonLock(bar)
+end
+
+function Pet:UpdateButtonLock(bar)
+ local f = bar:GetFrame()
+ f:SetAttribute("lockbuttons",bar.config.lockButtons)
+ f:SetAttribute("lockbuttonscombat",bar.config.lockButtonsCombat)
+ f:Execute(
+ [[
+ lockButtons = self:GetAttribute("lockbuttons")
+ lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+ ]])
+end
+
+function Pet:Refresh()
+ Super.Refresh(self)
+ self:Update()
+ self:UpdateHotkey()
+end
+
+function Pet:GetActionID()
+ return self.config.actionID
+end
+
+function Pet:SetActionID(id)
+ if not InCombatLockdown() then
+ if id < 0 or id > 10 then
+ ReAction:UserError(L["Pet action ID range is 1-10"])
+ return
+ end
+ self.config.actionID = id
+ f:SetAttribute("clickbutton2",_G["PetActionButton"..id])
+ f:SetAttribute("action",id)
+ self:Update()
+ self:UpdateHotkey()
+ end
+end
+
+function Pet:Update()
+ local action = self.config.actionID
+ local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(action)
+ local f = self:GetFrame()
+ local icon = self.frames.icon
+
+ if isToken then
+ icon:SetTexture(_G[texture])
+ self.tooltipName = _G[name]
+ else
+ icon:SetTexture(texture)
+ self.tooltipName = name
+ end
+
+ self.isToken = isToken
+ self.tooltipSubtext = subtext
+ f:SetChecked( isActive and 1 or 0 )
+
+ if autoCastAllowed then
+ f.autoCastTexture:Show()
+ else
+ f.autoCastTexture:Hide()
+ end
+
+ if autoCastEnabled then
+ AutoCastShine_AutoCastStart(f.autoCastShine)
+ else
+ AutoCastShine_AutoCastStop(f.autoCastShine)
+ end
+
+ if texture then
+ if GetPetActionSlotUsable(action) then
+ SetDesaturation(icon,nil)
+ else
+ SetDesaturation(icon,1)
+ end
+ icon:Show()
+ f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+ else
+ icon:Hide()
+ f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+ end
+
+ self:UpdateCooldown()
+end
+
+function Pet:UpdateCooldown()
+ CooldownFrame_SetTimer(self.frames.cooldown, GetPetActionCooldown(self.config.actionID))
+end
+
+function Pet:SetTooltip()
+ if self.tooltipName then
+ local f = self:GetFrame()
+ local uber = GetCVar("UberTooltips")
+ if self.isToken or (uber == "0") then
+ if uber == "0" then
+ GameTooltip:SetOwner(f, "ANCHOR_RIGHT")
+ else
+ GameTooltip_SetDefaultAnchor(GameTooltip, f)
+ end
+ GameTooltip:SetText(self.tooltipName)
+ if self.tooltipSubtext then
+ GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5)
+ end
+ GameTooltip:Show()
+ else
+ GameTooltip_SetDefaultAnchor(GameTooltip, f)
+ GameTooltip:SetPetAction(self.config.actionID)
+ end
+ else
+ GameTooltip:Hide()
+ end
+end
+
+function Pet:OnEvent(event, unit)
+ if event =="PET_BAR_UPDATE_COOLDOWN" then
+ self:UpdateCooldown()
+ elseif event == "UPDATE_BINDINGS" then
+ self:UpdateHotkey()
+ elseif event == "UNIT_PET" then
+ if unit == "player" then
+ self:Update()
+ end
+ elseif event == "UNIT_FLAGS" or event == "UNIT_AURA" then
+ if unit == "pet" then
+ self:Update()
+ end
+ else
+ self:Update()
+ end
+end
+
+function Pet:OnEnter()
+ self:SetTooltip()
+end
+
+function Pet:OnLeave()
+ GameTooltip:Hide()
+end
+
+function Pet:OnAttributeChanged(attr,value)
+ self:Update()
+end
+
+function Pet:PreClick()
+ self:GetFrame():SetChecked(0)
+end
+
+function Pet:OnDragStart()
+ self:SetChecked(0)
+ self:Update()
+end
+
+function Pet:OnReceiveDrag()
+ self:SetChecked(0)
+ self:Update()
+end
+
diff -r f255cd69e890 -r 65f2805957a0 ReAction.xml
--- a/ReAction.xml Sat Mar 26 12:26:55 2011 -0700
+++ b/ReAction.xml Sat Mar 26 12:35:08 2011 -0700
@@ -7,9 +7,15 @@
-
-
-
+
+
+
+
+
+
+
+
+
diff -r f255cd69e890 -r 65f2805957a0 StanceButton.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/StanceButton.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,198 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local InCombatLockdown = InCombatLockdown
+local GetNumShapeshiftForms = GetNumShapeshiftForms
+local GetShapeshiftFormInfo = GetShapeshiftFormInfo
+local IsUsableSpell = IsUsableSpell
+local GetSpellInfo = GetSpellInfo
+
+--
+-- private
+--
+local playerClass = select(2,UnitClass("player"))
+
+local eventList = {
+ "PLAYER_REGEN_ENABLED",
+ "PLAYER_ENTERING_WORLD",
+ "UPDATE_SHAPESHIFT_FORM",
+ "UPDATE_SHAPESHIFT_FORMS",
+ "UPDATE_SHAPESHIFT_USABLE",
+ "UPDATE_SHAPESHIFT_COOLDOWN",
+ "UPDATE_BINDINGS",
+}
+
+--
+-- Stance Button class
+--
+local buttonTypeID = "Stance"
+local Super = ReAction.Button
+local Stance = setmetatable(
+ {
+ defaultConfig = {
+ type = buttonTypeID,
+ btnHeight = 36,
+ btnWidth = 36,
+ btnRows = 1,
+ btnColumns = 6,
+ spacing = 3
+ },
+
+ barType = L["Stance Bar"],
+ buttonTypeID = buttonTypeID
+ },
+ { __index = Super } )
+
+ReAction.Button.Stance = Stance
+ReAction:RegisterBarType(Stance)
+
+function Stance:New( config, bar, idx, idHint )
+ local name = format("ReAction_%s_Stance_%d",bar:GetName(),idx)
+
+ self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+
+ local f = self:GetFrame()
+ local barFrame = bar:GetFrame()
+ local config = self:GetConfig()
+
+ -- set up the base stance ID
+ self:SetActionIDPool("stance",8)
+ config.stanceID = self:AcquireActionID(config.stanceID, idHint, true)
+
+ -- attribute setup
+ f:SetAttribute("type","spell")
+
+ -- non secure scripts
+ f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+ f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+ f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+ f:SetScript("PreClick", function(frame, ...) self:PreClick(...) end)
+
+ -- secure handlers
+ -- (none)
+
+ -- event registration
+ f:EnableMouse(true)
+ f:RegisterForClicks("AnyUp")
+ for _, evt in pairs(eventList) do
+ f:RegisterEvent(evt)
+ end
+
+ -- attach to skinner
+ bar:SkinButton(self)
+
+ -- initial display
+ if ReAction:GetConfigMode() then
+ self:GetFrame():Show()
+ end
+
+ self:Refresh()
+
+ return self
+end
+
+function Stance:GetActionID()
+ return self.config.stanceID
+end
+
+function Stance:UpdateAction()
+ if InCombatLockdown() then
+ self.updatePending = true
+ else
+ self.updatePending = false
+ local idx = self:GetActionID()
+ local f = self:GetFrame()
+ if idx > GetNumShapeshiftForms() then
+ f:Hide()
+ else
+ f:SetAttribute("spell", select(2,GetShapeshiftFormInfo(idx)))
+ f:Show()
+ self:Update()
+ end
+ end
+end
+
+function Stance:Refresh()
+ Super.Refresh(self)
+ self:UpdateHotkey()
+ self:UpdateAction()
+end
+
+function Stance:Update()
+ local texture, _, isActive, isCastable = GetShapeshiftFormInfo(self:GetActionID())
+
+ local icon = self.frames.icon
+ icon:SetTexture(texture)
+ self:GetFrame():SetChecked( isActive and 1 or 0 )
+ if isCastable then
+ self.frames.hotkey:Show()
+ icon:SetVertexColor(1.0, 1.0, 1.0)
+ else
+ icon:SetVertexColor(0.4, 0.4, 0.4)
+ end
+
+ self:UpdateCooldown()
+end
+
+function Stance:UpdateCooldown()
+ local start, duration, enabled = GetShapeshiftFormCooldown(self:GetActionID())
+ if start then
+ CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enabled)
+ end
+end
+
+function Stance:SetTooltip()
+ if GetCVar("UberTooltips") == "1" then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self:GetFrame())
+ else
+ GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT")
+ end
+ GameTooltip:SetShapeshift(self:GetActionID())
+end
+
+function Stance:OnEnter()
+ self:SetTooltip()
+end
+
+function Stance:OnLeave()
+ GameTooltip:Hide()
+end
+
+function Stance:PreClick()
+ local f = self:GetFrame()
+ f:SetChecked( not f:GetChecked() )
+end
+
+function Stance:OnEvent(event, arg)
+ if event == "PLAYER_REGEN_ENABLED" then
+ if self.updatePending then
+ self:UpdateAction()
+ end
+ elseif event == "UPDATE_SHAPESHIFT_COOLDOWN" then
+ self:UpdateCooldown()
+ elseif event == "UPDATE_SHAPESHIFT_FORMS" then
+ self:UpdateAction()
+ elseif event == "UNIT_AURA" then
+ if arg == "player" then
+ self:Update()
+ end
+ elseif event == "UPDATE_BINDINGS" then
+ self:UpdateHotkey()
+ else
+ self:Update()
+ end
+end
+
+function Stance:ShowGridTemp(show)
+ if show then
+ self:GetFrame():Show()
+ else
+ self:UpdateAction()
+ end
+end
diff -r f255cd69e890 -r 65f2805957a0 VehicleExitButton.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/VehicleExitButton.lua Sat Mar 26 12:35:08 2011 -0700
@@ -0,0 +1,108 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local format = string.format
+
+--
+-- VExitButton Button class
+--
+local buttonTypeID = "VehicleExit"
+local Super = ReAction.Button
+local VExitButton = setmetatable(
+ {
+ defaultBarConfig = {
+ type = buttonTypeID ,
+ btnWidth = 36,
+ btnHeight = 36,
+ btnRows = 1,
+ btnColumns = 1,
+ spacing = 3,
+ buttons = { }
+ },
+
+ barType = L["Exit Vehicle Floater"],
+ buttonTypeID = buttonTypeID
+ },
+ { __index = Super } )
+
+ReAction.Button.VehicleExit = VExitButton
+ReAction:RegisterBarType(VExitButton)
+
+function VExitButton:New( config, bar, idx )
+ local name = format("ReAction_%s_VehicleExit_%d",bar:GetName(),idx)
+
+ self = Super.New(self, name, config, bar, idx, "SecureFrameTemplate, ActionButtonTemplate", "Button")
+
+ -- frame setup
+ local f = self:GetFrame()
+ self.frames.icon:SetTexture("Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up")
+ self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
+
+ -- attribute setup
+ -- (none)
+
+ -- non secure scripts
+ f:SetScript("OnClick", VehicleExit)
+ f:SetScript("OnEnter", function(frame) GameTooltip_AddNewbieTip(frame, LEAVE_VEHICLE, 1.0, 1.0, 1.0, nil) end)
+ f:SetScript("OnLeave", GameTooltip_Hide)
+ f:SetScript("OnEvent", function(frame, evt, ...) self:OnEvent(evt,...) end)
+
+ -- event registration
+ f:EnableMouse(true)
+ f:RegisterForClicks("AnyUp")
+ f:RegisterEvent("UPDATE_BINDINGS")
+
+ -- attach to skinner
+ bar:SkinButton(self)
+
+ self:Refresh()
+ self:UpdateHotkey()
+
+ return self
+end
+
+function VExitButton:SetupBar(bar)
+ Super.SetupBar(self,bar)
+ self:UpdateRegistration(bar)
+end
+
+function VExitButton:GetActionID()
+ return 1
+end
+
+function VExitButton:Refresh()
+ Super.Refresh(self)
+ -- it seems that setscale kills the texcoord, have to refresh it
+ self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
+end
+
+function VExitButton:OnEvent(event, ...)
+ if self[event] then
+ self[event](self, event, ...)
+ end
+end
+
+function VExitButton:UPDATE_BINDINGS()
+ self:UpdateHotkey()
+end
+
+function VExitButton:UpdateRegistration(bar)
+ -- auto show/hide when on a vehicle
+ local config = bar:GetConfig()
+ local f = bar:GetFrame()
+ if config.withControls then
+ if bar.vehicleExitStateRegistered then
+ UnregisterStateDriver(f, "unitexists")
+ bar.vehicleExitStateRegistered = false
+ end
+ bar:RegisterUnitWatch("vehicle",true)
+ else
+ bar:RegisterUnitWatch("vehicle",false)
+ if not bar.vehicleExitStateRegistered then
+ f:SetAttribute("unit","vehicle")
+ RegisterStateDriver(f, "unitexists", "[target=vehicle,exists,novehicleui] show; hide") -- spoof onstate-unitexists
+ bar.vehicleExitStateRegistered = true
+ end
+ end
+end
+
diff -r f255cd69e890 -r 65f2805957a0 classes/ActionButton.lua
--- a/classes/ActionButton.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,806 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local IsUsableAction = IsUsableAction
-local IsEquippedAction = IsEquippedAction
-local IsConsumableAction = IsConsumableAction
-local IsStackableAction = IsStackableAction
-local GetActionText = GetActionText
-local GetCVar = GetCVar
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-local IsCurrentAction = IsCurrentAction
-local IsAutoRepeatAction = IsAutoRepeatAction
-local IsUsableAction = IsUsableAction
-local IsAttackAction = IsAttackAction
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local GetActionCooldown = GetActionCooldown
-local GetActionTexture = GetActionTexture
-local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
-local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
-local IsActionInRange = IsActionInRange
-local InCombatLockdown = InCombatLockdown
-local HasAction = HasAction
-
---
--- Secure snippets
--- These are run within the context of the bar's sandbox, as the
--- buttons themselves do not have their own sandbox.
---
-local _onstate_mc = -- function(self, stateid, newstate)
-[[
- local oldMcVehicleState = mcVehicleState
- mcVehicleState = newstate
- control:ChildUpdate()
- if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
- control:ChildUpdate("vehicle")
- end
-]]
-
-local _childupdate = -- function(self, snippetid, message)
-[[
- local action = nil
- if (doVehicle and mcVehicleState == "vehicle") or
- (doMindControl and mcVehicleState == "mc") then
- local idx = self:GetAttribute("bar-idx")
- local maxN = (doVehicle and mcVehicleState == "vehicle") and 7 or 12
- if idx and idx <= maxN then
- action = 120 + idx
- else
- action = 0
- end
- elseif state and settings[state] and settings[state].page then
- action = self:GetAttribute("action-"..settings[state].page)
- end
- if action == nil then
- action = self:GetAttribute("default-action")
- end
-
- self:SetAttribute("action",action)
-
- if not self:GetAttribute("showgrid") then
- local tempShow = self:GetAttribute("showgrid-temp")
- local evtShow = self:GetAttribute("showgrid-event")
- if tempShow then tempShow = (tempShow > 0) end
- if evtShow then evtShow = (evtShow > 0) end
-
- if tempShow or evtShow or HasAction(action) then
- self:Show()
- else
- self:Hide()
- end
- end
-]]
-
-local _childupdate_vehicleExit = -- function(self, snippetid, message)
-[[
- local show = (mcVehicleState == "vehicle")
- if show and doVehicle then
- self:SetAttribute("type","macro")
- self:Show()
- else
- self:SetAttribute("type","action")
- end
- control:CallMethod("ShowVehicleExit",show)
-]]
-
-local _childupdate_showgrid = -- function(self, snippetid, message)
-[[
- showgrid_event = message
- self:SetAttribute("showgrid-event",message)
- if not self:GetAttribute("showgrid") then
- local count = message + (self:GetAttribute("showgrid-temp") or 0)
- if count <= 0 then
- local action = self:GetAttribute("action")
- -- note that HasAction is not updated on the target of a drag until after ACTIONBAR_HIDEGRID
- -- so, we set a flag for this button in pre-click/receive-drag and check for it here
- if HasAction(action) or self:GetAttribute("showgrid-clicked") then
- if not self:IsShown() then
- self:Show()
- end
- self:SetAttribute("showgrid-clicked",false)
- else
- if self:IsShown() then
- self:Hide()
- end
- end
- else
- self:Show()
- end
- end
-]]
-
-local _onDragStart = -- function(self, button, kind, value, ...)
-[[
- if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
- return kind, value, ...
- else
- return "action", self:GetAttribute("action")
- end
-]]
-
-local _onReceiveDrag = -- function(self, button, kind, value, ...)
-[[
- if kind ~= "spell" and kind ~= "item" and kind ~= "macro" and kind ~= "flyout" then
- return kind, value, ...
- else
- if showgrid_event and showgrid_event > 0 then
- self:SetAttribute("showgrid-clicked",true)
- end
- return "action", self:GetAttribute("action")
- end
-]]
-
-local _onClick = -- function(self, button, down)
-[[
- if showgrid_event and showgrid_event > 0 then
- self:SetAttribute("showgrid-clicked",true)
- end
- return button
-]]
-
---
--- private
---
-local eventList = {
- "PLAYER_ENTERING_WORLD",
- "ACTIONBAR_PAGE_CHANGED",
- "ACTIONBAR_SLOT_CHANGED",
- "UPDATE_BINDINGS",
- "ACTIONBAR_UPDATE_STATE",
- "ACTIONBAR_UPDATE_USABLE",
- "ACTIONBAR_UPDATE_COOLDOWN",
- "UNIT_INVENTORY_CHANGED",
- "LEARNED_SPELL_IN_TAB",
- "UPDATE_INVENTORY_ALERTS",
- "PLAYER_TARGET_CHANGED",
- "TRADE_SKILL_SHOW",
- "TRADE_SKILL_CLOSE",
- "PLAYER_ENTER_COMBAT",
- "PLAYER_LEAVE_COMBAT",
- "START_AUTOREPEAT_SPELL",
- "STOP_AUTOREPEAT_SPELL",
- "UNIT_ENTERED_VEHICLE",
- "UNIT_EXITED_VEHICLE",
- "COMPANION_UPDATE",
-}
-
---
--- Action Button class
---
-local buttonTypeID = "Action"
-local Super = ReAction.Button
-local Action = setmetatable(
- {
- defaultBarConfig = {
- type = buttonTypeID,
- btnWidth = 36,
- btnHeight = 36,
- btnRows = 1,
- btnColumns = 12,
- spacing = 3,
- buttons = { },
- },
-
- barType = L["Action Bar"],
- buttonTypeID = buttonTypeID
- },
- { __index = Super } )
-
-ReAction.Button.Action = Action
-ReAction:RegisterBarType(Action, true)
-
-function Action:New( config, bar, idx, idHint )
- local name = format("ReAction_%s_Action_%d",bar:GetName(),idx)
-
- self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
- self.barConfig = bar:GetConfig()
-
- local f = self:GetFrame()
- local barFrame = bar:GetFrame()
-
- self.rangeTimer = TOOLTIP_UPDATE_TIME
-
- -- set up the base action ID
- self:SetActionIDPool("action",120)
- config.actionID = self:AcquireActionID(config.actionID, idHint)
- self.nPages = 1
-
- -- attribute setup
- f:SetAttribute("type","action")
- f:SetAttribute("checkselfcast", true)
- f:SetAttribute("checkfocuscast", true)
- f:SetAttribute("action", config.actionID)
- f:SetAttribute("default-action", config.actionID)
- f:SetAttribute("bar-idx",idx)
- f:SetAttribute("showgrid-temp",0)
- f:SetAttribute("showgrid-event",0)
- f:SetAttribute("showgrid",not self:GetBarConfig().hideEmpty)
-
- -- non secure scripts
- f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
- f:SetScript("OnEnter", function(frame) self:OnEnter() end)
- f:SetScript("OnLeave", function(frame) self:OnLeave() end)
- f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
- f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
- f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end)
- f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
- f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
-
- -- event registration
- f:EnableMouse(true)
- f:RegisterForDrag("LeftButton", "RightButton")
- f:RegisterForClicks("AnyUp")
- for _, evt in pairs(eventList) do
- f:RegisterEvent(evt)
- end
-
- f.action = config.actionID -- need this to support silly ActionButton_UpdateFlyout. Should not taint anything anymore.
-
- -- secure handlers
- f:SetAttribute("_childupdate", _childupdate)
- f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid)
- barFrame:WrapScript(f, "OnDragStart", _onDragStart)
- barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
- barFrame:WrapScript(f, "OnClick", _onClick)
-
- -- attach to skinner
- bar:SkinButton(self)
-
- -- initial display
- if ReAction:GetConfigMode() then
- self:ShowGridTemp(true)
- end
-
- self:Refresh()
-
- return self
-end
-
-function Action:Destroy()
- local f = self:GetFrame()
- local c = self:GetConfig()
-
- f:SetAttribute("_childupdate-vehicle",nil)
- f:SetAttribute("action",c.actionID) -- so that Super.Destroy releases the right one
-
- if c.pageactions and #c.pageactions > 1 then
- for i = 2, #c.pageactions do
- self:ReleaseActionID(c.pageactions[i])
- self:ReleaseActionID(id)
- end
- end
-
- Super.Destroy(self)
-end
-
-function Action:GetBarConfig()
- -- this is the per-bar Action module config structure,
- -- not the config structure of the bar itself
- return self.barConfig
-end
-
-function Action:Refresh()
- Super.Refresh(self)
- self:RefreshPages()
- self:InstallVehicle()
- self:ShowGrid(not self:GetBarConfig().hideEmpty)
- self:UpdateAction()
-end
-
-function Action:InstallVehicle()
- local f = self:GetFrame()
- if self.idx == 7 and self:GetBarConfig().vehicle then
- if not self.vehicleInstalled then
- self.vehicleInstalled = true
- -- install vehicle-exit button on 7th button (only)
- f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit)
- f:SetAttribute("macrotext","/run VehicleExit()")
- self:GetBar():GetFrame().ShowVehicleExit = function(bar,show)
- self:ShowVehicleExit(show)
- end
- end
- -- setscale blows away tex coords
- self:UpdateIcon()
- elseif self.vehicleInstalled then
- self.vehicleInstalled = false
- f:SetAttribute("_childupdate-vehicle",nil)
- f:SetAttribute("macrotext",nil)
- end
-end
-
-function Action:ShowGrid( show )
- if not InCombatLockdown() then
- self.frame:SetAttribute("showgrid", show)
- self:UpdateShowGrid()
- end
-end
-
-function Action:ShowGridTemp( show )
- -- This function only modifies the show-grid when out
- -- of combat, and is ignored by the secure handler. Use
- -- it for configuration modes.
- if not InCombatLockdown() then
- local count = self.showGridTempCount or 0
- if show then
- count = count + 1
- else
- count = count - 1
- end
- if count < 0 then count = 0 end
- self.showGridTempCount = count
- self:GetFrame():SetAttribute("showgrid-temp",count)
- self:UpdateShowGrid()
- end
-end
-
-function Action:UpdateAll()
- self:UpdateActionIDLabel(ReAction:GetConfigMode())
- self:UpdateHotkey()
- self:UpdateShowGrid()
- self:UpdateIcon()
- self:UpdateBorder()
- self:UpdateMacroText()
- self:UpdateCount()
- self:UpdateTooltip()
- self:UpdateCheckedState()
- self:UpdateUsable()
- self:UpdateCooldown()
- self:UpdateFlash()
-end
-
-function Action:UpdateAction()
- local action = self:GetActionID()
- if action ~= self.actionID then
- self.actionID = action
- self:UpdateAll()
- end
-end
-
-function Action:UpdateShowGrid()
- if not InCombatLockdown() then
- local f = self:GetFrame()
- local count = (f:GetAttribute("showgrid-event") or 0) +
- (self.showGridTempCount or 0) +
- (f:GetAttribute("showgrid") and 1 or 0)
-
- if count <= 0 and not HasAction(self.actionID) then
- if f:IsShown() then
- f:Hide()
- end
- elseif not f:IsShown() then
- f:Show()
- end
- end
-end
-
-function Action:UpdateIcon()
- local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture()
- local icon = self.frames.icon
- local hotkey = self.frames.hotkey
- local f = self:GetFrame()
-
- if self.vehicleExitMode then
- texture = "Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up"
- icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
- icon:SetVertexColor(1,1,1)
- else
- icon:SetTexCoord(0,1,0,1)
- end
-
- if texture then
- icon:SetTexture(texture)
- if tLeft then
- icon:SetTexCoord(tLeft,tRight,tTop,tBottom)
- end
- icon:Show()
- self.rangeTimer = -1
- f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
- else
- icon:Hide()
- self.frames.cooldown:Hide()
- self.rangeTimer = nil
- f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
- end
-end
-
-function Action:GetIconTexture()
- return GetActionTexture(self.actionID)
-end
-
-function Action:UpdateBorder()
- local action = self.actionID
- if ReAction:GetKeybindMode() then
- self:UpdateKeybindModeDisplay(true)
- elseif IsEquippedAction(action) then
- self.frames.border:SetVertexColor(0, 1.0, 0, 0.35)
- self.frames.border:Show()
- else
- self.frames.border:Hide()
- end
-end
-
-function Action:UpdateMacroText()
- local action = self.actionID
- if not IsConsumableAction(action) and not IsStackableAction(action) then
- self.frames.name:SetText(GetActionText(action))
- else
- self.frames.name:SetText("")
- end
-end
-
-function Action:UpdateCount()
- local action = self.actionID
- if IsConsumableAction(action) or IsStackableAction(action) then
- self.frames.count:SetText(GetActionCount(action))
- else
- self.frames.count:SetText("")
- end
-end
-
-function Action:UpdateTooltip()
- local f = self:GetFrame()
- if GameTooltip:GetOwner() == f then
- self:SetTooltip()
- end
-end
-
-function Action:SetTooltip()
- local f = self:GetFrame()
- if GetCVar("UberTooltips") == "1" then
- GameTooltip_SetDefaultAnchor(GameTooltip, f)
- else
- GameTooltip:SetOwner(f,"ANCHOR_RIGHT")
- end
- GameTooltip:SetAction(self.actionID)
-end
-
-function Action:UpdateCheckedState()
- local action = self.actionID
- if IsCurrentAction(action) or IsAutoRepeatAction(action) then
- self:GetFrame():SetChecked(1)
- else
- self:GetFrame():SetChecked(0)
- end
-end
-
-function Action:UpdateUsable()
- local isUsable, notEnoughMana = self:GetUsable()
- local noRange = self:GetInRange()
-
- isUsable = self.vehicleExitMode or (isUsable and not noRange)
-
- if isUsable then
- if self.usableStatus ~= "usable" then
- self.frames.icon:SetVertexColor(1.0, 1.0, 1.0)
- self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
- self.usableStatus = "usable"
- end
- elseif noRange then
- if self.usableStatus ~= "norange" then
- self.frames.icon:SetVertexColor(1.0,0.1,0.1)
- self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
- self.usableStatus = "norange"
- end
- elseif notEnoughMana then
- if self.usableStatus ~= "oom" then
- self.frames.icon:SetVertexColor(0.5, 0.5, 1.0)
- self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0)
- self.usableStatus = "oom"
- end
- else
- if self.usableStatus ~= "unusable" then
- self.frames.icon:SetVertexColor(0.4, 0.4, 0.4)
- self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
- self.usableStatus = "unusable"
- end
- end
-end
-
-function Action:GetUsable()
- return IsUsableAction(self.actionID)
-end
-
-function Action:GetInRange()
- return IsActionInRange(self.actionID) == 0
-end
-
-function Action:UpdateCooldown()
- CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown())
-end
-
-function Action:GetCooldown()
- return GetActionCooldown(self.actionID)
-end
-
-function Action:UpdateFlash()
- local action = self.actionID
- self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) )
-end
-
-function Action:SetFlash(flash)
- if self.flashing ~= flash then
- self.flashing = flash
- self.flashtime = 0
- if not flash then
- self.frames.flash:Hide()
- end
- self:UpdateCheckedState()
- end
-end
-
-function Action:RunFlash(elapsed)
- if self.flashing then
- local flashtime = self.flashtime - elapsed
- self.flashtime = flashtime
- if flashtime <= 0 then
- local overtime = -flashtime
- if overtime >= ATTACK_BUTTON_FLASH_TIME then
- overtime = 0
- end
- flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
- local flash = self.frames.flash
- if flash:IsShown() then
- flash:Hide()
- else
- flash:Show()
- end
- end
- end
-end
-
-function Action:RunRangeFinder(elapsed)
- local rangeTimer = self.rangeTimer
- if rangeTimer then
- rangeTimer = rangeTimer - elapsed
- self.rangeTimer = rangeTimer
- if rangeTimer <= 0 then
- self:UpdateUsable()
- self.rangeTimer = TOOLTIP_UPDATE_TIME
- end
- end
-end
-
-function Action:GetActionID(page)
- if page == nil then
- -- get the effective ID
- return self:GetFrame():GetAttribute("action")
- else
- if page == 1 then
- return self.config.actionID
- else
- return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
- end
- end
-end
-
-function Action:SetActionID( id, page )
- id = tonumber(id)
- page = tonumber(page)
- if id == nil or id < 1 or id > 120 then
- ReAction:UserError(L["Action ID range is 1-120"])
- return
- end
- if page and page ~= 1 then
- if not self.config.pageactions then
- self.config.pageactions = { }
- end
- self:ReleaseActionID(self.config.pageactions[page])
- self.config.pageactions[page] = id
- self:AcquireActionID(self.config.pageactions[page])
- self.frame:SetAttribute("action-page"..page,id)
- else
- self:ReleaseActionID(self.config.actionID)
- self.config.actionID = id
- self:AcquireActionID(self.config.actionID)
- self.frame:SetAttribute("action",id)
- self.frame:SetAttribute("default-action",id)
- if self.config.pageactions then
- self.config.pageactions[1] = id
- self.frame:SetAttribute("action-page1",id)
- end
- end
-end
-
-function Action:RefreshPages( force )
- local nPages = self:GetBarConfig().nPages
- if nPages and (nPages ~= self.nPages or force) then
- local f = self:GetFrame()
- local c = self.config.pageactions
- if nPages > 1 and not c then
- c = { }
- self.config.pageactions = c
- end
- for i = 1, nPages do
- if i > 1 then
- c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
- else
- c[i] = self.config.actionID -- page 1 is the same as the base actionID
- end
- f:SetAttribute("action-page"..i,c[i])
- end
- for i = nPages+1, #c do
- self:ReleaseActionID(c[i])
- c[i] = nil
- f:SetAttribute("action-page"..i,nil)
- end
- self.nPages = nPages
- end
-end
-
-function Action:SetupBar( bar )
- Super.SetupBar(self,bar)
-
- local f = bar:GetFrame()
- local config = bar:GetConfig()
- f:SetAttribute("mindcontrol",config.mindcontrol)
- f:SetAttribute("vehicle",config.vehicle)
- f:Execute(
- [[
- doMindControl = self:GetAttribute("mindcontrol")
- doVehicle = self:GetAttribute("vehicle")
- control:ChildUpdate()
- ]])
-
- f:SetAttribute("_onstate-mc", _onstate_mc)
- RegisterStateDriver(f, "mc", "[vehicleui] vehicle; [bonusbar:5] mc; none")
-
- f:SetAttribute("lockbuttons",config.lockButtons)
- f:SetAttribute("lockbuttonscombat",config.lockButtonsCombat)
- f:Execute(
- [[
- lockButtons = self:GetAttribute("lockbuttons")
- lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
- ]])
-end
-
-
-function Action:SetButtonLock( bar, lock, lockCombat )
- local f = bar:GetFrame()
- f:SetAttribute("lockbuttons",lock)
- f:SetAttribute("lockbuttonscombat",lockCombat)
- f:Execute(
- [[
- lockButtons = self:GetAttribute("lockbuttons")
- lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
- ]])
-end
-
-
-function Action:ShowVehicleExit(show)
- self.vehicleExitMode = show and self:GetBarConfig().vehicle
- self:UpdateIcon()
-end
-
-function Action:OnEnter( )
- self:SetTooltip()
-end
-
-function Action:OnLeave( )
- GameTooltip:Hide()
-end
-
-function Action:OnAttributeChanged( attr, value )
- if attr ~= "statehidden" then
- self:UpdateAction()
- end
- local f = self:GetFrame()
- f.action = f:GetAttribute("action") -- support ActionButton_UpdateFlyout
-end
-
-function Action:PostClick( )
- self:UpdateCheckedState()
-end
-
-function Action:OnUpdate( elapsed )
- self:RunFlash(elapsed)
- self:RunRangeFinder(elapsed)
-end
-
-function Action:OnDragStart()
- self:UpdateCheckedState()
- self:UpdateFlash()
-end
-
-function Action:OnReceiveDrag()
- self:UpdateCheckedState()
- self:UpdateFlash()
-end
-
-function Action:OnEvent(event, ...)
- if self[event] then
- self[event](self, event, ...)
- end
-end
-
-function Action:ACTIONBAR_SLOT_CHANGED(event, action)
- if action == 0 or action == self.actionID then
- self:UpdateAll()
- end
-end
-
-function Action:PLAYER_ENTERING_WORLD()
- self:UpdateAction()
-end
-
-function Action:ACTIONBAR_PAGE_CHANGED()
- self:UpdateAction()
-end
-
-function Action:UPDATE_BONUS_ACTIONBAR()
- self:UpdateAction()
-end
-
-function Action:UPDATE_BINDINGS()
- self:UpdateHotkey()
-end
-
-function Action:PLAYER_TARGET_CHANGED()
- self.rangeTimer = -1
-end
-
-function Action:ACTIONBAR_UPDATE_STATE()
- self:UpdateCheckedState()
-end
-
-function Action:TRADE_SKILL_SHOW()
- self:UpdateCheckedState()
-end
-Action.TRADE_SKILL_CLOSE = Action.TRADE_SKILL_CLOSE
-
-function Action:UNIT_ENTERED_VEHICLE(event,unit)
- if unit == "player" then
- self:UpdateCheckedState()
- end
-end
-Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE
-
-function Action:COMPANION_UPDATE(event,unit)
- if unit == "mount" then
- self:UpdateCheckedState()
- end
-end
-
-function Action:ACTIONBAR_UPDATE_USABLE()
- self:UpdateUsable()
-end
-
-function Action:ACTIONBAR_UPDATE_COOLDOWN()
- self:UpdateCooldown()
-end
-
-function Action:PLAYER_ENTER_COMBAT()
- if IsAttackAction(self.actionID) then
- self:SetFlash(true)
- end
-end
-
-function Action:PLAYER_LEAVE_COMBAT()
- if IsAttackAction(self.actionID) then
- self:SetFlash(false)
- end
-end
-
-function Action:START_AUTOREPEAT_SPELL()
- if IsAutoRepeatAction(self.actionID) then
- self:SetFlash(true)
- end
-end
-
-function Action:STOP_AUTOREPEAT_SPELL()
- if not IsAttackAction(self.actionID) then
- self:SetFlash(false)
- end
-end
-
-function Action:UNIT_INVENTORY_CHANGED(unit)
- if unit == "player" then
- self:UpdateTooltip()
- end
-end
-
-function Action:LEARNED_SPELL_IN_TAB()
- self:UpdateTooltip()
-end
diff -r f255cd69e890 -r 65f2805957a0 classes/BagButton.lua
--- a/classes/BagButton.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,499 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local GetCVar = GetCVar
-local ContainerIDToInventoryID = ContainerIDToInventoryID
-local NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES
-local IsModifiedClick = IsModifiedClick
-local CursorHasItem = CursorHasItem
-local GetInventoryItemTexture = GetInventoryItemTexture
-local GetInventorySlotInfo = GetInventorySlotInfo
-local PickupBagFromSlot = PickupBagFromSlot
-local CursorCanGoInSlot = CursorCanGoInSlot
-
--- class declarations
-local buttonTypeID = "Bag"
-local weak = { __mode = "k" }
-local Super = ReAction.Button
-local BagBase = setmetatable(
- {
- defaultBarConfig = {
- type = buttonTypeID,
- btnWidth = 30,
- btnHeight = 30,
- btnRows = 1,
- btnColumns = 6,
- spacing = 4,
- buttons = { }
- },
-
- barType = L["Bag Bar"],
- buttonTypeID = buttonTypeID,
-
- allButtons = setmetatable( { }, weak )
- },
- { __index = Super } )
-
-local Bag = setmetatable( { }, { __index = BagBase } )
-local Backpack = setmetatable( { }, { __index = BagBase } )
-local Keyring = setmetatable( { }, { __index = BagBase } )
-
-ReAction.Button.Bag = BagBase
-ReAction:RegisterBarType(BagBase)
-
---
--- Bag Button base class
---
-
-function BagBase:New( btnCfg, bar, idx, idHint )
- local name = format("ReAction_%s_Bag_%d",bar:GetName(),idx)
-
- -- use a variable private leaf implementation class
- -- unlike traditional OO programming, we can initialize the leaf
- -- class before initializing its parent
- local class = Bag
- if idx == 1 then
- class = Backpack
- elseif idx == 6 then
- class = Keyring
- end
- self = class:New(name, btnCfg, bar, idx)
-
- local f = self:GetFrame()
- local config = self:GetConfig()
-
- -- set up the bag ID pool
- self:SetActionIDPool("bag",6)
- config.bagID = self:AcquireActionID(config.bagID, idHint, true)
-
- -- non secure scripts
- f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
- f:SetScript("OnEnter", function(frame) self:OnEnter() end)
- f:SetScript("OnLeave", function(frame) self:OnLeave() end)
- f:SetScript("OnReceiveDrag", function(frame, ...) self:OnReceiveDrag(...) end)
- f:SetScript("OnClick", function(frame, ...) self:OnClick(...) end)
-
- -- secure handlers
- -- (none)
-
- -- event registration
- f:EnableMouse(true)
- f:RegisterForClicks("LeftButtonUp","RightButtonUp")
- f:RegisterEvent("UPDATE_BINDINGS")
-
- -- frame setup
- f:SetID(self:GetBagID())
-
- if not f.hotkey then
- local h = f:CreateFontString(name.."HotKey","ARTWORK","NumberFontNormalSmallGray")
- h:SetWidth(30)
- h:SetHeight(10)
- h:SetJustifyH("RIGHT")
- h:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
- h:Show()
- f.hotkey = h
- end
-
- if not _G[name.."ItemAnim"] then
- local anim = CreateFrame("Model",name.."ItemAnim",f,"ItemAnimTemplate")
- anim:SetPoint("BOTTOMRIGHT",f,"BOTTOMRIGHT",-10,0)
- anim:Hide()
- end
-
- if not f.border then
- local b = f:CreateTexture(name.."Border","OVERLAY")
- b:SetAllPoints()
- b:SetWidth(f:GetWidth()*(62/36))
- b:SetHeight(f:GetHeight()*(62/36))
- b:SetTexture("Interface\\Buttons\UI-ActionButton-Border")
- b:SetBlendMode("ADD")
- b:Hide()
- f.border = b
- end
-
- self.frames.count:SetDrawLayer("ARTWORK")
-
- self.frames.hotkey = f.hotkey
- self.frames.border = _G[name.."Border"]
- self.frames.icon = _G[name.."IconTexture"]
- self.frames.anim = _G[name.."ItemAnim"]
-
- -- initial display
- if ReAction:GetConfigMode() then
- self:GetFrame():Show()
- end
-
- self:Refresh()
-
- BagBase.allButtons[self] = true
-
- return self
-end
-
-function BagBase:Destroy()
- BagBase.allButtons[self] = nil
- Super.Destroy(self)
-end
-
-
-function BagBase:GetActionID()
- return self.config.bagID
-end
-
-function BagBase:GetBagID()
- return self:GetActionID() - 1
-end
-
-function BagBase:Refresh()
- Super.Refresh(self)
- self:UpdateHotkey()
- self:Update()
-end
-
-function BagBase:Update()
- self:UpdateChecked()
-end
-
-function BagBase:UpdateChecked(force)
- if force == nil then
- for i=1, NUM_CONTAINER_FRAMES do
- local c = _G["ContainerFrame"..i]
- if c:GetID() == self:GetBagID() and c:IsShown() then
- self:GetFrame():SetChecked(1)
- return
- end
- end
- self:GetFrame():SetChecked(0)
- end
- self:GetFrame():SetChecked(force)
-end
-
-function BagBase:OnEvent(evt, ...)
- if self[evt] then
- self[evt](self, ...)
- end
-end
-
-function BagBase:OnEnter()
- self:SetTooltip()
-end
-
-function BagBase:OnLeave()
- GameTooltip:Hide()
-end
-
-function BagBase:UPDATE_BINDINGS()
- self:UpdateHotkey()
-end
-
-function BagBase:IterateAllButtons()
- return pairs(self.allButtons)
-end
-
-
---
--- Bag Button class
---
-function Bag:New(name, cfg, bar, idx)
- self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
-
- local f = self:GetFrame()
-
- f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
-
- f:RegisterEvent("CURSOR_UPDATE")
- f:RegisterEvent("BAG_UPDATE")
- f:RegisterEvent("BAG_CLOSED")
- f:SetScript("OnDragStart", function(frame, ...) self:OnDragStart(...) end)
- f:RegisterForDrag("LeftButton")
-
- -- attach to skinner
- bar:SkinButton(self,
- {
- Icon = _G[name.."IconTexture"]
- }
- )
-
- return self
-end
-
-function Bag:GetInventorySlot()
- return ContainerIDToInventoryID(self:GetBagID())
-end
-
-function Bag:GetInventorySlotName()
- return "Bag"..(self:GetBagID()-1).."Slot"
-end
-
-function Bag:SetTooltip()
- GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
- if not GameTooltip:SetInventoryItem("player", self:GetInventorySlot()) then
- GameTooltip:SetText(EQUIP_CONTAINER, 1.0, 1.0, 1.0)
- end
-end
-
-function Bag:Update()
- local texture = GetInventoryItemTexture("player", self:GetInventorySlot())
- if texture then
- self.frames.icon:SetTexture(texture)
- self.frames.icon:Show()
- self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
- else
- local _, bgTex = GetInventorySlotInfo(self:GetInventorySlotName())
- self.frames.icon:SetTexture(bgTex)
- self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
- end
- self:UpdateChecked()
-end
-
-function Bag:OnClick()
- if IsModifiedClick("OPENALLBAGS") then
- OpenAllBags()
- else
- if not PutItemInBag(self:GetInventorySlot()) then
- ToggleBag(self:GetBagID())
- end
- end
- self:UpdateChecked()
-end
-
-function Bag:OnReceiveDrag()
- if CursorHasItem() then
- PutItemInBag(self:GetInventorySlot())
- end
-end
-
-function Bag:OnDragStart()
- PickupBagFromSlot(self:GetInventorySlot())
- self:Update()
-end
-
-function Bag:BAG_UPDATE(bag)
- if bag == self:GetBagID() then
- self:Update()
- end
-end
-
-function Bag:CURSOR_UPDATE()
- if CursorCanGoInSlot(self:GetInventorySlot()) then
- self:GetFrame():LockHighlight()
- else
- self:GetFrame():UnlockHighlight()
- end
-end
-
-function Bag:BAG_CLOSED(bag)
- if bag == self:GetBagID() then
- self:Update()
- end
-end
-
-
---
--- Backpack Button class
---
-function Backpack:New(name, cfg, bar, idx)
- self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
-
- local f = self:GetFrame()
- local icon = _G[name.."IconTexture"]
- icon:SetTexture("Interface\\Buttons\\Button-Backpack-Up")
- icon:Show()
- f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
- f:RegisterEvent("PLAYER_ENTERING_WORLD");
- f:RegisterEvent("CVAR_UPDATE");
- f:SetScript("OnShow", function(frame, ...) self:OnShow(...) end)
-
- -- attach to skinner
- bar:SkinButton(self,
- {
- Icon = _G[name.."IconTexture"]
- }
- )
-
- return self
-end
-
-function Backpack:Update()
- self:UpdateFreeSlots()
- self:UpdateChecked()
-end
-
-function Backpack:UpdateFreeSlots()
- if GetCVar("displayFreeBagSlots") == "1" then
- local total = 0
- for i = BACKPACK_CONTAINER, NUM_BAG_SLOTS do
- local free, family = GetContainerNumFreeSlots(i)
- if family == 0 then
- total = total + free
- end
- end
-
- self.freeSlots = total
- self.frames.count:SetText(format("(%s)", self.freeSlots))
- self.frames.count:Show()
- elseif self.frames.count:IsShown() then
- self.frames.count:Hide()
- end
-end
-
-function Backpack:SetTooltip()
- GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
- GameTooltip:SetText(BACKPACK_TOOLTIP, 1.0, 1.0, 1.0)
- GameTooltip:AddLine(string.format(NUM_FREE_SLOTS, (self.freeSlots or 0)))
- GameTooltip:Show();
-end
-
-function Backpack:OnShow()
- self:UpdateFreeSlots()
-end
-
-function Backpack:OnClick()
- if IsModifiedClick("OPENALLBAGS") then
- OpenAllBags()
- else
- if not PutItemInBackpack() then
- ToggleBackpack()
- end
- end
- self:UpdateChecked()
-end
-
-function Backpack:OnReceiveDrag()
- if CursorHasItem() then
- PutItemInBackpack()
- end
-end
-
-function Backpack:PLAYER_ENTERING_WORLD()
- self:CVAR_UPDATE("DISPLAY_FREE_BAG_SLOTS", GetCVar("displayFreeBagSlots"))
-end
-
-function Backpack:CVAR_UPDATE( cvar, value )
- if cvar == "DISPLAY_FREE_BAG_SLOTS" then
- if value == "1" then
- self:GetFrame():RegisterEvent("BAG_UPDATE")
- else
- self:GetFrame():UnregisterEvent("BAG_UPDATE")
- end
- self:UpdateFreeSlots()
- end
-end
-
-function Backpack:BAG_UPDATE(bag)
- if bag >= BACKPACK_CONTAINER and bag <= NUM_BAG_SLOTS then
- self:UpdateFreeSlots()
- end
-end
-
-
---
--- Keyring Button class
---
-function Keyring:New(name, cfg, bar, idx)
- self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
-
- local f = self:GetFrame()
-
- f:SetWidth(18)
- f:SetHeight(39)
-
- local tex = f:GetNormalTexture()
- tex:ClearAllPoints()
- tex:SetAllPoints()
-
- f:SetNormalTexture("Interface\\Buttons\\UI-Button-KeyRing")
- f:SetHighlightTexture("Interface\\Buttons\\UI-Button-KeyRing-Highlight")
- f:SetPushedTexture("Interface\\Buttons\\UI-Button-KeyRing-Down")
- f:GetNormalTexture():SetTexCoord(0,0.5625,0,0.609375)
- f:GetHighlightTexture():SetTexCoord(0,0.5625,0,0.609375)
- f:GetPushedTexture():SetTexCoord(0,0.5625,0,0.609375)
-
- if not HasKey() then
- f:Hide()
- end
-
- -- DO NOT attach to skinner
-
- return self
-end
-
-function Keyring:GetBagID()
- return KEYRING_CONTAINER
-end
-
-function Keyring:Refresh()
- local f = self:GetFrame()
- self.bar:PlaceButton( self, f:GetHeight(), f:GetHeight() ) -- use height x height since it's an odd size
- self:UpdateHotkey()
- self:Update()
-end
-
-function Keyring:SetTooltip()
- GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT");
- GameTooltip:SetText(KEYRING, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
- GameTooltip:AddLine();
-end
-
-function Keyring:OnReceiveDrag()
- if CursorHasItem() then
- PutKeyInKeyRing()
- end
-end
-
-function Keyring:OnClick()
- if CursorHasItem() then
- PutKeyInKeyRing()
- else
- ToggleKeyRing()
- end
- self:UpdateChecked()
-end
-
-function Keyring:ShowGridTemp(show)
- if not HasKey() then
- if show then
- self:GetFrame():Show()
- else
- self:GetFrame():Hide()
- end
- end
-end
-
-
-
--- hook some functions to propagate to our bag buttons
-hooksecurefunc("Disable_BagButtons",
- function()
- for b in BagBase:IterateAllButtons() do
- local f = b:GetFrame()
- f:Disable()
- SetDesaturation(b.frames.icon,1)
- end
- end)
-
-hooksecurefunc("Enable_BagButtons",
- function()
- for b in BagBase:IterateAllButtons() do
- local f = b:GetFrame()
- f:Enable()
- SetDesaturation(b.frames.icon,nil)
- end
- end)
-
-hooksecurefunc("ContainerFrame_OnHide",
- function()
- for b in BagBase:IterateAllButtons() do
- b:Update()
- end
- end)
-
-hooksecurefunc("ContainerFrame_OnShow",
- function()
- for b in BagBase:IterateAllButtons() do
- b:Update()
- end
- end)
diff -r f255cd69e890 -r 65f2805957a0 classes/Bar.lua
--- a/classes/Bar.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,854 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local LKB = ReAction.LKB
-local _G = _G
-local CreateFrame = CreateFrame
-local floor = math.floor
-local fmod = math.fmod
-local format = string.format
-local tfetch = addonTable.tfetch
-local tbuild = addonTable.tbuild
-local fieldsort = addonTable.fieldsort
-
-local LSG = LibStub("ReAction-LibShowActionGrid-1.0")
-
----- Secure snippets ----
-local _reaction_init =
-[[
- anchorKeys = newtable("point","relPoint","x","y")
-
- state = nil
- set_state = nil
- state_override = nil
- unit_exists = nil
-
- showAll = false
- hidden = false
-
- defaultAlpha = 1.0
- defaultScale = 1.0
- defaultAnchor = newtable()
-
- activeStates = newtable()
- settings = newtable()
- extensions = newtable()
-]]
-
-local _reaction_refresh =
-[[
- local oldState = state
- state = state_override or set_state or state
-
- local hide = nil
- if state then
- local settings = settings[state]
- if settings then
- -- show/hide
- hide = settings.hide
- -- re-anchor
- local old_anchor = activeStates.anchor
- activeStates.anchor = settings.anchorEnable and state
- if old_anchor ~= activeStates.anchor or not set_state then
- if activeStates.anchor then
- if settings.anchorPoint then
- self:ClearAllPoints()
- local f = self:GetAttribute("frameref-anchor-"..state)
- if f then
- self:SetPoint(settings.anchorPoint, f, settings.anchorRelPoint, settings.anchorX, settings.anchorY)
- end
- end
- elseif defaultAnchor.point then
- self:ClearAllPoints()
- self:SetPoint(defaultAnchor.point, defaultAnchor.frame,
- defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
- end
- end
- -- re-scale
- local old_scale = activeStates.scale
- activeStates.scale = settings.enableScale and state
- if old_scale ~= activeStates.scale or not set_state then
- self:SetScale(activeStates.scale and settings.scale or defaultScale)
- end
- -- alpha
- local old_alpha = activeStates.alpha
- activeStates.alpha = settings.enableAlpha and state
- if old_alpha ~= activeStates.alpha or not set_state then
- self:SetAlpha(activeStates.alpha and settings.alpha or defaultAlpha)
- end
- end
- end
-
- -- hide if state or unit_exists says to
- hide = not showAll and (hide or unithide)
- if hide ~= hidden then
- hidden = hide
- if hide then
- self:Hide()
- else
- self:Show()
- end
- end
-
- for _, attr in pairs(extensions) do
- control:RunAttribute(attr)
- end
-
- control:ChildUpdate()
-
- if showAll then
- control:CallMethod("UpdateHiddenLabel", state and settings[state] and settings[state].hide)
- end
-
- if oldState ~= state then
- control:CallMethod("StateRefresh", state)
- end
-]]
-
-local _onstate_reaction = -- function( self, stateid, newstate )
-[[
- set_state = newstate
-]] .. _reaction_refresh
-
-local _onstate_showgrid = -- function( self, stateid, newstate )
-[[
- control:ChildUpdate(stateid,newstate)
- control:CallMethod("UpdateShowGrid")
-]]
-
-local _onstate_unitexists = -- function( self, stateid, newstate )
-[[
- unithide = not newstate or newstate == "hide"
-]] .. _reaction_refresh
-
-local _onclick = -- function( self, button, down )
-[[
- if state_override == button then
- state_override = nil -- toggle
- else
- state_override = button
- end
-]] .. _reaction_refresh
-
--- For reference
--- the option field names must match the field names of the options table, below
-local stateProperties = {
- hide = true,
- --keybindState = true, TODO: broken
- anchorEnable = true,
- anchorFrame = true,
- anchorPoint = true,
- anchorRelPoint = true,
- anchorX = true,
- anchorY = true,
- enableScale = true,
- scale = true,
- enableAlpha = true,
- alpha = true,
-}
-
-
-
----- Bar class ----
-local Bar = { }
-local frameList = { }
-
-ReAction.Bar = Bar -- export to ReAction
-
-function Bar:New( name, config, buttonClass )
- if type(config) ~= "table" then
- error("ReAction.Bar: config table required")
- end
-
- -- create new self
- self = setmetatable(
- {
- config = config,
- name = name,
- buttons = { },
- buttonClass = buttonClass,
- width = config.width or 480,
- height = config.height or 40,
- },
- {__index = self} )
-
- -- The frame type is 'Button' in order to have an OnClick handler. However, the frame itself is
- -- not mouse-clickable by the user.
- local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
- name = name and "ReAction-"..name
- local f = name and frameList[name]
- if not f then
- f = CreateFrame("Button", name, parent, "SecureHandlerStateTemplate, SecureHandlerClickTemplate")
- if name then
- frameList[name] = f
- end
- end
- f:SetFrameStrata("MEDIUM")
- f:SetWidth(self.width)
- f:SetHeight(self.height)
- f:SetAlpha(config.alpha or 1.0)
- f:Show()
- f:EnableMouse(false)
- f:SetClampedToScreen(true)
- LSG:AddFrame(f)
-
- -- secure handlers
- f:Execute(_reaction_init)
- f:SetAttribute("_onstate-reaction", _onstate_reaction)
- f:SetAttribute("_onstate-showgrid", _onstate_showgrid)
- f:SetAttribute("_onstate-unitexists", _onstate_unitexists)
- f:SetAttribute("_onclick", _onclick)
-
- -- secure handler CallMethod()s
- f.UpdateShowGrid = function() self:UpdateShowGrid() end
- f.StateRefresh = function() self:RefreshControls() end
- f.UpdateHiddenLabel = function(f,hidden) self:SetLabelSubtext(hidden and L["Hidden"]) end
-
- -- Override the default frame accessor to provide strict read-only access
- function self:GetFrame()
- return f
- end
-
- self:ApplyAnchor()
- self:SetConfigMode(ReAction:GetConfigMode())
- self:SetKeybindMode(ReAction:GetKeybindMode())
-
- if ReAction.LBF then
- local g = ReAction.LBF:Group(L["ReAction"], self.name)
- self.config.ButtonFacade = self.config.ButtonFacade or {
- skinID = "Blizzard",
- backdrop = true,
- gloss = 0,
- colors = {},
- }
- local c = self.config.ButtonFacade
- g:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
- self.LBFGroup = g
- end
-
- ReAction.RegisterCallback(self, "OnConfigModeChanged")
-
- buttonClass:SetupBar(self)
- self:ApplyStates()
-
- return self
-end
-
-function Bar:Destroy()
- local f = self:GetFrame()
- self:CleanupStates()
- for idx, b in self:IterateButtons() do
- b:Destroy()
- end
- f:UnregisterAllEvents()
- self:ShowControls(false)
- ReAction.UnregisterAllCallbacks(self)
- LKB.UnregisterAllCallbacks(self)
- if self.LBFGroup then
- self.LBFGroup:Delete(true)
- end
- LSG:RemoveFrame(f)
- f:SetParent(UIParent)
- f:ClearAllPoints()
- f:Hide()
-end
-
---
--- Events
---
-
-function Bar:OnConfigModeChanged(event, mode)
- self:SetConfigMode(mode)
-end
-
---
--- Accessors
---
-
-function Bar:GetName()
- return self.name
-end
-
--- only ReAction:RenameBar() should call this function. Calling from any other
--- context will desync the bar list in the ReAction class.
-function Bar:SetName(name)
- if self.LBFGroup then
- -- LBF doesn't offer a method of renaming a group, so delete and remake the group.
- local c = self.config.ButtonFacade
- local g = ReAction.LBF:Group(L["ReAction"], name)
- for idx, b in self:IterateButtons() do
- self.LBFGroup:RemoveButton(b:GetFrame(), true)
- g:AddButton(b:GetFrame())
- end
- self.LBFGroup:Delete(true)
- self.LBFGroup = g
- self.LBFGroup:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
- end
- self.name = name
- if self.overlay then
- self.overlay:SetLabel(self.name)
- end
-end
-
-function Bar:GetFrame()
- -- this method is included for documentation purposes. It is overridden
- -- for each object in the :New() method.
- error("Invalid Bar object: used without initialization")
-end
-
-function Bar:GetButton(idx)
- return self.buttons[idx]
-end
-
-function Bar:GetButtonClass()
- return self.buttonClass
-end
-
-function Bar:GetConfig()
- return self.config
-end
-
-function Bar:GetAnchor()
- local c = self.config
- return (c.point or "CENTER"),
- (c.anchor or self:GetFrame():GetParent():GetName()),
- (c.relpoint or c.point or "CENTER"),
- (c.x or 0),
- (c.y or 0)
-end
-
-function Bar:SetAnchor(point, frame, relativePoint, x, y)
- local c = self.config
- c.point = point or c.point
- c.anchor = frame or c.anchor
- c.relpoint = relativePoint or c.relpoint
- c.x = x or c.x
- c.y = y or c.y
- self:ApplyAnchor()
-end
-
-function Bar:GetSize()
- local f = self:GetFrame()
- return f:GetWidth(), f:GetHeight()
-end
-
-function Bar:SetSize(w,h)
- local f = self:GetFrame()
- self.config.width = w
- self.config.height = h
- f:SetWidth(w)
- f:SetHeight(h)
-end
-
-function Bar:GetButtonSize()
- local w = self.config.btnWidth or 32
- local h = self.config.btnHeight or 32
- -- TODO: get from modules?
- return w,h
-end
-
-function Bar:SetButtonSize(w,h)
- if w > 0 and h > 0 then
- self.config.btnWidth = w
- self.config.btnHeight = h
- end
-end
-
-function Bar:GetNumButtons()
- local r,c = self:GetButtonGrid()
- return r*c
-end
-
-function Bar:GetButtonGrid()
- local cfg = self.config
- local r = cfg.btnRows or 1
- local c = cfg.btnColumns or 1
- local s = cfg.spacing or 4
- return r,c,s
-end
-
-function Bar:SetButtonGrid(r,c,s)
- if r > 0 and c > 0 and s > 0 then
- local cfg = self.config
- cfg.btnRows = r
- cfg.btnColumns = c
- cfg.spacing = s
- end
- self.buttonClass:SetupBar(self)
-end
-
-function Bar:GetAlpha()
- return self.config.alpha or 1.0
-end
-
-function Bar:SetAlpha(value)
- self.config.alpha = value
- self:GetFrame():SetAlpha(value or 1.0)
- self:UpdateDefaultStateAlpha()
-end
-
-function Bar:IterateButtons()
- -- iterator returns idx, button, but does NOT iterate in index order
- return pairs(self.buttons)
-end
-
---
--- Methods
---
-
-function Bar:SetConfigMode(mode)
- self:SetSecureData("showAll",mode)
- self:ShowControls(mode)
- for idx, b in self:IterateButtons() do
- b:ShowGridTemp(mode)
- b:UpdateActionIDLabel(mode)
- end
-end
-
-function Bar:SetKeybindMode(mode)
- self:SetSecureData("showAll",mode)
- for idx, b in self:IterateButtons() do
- b:SetKeybindMode(mode)
- end
-end
-
-function Bar:ApplyAnchor()
- local f = self:GetFrame()
- local c = self.config
- local p = c.point
-
- f:SetWidth(c.width)
- f:SetHeight(c.height)
- f:ClearAllPoints()
-
- if p then
- local a = f:GetParent()
- if c.anchor then
- local bar = ReAction:GetBar(c.anchor)
- if bar then
- a = bar:GetFrame()
- else
- a = _G[c.anchor]
- end
- end
- local fr = a or f:GetParent()
- f:SetPoint(p, a or f:GetParent(), c.relpoint, c.x or 0, c.y or 0)
- else
- f:SetPoint("CENTER")
- end
-
- self:UpdateDefaultStateAnchor()
-end
-
-function Bar:ClipNButtons( n )
- local cfg = self.config
- local r = cfg.btnRows or 1
- local c = cfg.btnColumns or 1
-
- cfg.btnRows = ceil(n/c)
- cfg.btnColumns = min(n,c)
-end
-
-function Bar:AddButton(idx, button)
- local f = self:GetFrame()
-
- self.buttons[idx] = button
-
- -- Store a properly wrapped reference to the child frame as an attribute
- -- (accessible via "frameref-btn#")
- f:SetFrameRef(format("btn%d",idx), button:GetFrame())
-
- -- button constructors are responsible for calling SkinButton
-end
-
-function Bar:RemoveButton(button)
- local idx = button:GetIndex()
- if idx then
- self:GetFrame():SetAttribute(format("frameref-btn%d",idx),nil)
- self.buttons[idx] = nil
- end
- if self.LBFGroup then
- self.LBFGroup:RemoveButton(button:GetFrame(),true)
- end
-end
-
-function Bar:PlaceButton(button, baseW, baseH)
- local idx = button:GetIndex()
- if idx then
- local r, c, s = self:GetButtonGrid()
- local bh, bw = self:GetButtonSize()
- local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
- local x, y = col*bw + (col+0.5)*s, -(row*bh + (row+0.5)*s)
- local scale = bw/baseW
- local b = button:GetFrame()
-
- b:ClearAllPoints()
- b:SetPoint("TOPLEFT",x/scale,y/scale)
- b:SetScale(scale)
- end
-end
-
-function Bar:SkinButton( button, data )
- if self.LBFGroup then
- self.LBFGroup:AddButton(button:GetFrame(), data)
- end
-end
-
-function Bar:UpdateShowGrid()
- for idx, button in self:IterateButtons() do
- button:UpdateShowGrid()
- end
-end
-
-function Bar:ShowControls(show)
- if show then
- if not self.overlay then
- self.overlay = Bar.Overlay:New(self) -- see Overlay.lua
- end
- self.overlay:Show()
- self:RefreshSecureState()
- elseif self.overlay then
- self.overlay:Hide()
- end
-end
-
-function Bar:RefreshControls()
- if self.overlay and self.overlay:IsShown() then
- self.overlay:RefreshControls()
- end
-end
-
-function Bar:SetLabelSubtext(text)
- if self.overlay then
- self.overlay:SetLabelSubtext(text)
- end
-end
-
---
--- Secure state functions
---
-
-function Bar:GetSecureState()
- local env = GetManagedEnvironment(self:GetFrame())
- return env and env.state
-end
-
-function Bar:GetStateProperty(state, propname)
- return tfetch(self:GetConfig(), "states", state, propname)
-end
-
-function Bar:SetStateProperty(state, propname, value)
- local s = tbuild(self:GetConfig(), "states", state)
- s[propname] = value
- self:SetSecureStateData(state, propname, value)
-end
-
-function Bar:ApplyStates()
- local states = tfetch(self:GetConfig(), "states")
- if states then
- self:SetStateDriver(states)
- end
-end
-
-function Bar:CleanupStates()
- self:SetStateDriver(nil)
-end
-
-function Bar:RefreshSecureState()
- self:GetFrame():Execute(_reaction_refresh)
-end
-
--- usage: SetSecureData(globalname, [tblkey1, tblkey2, ...], value)
-function Bar:SetSecureData( ... )
- local n = select('#',...)
- if n < 2 then
- error("ReAction.Bar:SetSecureData() requires at least 2 arguments")
- end
- local f = self:GetFrame()
- f:SetAttribute("data-depth",n-1)
- f:SetAttribute("data-value",select(n,...))
- for i = 1, n-1 do
- local key = select(i,...)
- if key == nil then
- error("ReAction.Bar:SetSecureData() - nil table key in argument list (#"..i..")")
- end
- f:SetAttribute("data-key-"..i, key)
- end
- f:Execute(
- [[
- local n = self:GetAttribute("data-depth")
- if n > 0 then
- local value = self:GetAttribute("data-value")
- local t = _G
- for i = 1, n do
- local key = self:GetAttribute("data-key-"..i)
- if not key then return end
- if not t[key] then
- t[key] = newtable()
- end
- if i == n then
- t[key] = value
- else
- t = t[key]
- end
- end
- end
- ]])
- self:RefreshSecureState()
-end
-
-function Bar:SetSecureStateData( state, key, value )
- self:SetSecureData("settings",state,key,value)
-end
-
--- sets a snippet to be run as an extension to _onstate-reaction
-function Bar:SetSecureStateExtension( id, snippet )
- if id == nil then
- error("ReAction.Bar:SetSecureStateExtension() requires an id")
- end
- local f = self:GetFrame()
- f:SetAttribute("input-secure-ext-id",id)
- f:SetAttribute("secure-ext-"..id,snippet)
- f:Execute(
- [[
- local id = self:GetAttribute("input-secure-ext-id")
- if id then
- extensions[id] = self:GetAttribute("secure-ext-"..id) or nil
- end
- ]])
- self:RefreshSecureState()
-end
-
-function Bar:SetFrameRef( name, refFrame )
- if refFrame then
- local _, explicit = refFrame:IsProtected()
- if not explicit then
- refFrame = nil
- end
- end
- if refFrame then
- self:GetFrame():SetFrameRef(name,refFrame)
- else
- self:GetFrame():SetAttribute("frameref-"..name,nil)
- end
-end
-
-function Bar:SetStateDriver( states )
- if states then
- for state, props in pairs(states) do
- self:SetSecureStateData(state, "active_", true) -- make sure there's a 'settings' field for this state
- for propname, value in pairs(props) do
- if propname == "anchorFrame" then
- self:SetFrameRef("anchor-"..state, _G[value])
- elseif propname == "rule" then
- -- do nothing
- else
- self:SetSecureStateData(state, propname, value)
- end
- end
- end
- end
- local rule = states and self:BuildStateRule(states)
- if rule then
- RegisterStateDriver(self:GetFrame(),"reaction",rule)
- elseif self.statedriver then
- UnregisterStateDriver(self:GetFrame(),"reaction")
- end
- self.statedriver = rule
- self:BuildStateKeybinds(states)
- self:RefreshSecureState()
-end
-
--- pass unit=nil to set up the unit elsewhere, if you want something more complex
-function Bar:RegisterUnitWatch( unit, enable )
- local f = self:GetFrame()
- if unit then
- f:SetAttribute("unit",unit)
- end
- if enable then
- if not self.unitwatch then
- RegisterUnitWatch(self:GetFrame(),true)
- end
- elseif self.unitwatch then
- UnregisterUnitWatch(self:GetFrame())
- end
- self.unitwatch = enable
- self:RefreshSecureState()
-end
-
-function Bar:SetStateKeybind( key, state )
- local f = self:GetFrame()
- local binds = self.statebinds
- if not binds then
- binds = { }
- self.statebinds = binds
- end
-
- -- clear the old binding, if any
- if binds[state] then
- SetOverrideBinding(f, false, binds[state], nil)
- end
-
- if key then
- SetOverrideBindingClick(f, false, key, f:GetName(), state) -- state name is virtual mouse button
- end
- binds[state] = key
-end
-
-function Bar:GetStateKeybind( state )
- if self.statebinds and state then
- return self.statebinds[state]
- end
-end
-
-function Bar:UpdateDefaultStateAnchor()
- local point, frame, relPoint, x, y = self:GetAnchor()
- local f = self:GetFrame()
- f:SetAttribute("defaultAnchor-point",point)
- f:SetAttribute("defaultAnchor-relPoint",relPoint)
- f:SetAttribute("defaultAnchor-x",x)
- f:SetAttribute("defaultAnchor-y",y)
- self:SetFrameRef("defaultAnchor",_G[frame or "UIParent"])
- f:Execute([[
- for _, k in pairs(anchorKeys) do
- defaultAnchor[k] = self:GetAttribute("defaultAnchor-"..k)
- end
- defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
- ]])
-end
-
-function Bar:UpdateDefaultStateAlpha()
- local f = self:GetFrame()
- f:SetAttribute("defaultAlpha",self:GetAlpha())
- f:Execute([[
- defaultAlpha = self:GetAttribute("defaultAlpha")
- ]])
-end
-
----- secure state driver rules ----
-
-local playerClass = select(2, UnitClass("player"))
-local function ClassFilter(...)
- for i = 1, select('#',...) do
- if playerClass == select(i,...) then
- return false
- end
- end
- return true
-end
-
-local ruleformats = {
- stealth = { format = "stealth", filter = ClassFilter("ROGUE","DRUID") },
- nostealth = { format = "nostealth", filter = ClassFilter("ROGUE","DRUID") },
- shadowdance = { format = "bonusbar:2", filter = ClassFilter("ROGUE") },
- shadowform = { format = "form:1", filter = ClassFilter("PRIEST") },
- noshadowform = { format = "noform", filter = ClassFilter("PRIEST") },
- battle = { format = "stance:1", filter = ClassFilter("WARRIOR") },
- defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") },
- berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") },
- caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") },
- bear = { format = "form:1", filter = ClassFilter("DRUID") },
- cat = { format = "form:3", filter = ClassFilter("DRUID") },
- tree = { format = "form:5", filter = ClassFilter("DRUID") },
- moonkin = { format = "form:5", filter = ClassFilter("DRUID") },
- demon = { format = "form:2", filter = ClassFilter("WARLOCK") },
- nodemon = { format = "noform", filter = ClassFilter("WARLOCK") },
- pet = { format = "pet" },
- nopet = { format = "nopet" },
- harm = { format = "@target,harm" },
- help = { format = "@target,help" },
- notarget = { format = "@target,noexists" },
- focusharm = { format = "@focus,harm" },
- focushelp = { format = "@focus,help" },
- nofocus = { format = "@focus,noexists" },
- raid = { format = "group:raid" },
- party = { format = "group:party" },
- solo = { format = "nogroup" },
- combat = { format = "combat" },
- nocombat = { format = "nocombat" },
- possess = { format = "@vehicle,noexists,bonusbar:5" },
- vehicle = { format = "@vehicle,exists,bonusbar:5" },
-}
-
-function Bar.InitRuleFormats()
- local forms = { }
- for i = 1, GetNumShapeshiftForms() do
- local _, name = GetShapeshiftFormInfo(i)
- forms[name] = i;
- end
- -- use 9 if not found since 9 is never a valid stance/form
- local defensive = forms[GetSpellInfo(71)] or 9
- local berserker = forms[GetSpellInfo(2458)] or 9
- local bear = forms[GetSpellInfo(5487)] or 9
- local aquatic = forms[GetSpellInfo(1066)] or 9
- local cat = forms[GetSpellInfo(768)] or 9
- local travel = forms[GetSpellInfo(783)] or 9
- local tree = forms[GetSpellInfo(33891)] or 9
- local moonkin = forms[GetSpellInfo(24858)] or 9
- local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9
-
- ruleformats.defensive.format = "stance:"..defensive
- ruleformats.berserker.format = "stance:"..berserker
- ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight)
- ruleformats.bear.format = "form:"..bear
- ruleformats.cat.format = "form:"..cat
- ruleformats.tree.format = "form:"..tree
- ruleformats.moonkin.format = "form:"..moonkin
-end
-
-function Bar:BuildStateRule(states)
- -- states is a table :
- -- states[statename].rule = {
- -- order = #,
- -- type = "default"/"custom"/"any"/"all",
- -- values = { ... }, -- keys of ruleformats[]
- -- custom = "...",
- -- }
- local rules = { }
- local default
-
- for idx, state in ipairs(fieldsort(states, "rule", "order")) do
- local c = states[state].rule
- local type = c.type
- if type == "default" then
- default = default or state
- elseif type == "custom" then
- if c.custom then
- -- strip out all spaces from the custom rule
- table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state))
- end
- elseif type == "any" or type == "all" then
- if c.values then
- local clauses = { }
- for key, value in pairs(c.values) do
- if ruleformats[key] and not ruleformats[key].filter then
- table.insert(clauses, ruleformats[key].format)
- end
- end
- if #clauses > 0 then
- local sep = (type == "any") and "][" or ","
- table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state))
- end
- end
- end
- end
- -- make sure that the default, if any, is last
- if default then
- table.insert(rules, default)
- end
- return table.concat(rules,";")
-end
-
-function Bar:BuildStateKeybinds( states )
- if states then
- for name, state in pairs(states) do
- local rule = tfetch(state, "rule")
- if rule and rule.type == "keybind" then
- self:SetStateKeybind(rule.keybind, name)
- else
- self:SetStateKeybind(nil, name) -- this clears an existing keybind
- end
- end
- end
-end
-
diff -r f255cd69e890 -r 65f2805957a0 classes/Button.lua
--- a/classes/Button.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,359 +0,0 @@
---[[
- ReAction Button base class
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local LKB = ReAction.LKB
-local _G = _G
-local CreateFrame = CreateFrame
-local GetBindingKey = GetBindingKey
-local format = string.format
-
--- private
-local trash = CreateFrame("Frame")
-local frameList = { }
-local idPools = { }
-
-local function kb_onEnter( frame )
- LKB:Set(frame)
-end
-
--- Button class
-local buttonTypeID = "Button"
-local Button = {
- defaultBarConfig = {
- type = buttonTypeID,
- btnWidth = 36,
- btnHeight = 36,
- btnRows = 1,
- btnColumns = 12,
- spacing = 3
- },
- barType = L["Button Bar"]
-}
-
-ReAction.Button = Button -- export to ReAction
-
-function Button:New( name, config, bar, idx, inherits, buttonType )
- buttonType = buttonType or "CheckButton"
-
- -- create new self
- self = setmetatable(
- {
- bar = bar,
- idx = idx,
- config = config,
- name = name,
- },
- { __index = self } )
-
- -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
- -- existing globals. Can't set to nil in the global because it's then tainted.
- -- Caller is responsible for ensuring global uniqueness of names.
- local f = name and frameList[name]
- if f then
- f:SetParent(bar:GetFrame())
- else
- f = CreateFrame(buttonType, name, bar:GetFrame(), inherits)
- if name then
- frameList[name] = f
- end
- end
-
- self.frame = f
-
- local frames = { }
- self.frames = frames
- frames.icon = _G[name.."Icon"]
- frames.flash = _G[name.."Flash"]
- frames.hotkey = _G[name.."HotKey"]
- frames.count = _G[name.."Count"]
- frames.name = _G[name.."Name"]
- frames.border = _G[name.."Border"]
- frames.cooldown = _G[name.."Cooldown"]
- frames.normalTexture = _G[name.."NormalTexture"]
-
- if config then
- config.name = name
- end
-
- -- install LibKeyBound handlers onto frame
- function f:GetActionName()
- return format("%s:%s", bar:GetName(), idx)
- end
-
- local clickBinding = format("CLICK %s:LeftButton", name)
- function f:GetHotkey()
- return LKB:ToShortKey(GetBindingKey(clickBinding))
- end
-
- return self
-end
-
-function Button:Destroy()
- local f = self:GetFrame()
- f:UnregisterAllEvents()
- self:ReleaseActionID(self:GetActionID())
- if f then
- f:Hide()
- f:SetParent(trash)
- f:ClearAllPoints()
- end
-end
-
-function Button:GetBar()
- return self.bar
-end
-
-function Button:GetFrame()
- return self.frame
-end
-
-function Button:GetIndex()
- return self.idx
-end
-
-function Button:GetName()
- return self.name
-end
-
-function Button:GetDefaultBarConfig()
- return self.defaultBarConfig
-end
-
-function Button:GetBarType()
- return self.barType
-end
-
-function Button:GetButtonTypeID()
- return self.buttonTypeID
-end
-
-function Button:GetConfig()
- return self.config
-end
-
-function Button:GetActionID()
- -- derived classes should override this
- return nil
-end
-
-function Button:SetActionIDPool( poolID, maxID )
- self.actionPoolID = poolID
- self.actionMaxID = maxID
-end
-
-function Button:SetupBar( bar )
- local config = bar:GetConfig()
- if not config.buttons then
- config.buttons = { }
- end
- local btnCfg = config.buttons
-
- local r, c = bar:GetButtonGrid()
- local n = r*c
- local cfgN = n
-
- local hint = nil
- local i = 1
- repeat
- local b = bar:GetButton(i)
- if b then
- if i > n then
- bar:RemoveButton(b)
- b:Destroy()
- if i > cfgN then
- btnCfg[i] = nil
- end
- else
- b:Refresh()
- hint = b:GetActionID()
- end
- elseif i <= n then
- local cfg = btnCfg[i] or { }
- local success, r = pcall(self.New, self, cfg, bar, i, hint) -- note call semantics for derived class constructors
- if success and r then
- b = r
- bar:AddButton(i,b)
- btnCfg[i] = cfg
- b:Refresh()
- hint = b:GetActionID()
- else
- n = i - 1
- if not success then
- bar:ClipNButtons(n)
- cfgN = n
- geterrorhandler()(r)
- end
- end
- end
- i = i + 1
- until b == nil
-end
-
-function Button:AcquireActionID( id, hint, unique )
- local poolID = self.actionPoolID
- local maxID = self.actionMaxID
- if not poolID or not maxID then
- error("AcquireActionID: must setup pool first with SetActionIDPool")
- end
- local pool = idPools[poolID]
- if not pool then
- pool = { nWraps = 0, useCount = { } }
- for i = 1, maxID do
- pool.useCount[i] = 0
- end
- idPools[poolID] = pool
- end
- local useCount = pool.useCount
- if id == nil then
- repeat
- local nWraps = pool.nWraps or 0
- if hint and (useCount[hint] == nil or useCount[hint] == nWraps) then
- id = hint
- else
- local start = hint or 1
- for i = start, maxID do
- if useCount[i] == nil or useCount[i] == nWraps then
- id = i
- break
- end
- end
- if not id then
- for i = 1, start do
- if useCount[i] == nil or useCount[i] == nWraps then
- id = i
- break
- end
- end
- end
- end
- if id == nil then
- if unique then
- return nil
- end
- pool.nWraps = nWraps + 1
- end
- until id ~= nil
- end
- useCount[id] = (useCount[id] or 0) + 1
- return id
-end
-
-function Button:ReleaseActionID( id )
- local poolID = self.actionPoolID
- if not poolID then
- error("ReleaseActionID: must setup pool first with SetActionIDPool")
- end
- local pool = idPools[poolID]
- if pool and id and pool.useCount[id] then
- pool.useCount[id] = pool.useCount[id] - 1
- pool.nWraps = min(pool.useCount[id], pool.nWraps)
- end
-end
-
-function Button:Refresh()
- local f = self:GetFrame()
- self.bar:PlaceButton( self, f:GetWidth(), f:GetHeight() )
-end
-
-function Button:SetKeybindMode( mode )
- local f = self.frame
- if mode then
- self.oldOnEnter = f:GetScript("OnEnter")
- f:SetScript("OnEnter", kb_onEnter)
- elseif self.oldOnEnter then
- f:SetScript("OnEnter", self.oldOnEnter)
- self.oldOnEnter = nil
- end
- self:ShowGridTemp(mode)
- self:UpdateKeybindModeDisplay( mode )
-end
-
-function Button:UpdateKeybindModeDisplay( mode )
- local border = self.frames.border or _G[format("%sBorder",tostring(self:GetName()))]
- if border then
- if mode then
- border:SetVertexColor(LKB:GetColorKeyBoundMode())
- border:Show()
- else
- border:Hide()
- end
- end
-end
-
-function Button:UpdateHotkey( hotkey )
- hotkey = hotkey or self.frames.hotkey
- if not hotkey then
- hotkey = _G[self:GetName().."HotKey"]
- self.frames.hotkey = hotkey
- end
- if hotkey then
- local txt = self.frame:GetHotkey()
- hotkey:SetText( txt )
- if txt == nil or txt == "" then
- hotkey:Hide()
- else
- hotkey:Show()
- end
- end
-end
-
-function Button:GetActionIDLabel( create )
- local f = self:GetFrame()
- if not f.actionIDLabel and create then
- local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
- label:SetAllPoints()
- label:SetJustifyH("CENTER")
- label:SetShadowColor(0,0,0,1)
- label:SetShadowOffset(2,-2)
- f.actionIDLabel = label -- store the label with the frame for recycling
- end
- return f.actionIDLabel
-end
-
-function Button:UpdateActionIDLabel( show )
- local label = self:GetActionIDLabel( show )
- if label then
- if show then
- local id = self:GetActionID()
- if id then
- label:SetText(tostring(id))
- label:Show()
- return
- end
- end
- label:Hide()
- end
-end
-
-function Button:SetNormalVertexColor( r, g, b, a )
- if ReAction.LBF then
- ReAction.LBF:SetNormalVertexColor(self:GetFrame(), r, g, b, a)
- else
- self:GetFrame():GetNormalTexture():SetVertexColor(r,g,b,a)
- end
-end
-
-function Button:GetNormalVertexColor()
- if ReAction.LBF then
- return ReAction.LBF:GetNormalVertexColor(self:GetFrame())
- else
- return self:GetFrame():GetNormalTexture():GetVertexColor()
- end
-end
-
-function Button:UpdateShowGrid()
- -- does nothing by default
-end
-
-function Button:ShowGridTemp(show)
- -- does nothing by default
-end
-
-function Button:ShowGrid(show)
- -- does nothing by default
-end
diff -r f255cd69e890 -r 65f2805957a0 classes/MultiCastButton.lua
--- a/classes/MultiCastButton.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,779 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local unpack = unpack
-local GetCVar = GetCVar
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local InCombatLockdown = InCombatLockdown
-local IsUsableSpell = IsUsableSpell
-local IsUsableAction = IsUsableAction
-local IsSpellKnown = IsSpellKnown
-local IsSpellInRange = IsSpellInRange
-local IsActionInRange = IsActionInRange
-local GetSpellInfo = GetSpellInfo
-local GetSpellCooldown = GetSpellCooldown
-local GetActionCooldown = GetActionCooldown
-local GetSpellTexture = GetSpellTexture
-local GetActionTexture = GetActionTexture
-local GetMultiCastTotemSpells = GetMultiCastTotemSpells
-
---[[
- Blizzard Constants:
- - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4
- - NUM_MULTI_CAST_PAGES = 3
- - SHAMAN_TOTEM_PRIORITIES = { } -- sets the order of the totems
- - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs
- - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs
-
- Blizzard Events:
- - UPDATE_MULTI_CAST_ACTIONBAR
-
- Blizzard APIs:
- - GetMultiCastBarOffset() : returns 6
-
- - SetMultiCastSpell(actionID, spellID) (protected) OR
- SetAttribute("type","multispell")
- SetAttribute("action",actionID)
- SetAttribute("spell",spellID)
-
- note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(),
- so that's action ID 132-144.
-
- - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot)
- returns spellIDs for all known totems that fit that slot. This function is available in
- the secure environment.
-
- Blizzard textures:
- All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single
- texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose
- this is to slightly optimize texture load performance, but it makes the UI code more clumsy.
-
- Each totem button and arrow has a colored border indicating its elemental type.
-
- TODO:
- - make whether to show the colored border configurable (looks really bad with ButtonFacade:Zoomed)
- - apply ButtonFacade to the flyout buttons? Or at least zoom the textures slightly?
- - use a multiplier with SetTexCoord on totem bar texture?
-
- Design Notes:
- - Only the header has a secure context. All other frames execute in its context.
-
- - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are
- GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by
- the summon flyout, which is also paged with the summon spells (the recall button is not paged)
-
- - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new
- spells) with the list of spells known for each slot.
-
- - Each button (except recall) has an arrow button which appears on mouseover and when clicked
- opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not
- appear.
-
- - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child
- of the bar. Each time the flyout panel is opened, the individual buttons grab their corresponding
- spell/type from the list, according to the slot which opened the flyout. Each button either sets
- the current page (summon) or sets a multispell to an actionID via type="multispell". None of them
- actually cast any spells (though, I suppose we could modify this so that e.g. configurable
- right-click casts the spell). The flyout also has a close button which closes the flyout: the
- flyout-open code positions the close button anchored to the last button in the flyout (which
- changes dynamically because each slot has a different number of items in the list).
-
- - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of
- the summon spells is cast from elsewhere.
-
- - The default UI has Call of the Elements always selected on UI load. This module remembers the last
- selected one and restores it.
-
-
-]]--
-
-
---
--- Secure snippets
---
-
--- bar
-local _bar_init = -- function(self)
-[[
- -- set up some globals in the secure environment
- flyout = self:GetFrameRef("flyout")
- flyoutSlot = nil
- summonSlot = self:GetAttribute("summonSlot")
- recallSlot = self:GetAttribute("recallSlot")
- baseActionID = self:GetAttribute("baseActionID")
- slotsPerPage = self:GetAttribute("slotsPerPage")
- currentPage = currentPage or self:GetAttribute("lastSummon") or 1
-
- totemIDsBySlot = newtable()
- for i = 1, slotsPerPage do
- totemIDsBySlot[i] = self:GetAttribute("TOTEM_PRIORITY_"..i)
- end
-
- -- these are set up in bar:SetupBar()
- flyoutChildren = flyoutChildren or newtable()
- summonSpells = summonSpells or newtable()
-]]
-
-local _onstate_multispellpage = -- function(self, stateid, newstate)
-[[
- currentPage = tonumber(newstate)
- control:CallMethod("UpdateLastSummon",currentPage)
- control:ChildUpdate()
-]]
-
-
--- buttons
-local _childupdate = -- function(self, snippetid, message)
-[[
- local t = self:GetAttribute("type")
- self:SetAttribute(t, self:GetAttribute(t.."-page"..currentPage))
-]]
-
-local _onEnter = -- function(self)
- -- for whatever reason, RegisterAutoHide is unreliable
- -- unless you re-anchor the frame prior to calling it.
- -- Even then, it's still not terribly reliable.
-[[
- local slot = self:GetAttribute("bar-idx")
- local arrow = owner:GetFrameRef("arrow-"..slot)
- if arrow and not arrow:IsShown() and not (flyout:IsVisible() and flyoutSlot == slot) then
- arrow:ClearAllPoints()
- arrow:SetPoint("BOTTOM",self,"TOP",0,0)
- arrow:Show()
- arrow:RegisterAutoHide(0)
- arrow:AddToAutoHide(self)
- end
-]]
-
-
--- flyout arrow
-local _arrow_openFlyout = -- function(self)
-[[
- local slot = self:GetAttribute("bar-idx")
- local totemID = totemIDsBySlot[slot - (summonSlot or 0)]
- if totemID == 0 then
- totemID = "summon"
- end
-
- local lastButton, lastPage
- for page, b in ipairs(flyoutChildren) do
- b:Hide()
- b:SetAttribute("totemSlot",totemID)
- if slot == summonSlot then
- local spellID = self:GetParent():GetAttribute("spell-page"..page)
- if spellID then
- b:SetAttribute("type","changePage")
- b:SetAttribute("spell",spellID)
- b:Show()
- lastButton = b
- lastPage = page
- end
- else
- local spell = select(page, 0, GetMultiCastTotemSpells(totemID) )
- if spell then
- b:SetAttribute("type","multispell")
- b:SetAttribute("action", baseActionID + (currentPage - 1)*slotsPerPage + totemID)
- b:SetAttribute("spell", spell)
- b:Show()
- lastButton = b
- lastPage = page
- end
- end
- end
-
- local close = owner:GetFrameRef("close")
- if lastButton and close then
- close:ClearAllPoints()
- close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring
- close:Show()
- control:CallMethod("UpdateFlyoutTextures",totemID)
- end
-
- flyout:ClearAllPoints()
- flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring
- if lastPage then
- flyout:SetHeight(lastPage * 27 + (close and close:GetHeight() or 0))
- end
- flyout:Show()
- flyout:RegisterAutoHide(1) -- TODO: configurable
- flyout:AddToAutoHide(owner)
- flyoutSlot = slot
- self:Hide()
-]]
-
-local _closeFlyout = -- function(self)
-[[
- flyout:Hide()
-]]
-
-
--- flyout child buttons
-local _flyout_child_preClick = -- function(self, button, down)
-[[
- local button = button
- if self:GetAttribute("type") == "changePage" then
- owner:SetAttribute("state-multispellpage",self:GetAttribute("index"))
- self:GetParent():Hide()
- return false
- else
- return nil, "close"
- end
-]]
-
-local _flyout_child_postClick = -- function(self, message, button, down)
-[[
- if message == "close" then
- self:GetParent():Hide() -- hide flyout after selecting
- end
-]]
-
-
---
--- The Blizzard totem bar textures are all actually one big texture,
--- with texcoord offsets. Shamelessly stolen from FrameXML/MultiCastActionBarFrame.lua
---
-local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar"
-local FLYOUT_UP_BUTTON_HL_TCOORDS = { 72/128, 92/128, 88/256, 98/256 }
-local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128, 92/128, 69/256, 79/256 }
-
-local SLOT_EMPTY_TCOORDS = {
- [EARTH_TOTEM_SLOT] = { 66/128, 96/128, 3/256, 33/256 },
- [FIRE_TOTEM_SLOT] = { 67/128, 97/128, 100/256, 130/256 },
- [WATER_TOTEM_SLOT] = { 39/128, 69/128, 209/256, 239/256 },
- [AIR_TOTEM_SLOT] = { 66/128, 96/128, 36/256, 66/256 },
-}
-
-local SLOT_OVERLAY_TCOORDS = {
- [EARTH_TOTEM_SLOT] = { 1/128, 35/128, 172/256, 206/256 },
- [FIRE_TOTEM_SLOT] = { 36/128, 70/128, 172/256, 206/256 },
- [WATER_TOTEM_SLOT] = { 1/128, 35/128, 207/256, 240/256 },
- [AIR_TOTEM_SLOT] = { 36/128, 70/128, 137/256, 171/256 },
-}
-
-local FLYOUT_UP_BUTTON_TCOORDS = {
- ["summon"] = { 99/128, 127/128, 84/256, 102/256 },
- [EARTH_TOTEM_SLOT] = { 99/128, 127/128, 160/256, 178/256 },
- [FIRE_TOTEM_SLOT] = { 99/128, 127/128, 122/256, 140/256 },
- [WATER_TOTEM_SLOT] = { 99/128, 127/128, 199/256, 217/256 },
- [AIR_TOTEM_SLOT] = { 99/128, 127/128, 237/256, 255/256 },
-}
-
-local FLYOUT_DOWN_BUTTON_TCOORDS = {
- ["summon"] = { 99/128, 127/128, 65/256, 83/256 },
- [EARTH_TOTEM_SLOT] = { 99/128, 127/128, 141/256, 159/256 },
- [FIRE_TOTEM_SLOT] = { 99/128, 127/128, 103/256, 121/256 },
- [WATER_TOTEM_SLOT] = { 99/128, 127/128, 180/256, 198/256 },
- [AIR_TOTEM_SLOT] = { 99/128, 127/128, 218/256, 236/256 },
-}
-
-local FLYOUT_TOP_TCOORDS = {
- ["summon"] = { 33/128, 65/128, 1/256, 23/256 },
- [EARTH_TOTEM_SLOT] = { 0/128, 32/128, 46/256, 68/256 },
- [FIRE_TOTEM_SLOT] = { 33/128, 65/128, 46/256, 68/256 },
- [WATER_TOTEM_SLOT] = { 0/128, 32/128, 1/256, 23/256 },
- [AIR_TOTEM_SLOT] = { 0/128, 32/128, 91/256, 113/256 },
-}
-
-local FLYOUT_MIDDLE_TCOORDS = {
- ["summon"] = { 33/128, 65/128, 23/256, 43/256 },
- [EARTH_TOTEM_SLOT] = { 0/128, 32/128, 68/256, 88/256 },
- [FIRE_TOTEM_SLOT] = { 33/128, 65/128, 68/256, 88/256 },
- [WATER_TOTEM_SLOT] = { 0/128, 32/128, 23/256, 43/256 },
- [AIR_TOTEM_SLOT] = { 0/128, 32/128, 113/256, 133/256 },
-}
-
-local eventList = {
- "ACTIONBAR_SLOT_CHANGED",
- "ACTIONBAR_UPDATE_STATE",
- "ACTIONBAR_UPDATE_USABLE",
- "ACTIONBAR_UPDATE_COOLDOWN",
- "UPDATE_BINDINGS",
- "UPDATE_MULTI_CAST_ACTIONBAR",
-}
-
---
--- MultiCast Button class
--- Inherits implementation methods from Action button class, but circumvents the constructor
--- and redefines/removes some methods.
---
-local buttonTypeID = "Totem"
-local Super = ReAction.Button
-local Action = ReAction.Button.Action
-local MultiCast = setmetatable(
- {
- defaultBarConfig = {
- type = buttonTypeID,
- btnWidth = 36,
- btnHeight = 36,
- btnRows = 1,
- btnColumns = 6,
- spacing = 3,
- buttons = { }
- },
-
- barType = L["Totem Bar"],
- buttonTypeID = buttonTypeID
- },
- { __index = Action } )
-
-ReAction.Button.MultiCast = MultiCast
-ReAction:RegisterBarType(MultiCast)
-
-function MultiCast:New( btnConfig, bar, idx )
- local maxIndex = bar.nTotemSlots or 0
- if bar.summonSlot then
- maxIndex = maxIndex + 1
- end
- if bar.recallSlot then
- maxIndex = maxIndex + 1
- end
-
- if not bar.hasMulticast or idx > maxIndex then
- return false
- end
-
- if idx < 1 then
- error("invalid index")
- end
-
- local name = format("ReAction_%s_Totem_%d",bar:GetName(),idx)
-
- self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
-
- local barFrame = bar:GetFrame()
- local f = self:GetFrame()
-
- -- attributes
- local page = (idx == bar.recallSlot) and 1 or bar:GetConfig().lastSummon or 1
- if idx == bar.recallSlot or idx == bar.summonSlot then
- f:SetAttribute("type","spell")
- local spells = (idx == bar.summonSlot) and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS
- f:SetAttribute("spell",spells[page])
- for i, spell in ipairs(spells) do
- if spell and IsSpellKnown(spell) then
- f:SetAttribute("spell-page"..i, spell)
- end
- end
- else
- local offset = bar.summonSlot and 1 or 0
- local slot = SHAMAN_TOTEM_PRIORITIES[idx - offset]
- local baseAction = barFrame:GetAttribute("baseActionID") + slot
- self.totemSlot = slot
- f:SetAttribute("type","action")
- f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
- for i = 1, NUM_MULTI_CAST_PAGES do
- f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
- end
- if not f.overlayTex then
- local tx = f:CreateTexture("OVERLAY")
- tx:SetTexture(TOTEM_TEXTURE)
- tx:SetTexCoord(unpack(SLOT_OVERLAY_TCOORDS[self.totemSlot]))
- tx:SetWidth(34)
- tx:SetHeight(34)
- tx:SetPoint("CENTER")
- tx:Show()
- f.overlayTex = tx
- end
- end
- f:SetAttribute("bar-idx",idx)
-
- -- non secure scripts
- f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
- f:SetScript("OnEnter", function(frame) self:OnEnter() end)
- f:SetScript("OnLeave", function(frame) self:OnLeave() end)
- f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
- f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
-
- -- secure handlers
- if idx ~= bar.recallSlot then
- f:SetAttribute("_childupdate",_childupdate)
- end
- barFrame:WrapScript(f, "OnEnter", _onEnter)
-
- -- event registration
- f:EnableMouse(true)
- f:RegisterForClicks("AnyUp")
- for _, evt in pairs(eventList) do
- f:RegisterEvent(evt)
- end
-
- -- Set up a proxy for the icon texture for use with ButtonFacade
- local SetTexCoordRaw = self.frames.icon.SetTexCoord
- self.frames.icon.SetTexCoord = function( tx, ... )
- if self:GetIconTexture() == TOTEM_TEXTURE then
- SetTexCoordRaw(tx,select(2,self:GetIconTexture()))
- else
- SetTexCoordRaw(tx,...)
- end
- end
-
- -- attach to skinner
- bar:SkinButton(self)
-
- f:Show()
-
- -- open arrow and flyout background textures
- if idx ~= bar.recallSlot then
- local arrow = f._arrowFrame or CreateFrame("Button", nil, f, "SecureFrameTemplate")
- f._arrowFrame = arrow
- arrow:SetWidth(28)
- arrow:SetHeight(18)
- arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring
- arrow:SetNormalTexture(TOTEM_TEXTURE)
- local slot = self.totemSlot or "summon"
- arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS[slot]) )
- arrow:SetHighlightTexture(TOTEM_TEXTURE)
- arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) )
- arrow:SetAttribute("bar-idx",idx)
- arrow:Hide()
- barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout)
- barFrame:SetFrameRef("arrow-"..idx,arrow)
- end
-
- self:Refresh()
-
- return self
-end
-
-function MultiCast:Destroy()
- local barFrame = self.bar:GetFrame()
- local f = self:GetFrame()
- pcall( barFrame.UnwrapScript, barFrame, f, "OnEnter" ) -- ignore errors
- if f._arrowFrame then
- pcall( barFrame.UnwrapScript, barFrame, f._arrowFrame,"OnClick" ) -- ignore errors
- end
- Super.Destroy(self)
-end
-
-function MultiCast:Refresh()
- Super.Refresh(self)
- self:UpdateAction()
-end
-
-function MultiCast:ShowGrid( show )
-end
-
-function MultiCast:ShowGridTemp( show )
-end
-
-function MultiCast:AcquireActionID()
-end
-
-function MultiCast:ReleaseActionID()
-end
-
-function MultiCast:UpdateShowGrid()
-end
-
-function MultiCast:UpdateBorder()
-end
-
-function MultiCast:UpdateMacroText()
-end
-
-function MultiCast:UpdateCount()
-end
-
-function MultiCast:UpdateCheckedState()
- local action = self:GetActionID()
- if action and IsCurrentAction(action) then
- self:GetFrame():SetChecked(1)
- else
- self:GetFrame():SetChecked(0)
- end
-end
-
-function MultiCast:RefreshHasActionAttributes()
-end
-
-function MultiCast:UpdateFlash()
-end
-
-function MultiCast:GetIconTexture()
- local tx
- if self.spellID then
- tx = GetSpellTexture(GetSpellInfo(self.spellID))
- elseif self.actionID then
- tx = GetActionTexture(self.actionID)
- end
- if tx then
- return tx
- else
- return TOTEM_TEXTURE, unpack(SLOT_EMPTY_TCOORDS[self.totemSlot or 1])
- end
-end
-
-function MultiCast:UpdateAction()
- local action = self:GetActionID()
- if action then
- if action ~= self.actionID then
- self.actionID = action
- self:UpdateAll()
- end
- else
- local spellID = self:GetSpellID()
- if spellID ~= self.spellID then
- self.spellID = spellID
- self:UpdateAll()
- end
- end
-end
-
-function MultiCast:GetActionID(page)
- return self:GetFrame():GetAttribute("action")
-end
-
-function MultiCast:GetSpellID(page)
- return self:GetFrame():GetAttribute("spell")
-end
-
-function MultiCast:SetActionID( id )
- error("Can not set action ID of multicast buttons")
-end
-
-function MultiCast:SetTooltip()
- local barFrame = self:GetFrame()
- if GetCVar("UberTooltips") == "1" then
- GameTooltip_SetDefaultAnchor(GameTooltip, barFrame)
- else
- GameTooltip:SetOwner(barFrame)
- end
- if self.spellID then
- GameTooltip:SetSpellByID(self.spellID,false,true)
- elseif self.actionID then
- GameTooltip:SetAction(self.actionID)
- end
-end
-
-function MultiCast:GetUsable()
- if self.spellID then
- return IsUsableSpell((GetSpellInfo(self.spellID)))
- elseif self.actionID then
- return IsUsableAction(self.actionID)
- end
-end
-
-function MultiCast:GetInRange()
- if self.spellID then
- return IsSpellInRange((GetSpellInfo(self.spellID))) == 0
- elseif self.actionID then
- return IsActionInRange(self.actionID) == 0
- end
-end
-
-function MultiCast:GetCooldown()
- if self.spellID then
- return GetSpellCooldown((GetSpellInfo(self.spellID)))
- elseif self.actionID then
- return GetActionCooldown(self.actionID)
- else
- return 0, 0, 0
- end
-end
-
-function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR()
- self:UpdateAll()
-end
-
-
---
--- flyout setup
---
-local function ShowFlyoutTooltip(frame)
- if GetCVar("UberTooltips") == "1" then
- GameTooltip_SetDefaultAnchor(GameTooltip, frame)
- else
- GameTooltip:SetOwner(frame)
- end
- local spell = frame:GetAttribute("spell")
- if spell == nil or spell == 0 then
- GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
- else
- GameTooltip:SetSpellByID(spell,false,true)
- end
-end
-
-local function HideFlyoutTooltip()
- GameTooltip:Hide()
-end
-
-local function UpdateFlyoutIcon(frame)
- local spellID = frame:GetAttribute("spell")
- if spellID == 0 or spellID == nil then
- frame.icon:SetTexture(TOTEM_TEXTURE)
- local slot = tonumber(frame:GetAttribute("totemSlot")) or 1
- frame.icon:SetTexCoord( unpack(SLOT_EMPTY_TCOORDS[slot]) )
- else
- frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID)))
- frame.icon:SetTexCoord(0,1,0,1)
- end
-end
-
-function MultiCast:SetupBar( bar )
- Super.SetupBar(self,bar)
-
- local slot = 0
- local nTotemSlots = 0
- local summonSlot = nil
- local recallSlot = nil
-
- -- figure out the capabilities of the character
- for i, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do
- if spell and IsSpellKnown(spell) then
- slot = 1
- summonSlot = 1
- end
- end
-
- for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do
- local totem = SHAMAN_TOTEM_PRIORITIES[i];
- if GetTotemInfo(totem) and GetMultiCastTotemSpells(totem) then
- nTotemSlots = nTotemSlots + 1
- slot = slot + 1
- end
- end
-
- slot = slot + 1
- for i, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do
- if spell and IsSpellKnown(spell) then
- recallSlot = slot
- end
- end
-
- if nTotemSlots == 0 then
- bar.hasMulticast = false -- no multicast capability
- return
- end
-
- bar.hasMulticast = true
- bar.summonSlot = summonSlot
- bar.recallSlot = recallSlot
- bar.nTotemSlots = nTotemSlots
-
-
- local f = bar:GetFrame()
-
- -- init bar secure environment
- f:SetAttribute("lastSummon", bar:GetConfig().lastSummon)
- f:SetAttribute("summonSlot", summonSlot)
- f:SetAttribute("recallSlot", recallSlot)
- f:SetAttribute("slotsPerPage", NUM_MULTI_CAST_BUTTONS_PER_PAGE)
- f:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS)
- for i, p in ipairs(SHAMAN_TOTEM_PRIORITIES) do
- f:SetAttribute("TOTEM_PRIORITY_"..i,p)
- end
- f:SetAttribute("_onstate-multispellpage", _onstate_multispellpage)
-
- function f:UpdateLastSummon(value)
- bar:GetConfig().lastSummon = value
- end
-
- -- create flyout container frame and close arrow
- local flyout = bar._flyoutFrame
- if not flyout then
- flyout = CreateFrame("Frame", nil, f, "SecureFrameTemplate")
- bar._flyoutFrame = flyout
- f:SetFrameRef("flyout",flyout)
- flyout.buttons = { }
- flyout:Hide()
- flyout:SetWidth(24)
- flyout:SetHeight(1)
- flyout:SetPoint("BOTTOM",f,"TOP",0,0)
-
- local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate")
- close:SetWidth(28)
- close:SetHeight(18)
- close:SetPoint("BOTTOM",flyout,"TOP")
- close:SetNormalTexture(TOTEM_TEXTURE)
- close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS["summon"]))
- close:SetHighlightTexture(TOTEM_TEXTURE)
- close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) )
- f:SetFrameRef("close",close)
- f:WrapScript(close, "OnClick", _closeFlyout)
- close:Show()
-
- local midTx = flyout:CreateTexture("BACKGROUND")
- midTx:SetWidth(32)
- midTx:SetHeight(20)
- midTx:SetPoint("BOTTOM")
- midTx:SetTexture(TOTEM_TEXTURE)
- midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS["summon"]))
- midTx:Show()
-
- local topTx = flyout:CreateTexture("BACKGROUND")
- topTx:SetWidth(32)
- topTx:SetHeight(20)
- topTx:SetTexture(TOTEM_TEXTURE)
- midTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS["summon"]))
- topTx:SetPoint("BOTTOM",midTx,"TOP",0,-10)
- topTx:Show()
-
- function flyout:UpdateTextures(slot)
- slot = slot or "summon"
- close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS[slot]))
- midTx:ClearAllPoints()
- midTx:SetPoint("BOTTOM")
- midTx:SetPoint("TOP",close,"BOTTOM",0,0)
- midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS[slot]))
- topTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS[slot]))
- end
-
- -- create flyout buttons
- for i = 1, 10 do -- maximum 9 spells + 1 empty slot
- local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate")
- b:SetWidth(24)
- b:SetHeight(24)
- local prev = flyout.buttons[i-1]
- b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring
- b.icon = b:CreateTexture("BACKGROUND")
- b.icon:SetAllPoints()
- b.icon:Show()
- b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
- b:GetHighlightTexture():SetBlendMode("ADD")
- b:RegisterForClicks("AnyUp")
- b:SetScript("OnShow",UpdateFlyoutIcon)
- b:SetScript("OnEnter",ShowFlyoutTooltip)
- b:SetScript("OnLeave",HideFlyoutTooltip)
- b:SetAttribute("index",i)
- f:SetAttribute("flyout-child-idx",i)
- f:SetFrameRef("flyout-child",b)
- f:Execute([[
- flyoutChildren = flyoutChildren or newtable()
- flyoutChildren[self:GetAttribute("flyout-child-idx")] = self:GetFrameRef("flyout-child")
- ]])
- f:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick)
- b:Show()
- flyout.buttons[i] = b
- end
- end
-
- -- scale flyout frame
- local scale = bar:GetButtonSize() / 36
- flyout:SetScale(scale)
-
- function f:UpdateFlyoutTextures(slot)
- flyout:UpdateTextures(slot)
- end
-
- -- re-execute setup when new spells are loaded
- if not f.events_registered then
- f:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR")
- f:RegisterEvent("PLAYER_ENTERING_WORLD")
- -- Bar.frame does not use OnEvent
- f:SetScript("OnEvent",
- function()
- if not InCombatLockdown() then
- self:SetupBar(bar)
- end
- end)
- f.events_registered = true
- end
-
-
- f:Execute(_bar_init)
-end
-
diff -r f255cd69e890 -r 65f2805957a0 classes/Overlay.lua
--- a/classes/Overlay.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,754 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local LKB = ReAction.LKB
-local CreateFrame = CreateFrame
-local InCombatLockdown = InCombatLockdown
-local floor = math.floor
-local min = math.min
-local format = string.format
-local GameTooltip = GameTooltip
-local Bar = ReAction.Bar
-local GetSize = Bar.GetSize
-local SetSize = Bar.SetSize
-local GetButtonSize = Bar.GetButtonSize
-local GetButtonGrid = Bar.GetButtonGrid
-local SetButtonSize = Bar.SetButtonSize
-local SetButtonGrid = Bar.SetButtonGrid
-local ApplyAnchor = Bar.ApplyAnchor
-local GameTooltipTextRight1 = GameTooltipTextRight1
-local GameTooltipTextRight2 = GameTooltipTextRight2
-local GameTooltipTextRight3 = GameTooltipTextRight3
-
---
--- Wrap some of the bar manipulators to make them state-aware
---
-local function SetAnchor( bar, point, frame, relPoint, x, y )
- local state = bar:GetSecureState()
- if state then
- local anchorstate = bar:GetStateProperty(state, "anchorEnable")
- if anchorstate then
- bar:SetStateProperty(state, "anchorFrame", frame)
- bar:SetStateProperty(state, "anchorPoint", point)
- bar:SetStateProperty(state, "anchorRelPoint", relPoint)
- bar:SetStateProperty(state, "anchorX", x or 0)
- bar:SetStateProperty(state, "anchorY", y or 0)
- bar:SetAnchor(bar:GetAnchor())
- return
- end
- end
- bar:SetAnchor(point, frame, relPoint, x, y)
-end
-
-local function GetStateScale( bar )
- local state = bar:GetSecureState()
- if state and bar:GetStateProperty(state, "enableScale") then
- return bar:GetStateProperty(state, "scale")
- end
-end
-
-local function SetStateScale( bar, scale )
- local state = bar:GetSecureState()
- if state and bar:GetStateProperty(state, "enableScale") then
- bar:SetStateProperty(state, "scale", scale)
- end
-end
-
-
---
--- Bar config overlay
---
-
-local function GetNormalTextColor()
- return 1.0, 1.0, 1.0, 1.0
-end
-
-local function GetAnchoredTextColor()
- return 1.0, 1.0, 1.0, 1.0
-end
-
-local function GetNormalBgColor()
- return 0.7, 0.7, 1.0, 0.3
-end
-
-local function GetAnchoredBgColor()
- return 0.9, 0.2, 0.7, 0.3
-end
-
-local function StoreSize(bar)
- local f = bar:GetFrame()
- SetSize( bar, f:GetWidth(), f:GetHeight() )
-end
-
-local function StoreExtents(bar)
- local f = bar:GetFrame()
- local p, fr, rp, x, y = f:GetPoint(1)
- fr = fr and fr:GetName() or "UIParent"
- SetAnchor( bar, p, fr, rp, x, y )
- SetSize( bar, f:GetWidth(), f:GetHeight() )
-end
-
-local function RecomputeButtonSize(bar)
- local w, h = GetSize(bar)
- local bw, bh = GetButtonSize(bar)
- local r, c, s = GetButtonGrid(bar)
-
- local scaleW = (floor(w/c) - s) / bw
- local scaleH = (floor(h/r) - s) / bh
- local scale = min(scaleW, scaleH)
-
- SetButtonSize(bar, scale * bw, scale * bh, s)
-end
-
-local function ComputeBarScale(bar, overlay)
- local w, h = overlay:GetWidth() - 8, overlay:GetHeight() - 8
- local bw, bh = GetButtonSize(bar)
- local r, c, s = GetButtonGrid(bar)
-
- local scaleW = w / (c*(bw+s))
- local scaleH = h / (r*(bh+s))
- local scale = min(scaleW, scaleH)
-
- if scale > 2.5 then
- scale = 2.5
- elseif scale < 0.25 then
- scale = 0.25
- end
-
- return scale
-end
-
-local function RecomputeButtonSpacing(bar)
- local w, h = GetSize(bar)
- local bw, bh = GetButtonSize(bar)
- local r, c, s = GetButtonGrid(bar)
-
- SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh))
-end
-
-local function RecomputeGrid(bar)
- local w, h = GetSize(bar)
- local bw, bh = GetButtonSize(bar)
- local r, c, s = GetButtonGrid(bar)
-
- SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s)
-end
-
-local function ClampToButtons(bar)
- local bw, bh = GetButtonSize(bar)
- local r, c, s = GetButtonGrid(bar)
- SetSize(bar, (bw+s)*c + 1, (bh+s)*r + 1)
-end
-
-local function HideGameTooltip()
- GameTooltip:Hide()
-end
-
-local anchorInside = { inside = true }
-local anchorOutside = { outside = true }
-local edges = { "BOTTOM", "TOP", "LEFT", "RIGHT" }
-local oppositeEdges = {
- TOP = "BOTTOM",
- BOTTOM = "TOP",
- LEFT = "RIGHT",
- RIGHT = "LEFT"
-}
-local pointsOnEdge = {
- BOTTOM = { "BOTTOM", "BOTTOMLEFT", "BOTTOMRIGHT", },
- TOP = { "TOP", "TOPLEFT", "TOPRIGHT", },
- RIGHT = { "RIGHT", "BOTTOMRIGHT", "TOPRIGHT", },
- LEFT = { "LEFT", "BOTTOMLEFT", "TOPLEFT", },
-}
-local edgeSelector = {
- BOTTOM = 1, -- select x of x,y
- TOP = 1, -- select x of x,y
- LEFT = 2, -- select y of x,y
- RIGHT = 2, -- select y of x,y
-}
-local snapPoints = {
- [anchorOutside] = {
- BOTTOMLEFT = {"BOTTOMRIGHT","TOPLEFT","TOPRIGHT"},
- BOTTOM = {"TOP"},
- BOTTOMRIGHT = {"BOTTOMLEFT","TOPRIGHT","TOPLEFT"},
- RIGHT = {"LEFT"},
- TOPRIGHT = {"TOPLEFT","BOTTOMRIGHT","BOTTOMLEFT"},
- TOP = {"BOTTOM"},
- TOPLEFT = {"TOPRIGHT","BOTTOMLEFT","BOTTOMRIGHT"},
- LEFT = {"RIGHT"},
- CENTER = {"CENTER"}
- },
- [anchorInside] = {
- BOTTOMLEFT = {"BOTTOMLEFT"},
- BOTTOM = {"BOTTOM"},
- BOTTOMRIGHT = {"BOTTOMRIGHT"},
- RIGHT = {"RIGHT"},
- TOPRIGHT = {"TOPRIGHT"},
- TOP = {"TOP"},
- TOPLEFT = {"TOPLEFT"},
- LEFT = {"LEFT"},
- CENTER = {"CENTER"}
- }
-}
-local insidePointOffsetFuncs = {
- BOTTOMLEFT = function(x, y) return x, y end,
- BOTTOM = function(x, y) return 0, y end,
- BOTTOMRIGHT = function(x, y) return -x, y end,
- RIGHT = function(x, y) return -x, 0 end,
- TOPRIGHT = function(x, y) return -x, -y end,
- TOP = function(x, y) return 0, -y end,
- TOPLEFT = function(x, y) return x, -y end,
- LEFT = function(x, y) return x, 0 end,
- CENTER = function(x, y) return x, y end,
-}
-local pointCoordFuncs = {
- BOTTOMLEFT = function(f) return f:GetLeft(), f:GetBottom() end,
- BOTTOM = function(f) return nil, f:GetBottom() end,
- BOTTOMRIGHT = function(f) return f:GetRight(), f:GetBottom() end,
- RIGHT = function(f) return f:GetRight(), nil end,
- TOPRIGHT = function(f) return f:GetRight(), f:GetTop() end,
- TOP = function(f) return nil, f:GetTop() end,
- TOPLEFT = function(f) return f:GetLeft(), f:GetTop() end,
- LEFT = function(f) return f:GetLeft(), nil end,
- CENTER = function(f) return f:GetCenter() end,
-}
-local edgeBoundsFuncs = {
- BOTTOM = function(f) return f:GetLeft(), f:GetRight() end,
- LEFT = function(f) return f:GetBottom(), f:GetTop() end
-}
-edgeBoundsFuncs.TOP = edgeBoundsFuncs.BOTTOM
-edgeBoundsFuncs.RIGHT = edgeBoundsFuncs.LEFT
-local cornerTexCoords = {
- -- ULx, ULy, LLx, LLy, URx, URy, LRx, LRy
- TOPLEFT = { 1, 1, 1, 0, 0, 1, 0, 0 },
- TOPRIGHT = { 1, 0, 0, 0, 1, 1, 0, 1 },
- BOTTOMLEFT = { 0, 1, 1, 1, 0, 0, 1, 0 },
- BOTTOMRIGHT = { 0, 0, 0, 1, 1, 0, 1, 1 },
-}
-
--- Returns absolute coordinates x,y of the named point 'p' of frame 'f'
-local function GetPointCoords( f, p )
- local x, y = pointCoordFuncs[p](f)
- if not(x and y) then
- local cx, cy = f:GetCenter()
- x = x or cx
- y = y or cy
- end
- return x, y
-end
-
-
--- Returns true if frame 'f1' can be anchored to frame 'f2'
-local function CheckAnchorable( f1, f2 )
- -- can't anchor a frame to itself or to nil
- if f1 == f2 or f2 == nil then
- return false
- end
-
- -- can always anchor to UIParent
- if f2 == UIParent then
- return true
- end
-
- -- also can't do circular anchoring of frames
- -- walk the anchor chain, which generally shouldn't be that expensive
- -- (who nests draggables that deep anyway?)
- for i = 1, f2:GetNumPoints() do
- local _, f = f2:GetPoint(i)
- if not f then f = f2:GetParent() end
- return CheckAnchorable(f1,f)
- end
-
- return true
-end
-
--- Returns true if frames f1 and f2 specified edges overlap
-local function CheckEdgeOverlap( f1, f2, e )
- local l1, u1 = edgeBoundsFuncs[e](f1)
- local l2, u2 = edgeBoundsFuncs[e](f2)
- return l1 <= l2 and l2 <= u1 or l2 <= l1 and l1 <= u2
-end
-
--- Returns true if point p1 on frame f1 overlaps edge e2 on frame f2
-local function CheckPointEdgeOverlap( f1, p1, f2, e2 )
- local l, u = edgeBoundsFuncs[e2](f2)
- local x, y = GetPointCoords(f1,p1)
- x = select(edgeSelector[e2], x, y)
- return l <= x and x <= u
-end
-
--- Returns the distance between corresponding edges. It is
--- assumed that the passed in edges e1 and e2 are the same or opposites
-local function GetEdgeDistance( f1, f2, e1, e2 )
- local x1, y1 = pointCoordFuncs[e1](f1)
- local x2, y2 = pointCoordFuncs[e2](f2)
- return math.abs((x1 or y1) - (x2 or y2))
-end
-
-local globalSnapTargets = { [UIParent] = anchorInside }
-
-local function GetClosestFrameEdge(f1,f2,a)
- local dist, edge, opp
- if f2:IsVisible() and CheckAnchorable(f1,f2) then
- for _, e in pairs(edges) do
- local o = a.inside and e or oppositeEdges[e]
- if CheckEdgeOverlap(f1,f2,e) then
- local d = GetEdgeDistance(f1, f2, e, o)
- if not dist or (d < dist) then
- dist, edge, opp = d, e, o
- end
- end
- end
- end
- return dist, edge, opp
-end
-
-local function GetClosestVisibleEdge( f )
- local r, o, e1, e2
- local a = anchorOutside
- for _, b in ReAction:IterateBars() do
- local d, e, opp = GetClosestFrameEdge(f,b:GetFrame(),a)
- if d and (not r or d < r) then
- r, o, e1, e2 = d, b:GetFrame(), e, opp
- end
- end
- for f2, a2 in pairs(globalSnapTargets) do
- local d, e, opp = GetClosestFrameEdge(f,f2,a2)
- if d and (not r or d < r) then
- r, o, e1, e2, a = d, f2, e, opp, a2
- end
- end
- return o, e1, e2, a
-end
-
-local function GetClosestVisiblePoint(f1)
- local f2, e1, e2, a = GetClosestVisibleEdge(f1)
- if f2 then
- local rsq, p, rp, x, y
- -- iterate pointsOnEdge in order and use < to prefer edge centers to corners
- for _, p1 in ipairs(pointsOnEdge[e1]) do
- if CheckPointEdgeOverlap(f1,p1,f2,e2) then
- for _, p2 in pairs(snapPoints[a][p1]) do
- local x1, y1 = GetPointCoords(f1,p1)
- local x2, y2 = GetPointCoords(f2,p2)
- local dx = x1 - x2
- local dy = y1 - y2
- local rsq2 = dx*dx + dy*dy
- if not rsq or rsq2 < rsq then
- rsq, p, rp, x, y = rsq2, p1, p2, dx, dy
- end
- end
- end
- end
- return f2, p, rp, x, y
- end
-end
-
-local function GetClosestPointSnapped(f1, rx, ry, xOff, yOff)
- local o, p, rp, x, y = GetClosestVisiblePoint(f1)
- local s = false
-
- local insideOffsetFunc = p and insidePointOffsetFuncs[p]
- local coordFunc = p and pointCoordFuncs[p]
- if not insideOffsetFunc or not coordFunc then
- return
- end
-
- local sx, sy = insideOffsetFunc(xOff or 0, yOff or 0)
- local xx, yy = coordFunc(f1)
- if xx and yy then
- if math.abs(x) <= rx then
- if math.abs(y) <= ry then
- x = sx
- y = sy
- s = true
- elseif CheckEdgeOverlap(f1,o,"LEFT") then
- x = sx
- s = true
- end
- elseif math.abs(y) <= ry and CheckEdgeOverlap(f1,o,"TOP") then
- y = sy
- s = true
- end
- elseif xx then
- if math.abs(x) <= rx then
- x = sx
- s = true
- if math.abs(y) <= ry then
- y = sy
- end
- end
- elseif yy then
- if math.abs(y) <= ry then
- y = sy
- s = true
- if math.abs(x) <= rx then
- x = sx
- end
- end
- end
-
- -- correct for some Lua oddities with doubles
- if x == -0 then x = 0 end
- if y == -0 then y = 0 end
-
- if s then
- return o, p, rp, math.floor(x), math.floor(y)
- end
-end
-
-local function CreateSnapIndicator()
- local si = CreateFrame("Frame",nil,UIParent)
- si:SetFrameStrata("HIGH")
- si:SetHeight(16)
- si:SetWidth(16)
- local tex = si:CreateTexture()
- tex:SetAllPoints()
- tex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
- tex:SetBlendMode("ADD")
- tex:SetDrawLayer("OVERLAY")
- return si
-end
-
-local si1 = CreateSnapIndicator()
-local si2 = CreateSnapIndicator()
-
-local function DisplaySnapIndicator( f, rx, ry, xOff, yOff )
- local o, p, rp, x, y, snap = GetClosestPointSnapped(f, rx, ry, xOff, yOff)
- if o then
- si1:ClearAllPoints()
- si2:ClearAllPoints()
- si1:SetPoint("CENTER", f, p, 0, 0)
- local xx, yy = pointCoordFuncs[rp](o)
- x = math.abs(x) <=rx and xx and 0 or x
- y = math.abs(y) <=ry and yy and 0 or y
- si2:SetPoint("CENTER", o, rp, x, y)
- si1:Show()
- si2:Show()
- else
- if si1:IsVisible() then
- si1:Hide()
- si2:Hide()
- end
- end
- return o, p
-end
-
-local function HideSnapIndicator()
- if si1:IsVisible() then
- si1:Hide()
- si2:Hide()
- end
-end
-
-local function UpdateLabelString(overlay)
- local label = overlay.labelString
- if label then
- local name = overlay.labelName
- if name and overlay.labelSubtext then
- name = format("%s (%s)", name, overlay.labelSubtext)
- end
- label:SetText(name or "")
- end
-end
-
-local function CreateControls(bar)
- local f = bar:GetFrame()
-
- f:SetMovable(true)
- f:SetResizable(true)
-
- -- child of UIParent so that alpha and scale doesn't propagate to it
- local overlay = CreateFrame("Button", nil, UIParent)
- overlay:EnableMouse(true)
- overlay:SetFrameLevel(10) -- set it above the buttons
- overlay:SetPoint("TOPLEFT", f, "TOPLEFT", -4, 4)
- overlay:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 4, -4)
- overlay:SetBackdrop({
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true,
- tileSize = 16,
- edgeSize = 16,
- insets = { left = 0, right = 0, top = 0, bottom = 0 },
- })
-
- -- textures
- local bgTex = overlay:CreateTexture(nil,"BACKGROUND")
- bgTex:SetTexture(0.7,0.7,1.0,0.2)
- bgTex:SetPoint("TOPLEFT",4,-4)
- bgTex:SetPoint("BOTTOMRIGHT",-4,4)
- local hTex = overlay:CreateTexture(nil,"HIGHLIGHT")
- hTex:SetTexture(0.7,0.7,1.0,0.2)
- hTex:SetPoint("TOPLEFT",4,-4)
- hTex:SetPoint("BOTTOMRIGHT",-4,4)
- hTex:SetBlendMode("ADD")
- local aTex = overlay:CreateTexture(nil,"ARTWORK")
- aTex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
- aTex:SetWidth(16)
- aTex:SetHeight(16)
- aTex:Hide()
-
- -- label
- local label = overlay:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
- label:SetAllPoints()
- label:SetJustifyH("CENTER")
- label:SetShadowColor(0,0,0,1)
- label:SetShadowOffset(3,-3)
- label:SetTextColor(GetNormalTextColor())
- label:SetText(bar:GetName())
- label:Show()
- overlay.labelString = label
- overlay.labelName = bar:GetName()
-
- local function UpdateAnchorDecoration()
- local point, anchor, relPoint, x, y = f:GetPoint(1)
- if point then
- local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
- if (anchor and anchor ~= UIParent) or (ofsx == 0 and ofsy == 0) then
- bgTex:SetTexture( GetAnchoredBgColor() )
- hTex:SetTexture( GetAnchoredBgColor() )
- label:SetTextColor( GetAnchoredTextColor() )
- aTex:ClearAllPoints()
- aTex:SetPoint(point)
- aTex:Show()
- return
- end
- end
- bgTex:SetTexture( GetNormalBgColor() )
- hTex:SetTexture( GetNormalBgColor() )
- label:SetTextColor( GetNormalTextColor() )
- aTex:Hide()
- end
-
- local function StopResize()
- f:StopMovingOrSizing()
- f.isMoving = false
- f:SetScript("OnUpdate",nil)
- StoreSize(bar)
- ClampToButtons(bar)
- ReAction:RefreshEditor()
- end
-
- local function CornerUpdate()
- local bw, bh = GetButtonSize(bar)
- local r, c, s = GetButtonGrid(bar)
- local ss = GetStateScale(bar)
- if IsShiftKeyDown() then
- if ss then
- f:SetMinResize( ((s+bw)*c*0.25)/ss, ((s+bh)*r*0.25)/ss )
- f:SetMaxResize( ((s+bw)*c*2.5 + 1)/ss, ((s+bh)*r*2.5 + 1)/ss )
- scale = ComputeBarScale(bar, overlay)
- else
- f:SetMinResize( (s+12)*c+1, (s+12)*r+1 )
- f:SetMaxResize( (s+128)*c+1, (s+128)*r+1 )
- RecomputeButtonSize(bar)
- end
- elseif not ss and IsAltKeyDown() then
- f:SetMinResize( bw*c, bh*r )
- f:SetMaxResize( 2*bw*c, 2*bh*r )
- RecomputeButtonSpacing(bar)
- else
- f:SetMinResize( bw+s+1, bh+s+1 )
- f:SetMaxResize( 50*(bw+s)+1, 50*(bh+s)+1 )
- RecomputeGrid(bar)
- end
- GameTooltipTextRight2:SetText(format("%d x %d",r,c))
-
- local ss = GetStateScale(bar)
- if ss then
- GameTooltipTextRight4:SetText(format("%d%%", scale*100))
- else
- local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
- GameTooltipTextRight3:SetText(size)
- GameTooltipTextRight4:SetText(tostring(s))
- end
- end
-
- -- corner drag handles
- for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do
- local corner = CreateFrame("Frame",nil,overlay)
- corner:EnableMouse(true)
- corner:SetWidth(16)
- corner:SetHeight(16)
- corner:SetPoint(point)
-
- local tex = corner:CreateTexture(nil,"HIGHLIGHT")
- tex:SetTexture("Interface\\AddOns\\ReAction\\img\\corner")
- tex:SetTexCoord(unpack(cornerTexCoords[point]))
- tex:SetBlendMode("ADD")
- tex:SetAlpha(0.6)
- tex:SetAllPoints()
-
- corner:SetScript("OnMouseDown",
- function(_,btn)
- f:SetScript("OnUpdate", CornerUpdate)
- f:StartSizing(point)
- end
- )
- corner:SetScript("OnMouseUp",
- function()
- local ss = GetStateScale(bar)
- if ss then
- SetStateScale(bar, ComputeBarScale(bar, overlay))
- end
- StopResize()
- end)
- corner:SetScript("OnEnter",
- function()
- local bw, bh = GetButtonSize(bar)
- local r, c, s = bar:GetButtonGrid()
- local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
- local ss = GetStateScale(bar)
- local state = bar:GetSecureState()
- GameTooltip:SetOwner(f, "ANCHOR_"..point)
- if ss then
- GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
- else
- GameTooltip:AddLine(bar:GetName())
- end
- GameTooltip:AddDoubleLine(format("|cffcccccc%s|r %s",L["Drag"],L["to add/remove buttons:"]), format("%d x %d",r,c))
- if ss then
- GameTooltip:AddLine(L["State Scale Override"])
- GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to change scale:"]), format("%d%%", bar:GetStateProperty(state,"scale")*100))
- else
- GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to resize buttons:"]), tostring(floor(size)))
- GameTooltip:AddDoubleLine(format("|cff0033cc%s|r %s",L["Hold Alt"], L["to change spacing:"]), tostring(floor(s)))
- end
- GameTooltip:Show()
- end
- )
- corner:SetScript("OnLeave",
- function()
- GameTooltip:Hide()
- f:SetScript("OnUpdate",nil)
- end
- )
- end
-
- overlay:RegisterForDrag("LeftButton")
- overlay:RegisterForClicks("RightButtonUp")
-
- overlay:SetScript("OnDragStart",
- function()
- f:StartMoving()
- f.isMoving = true
- local w,h = bar:GetButtonSize()
- f:ClearAllPoints()
- UpdateAnchorDecoration()
- f:SetScript("OnUpdate", function()
- if IsShiftKeyDown() then
- local f, p = DisplaySnapIndicator(f,w,h)
- else
- HideSnapIndicator()
- end
- end)
- end
- )
-
- local function UpdateDragTooltip()
- GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT")
- local ss = GetStateScale(bar)
- local state = bar:GetSecureState()
- if ss then
- GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
- else
- GameTooltip:AddLine(bar:GetName())
- end
- GameTooltip:AddLine(format("|cffcccccc%s|r %s",L["Drag"],L["to move"]))
- GameTooltip:AddLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to anchor to nearby frames"]))
- GameTooltip:AddLine(format("|cff00cccc%s|r %s",L["Right-click"],L["for options..."]))
- local point, frame, relpoint, x, y = bar:GetFrame():GetPoint(1)
- if point then
- local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
- if (frame and frame ~= UIParent) or (ofsx == 0 and ofsy == 0) then
- frame = frame or UIParent
- GameTooltip:AddLine(format("%s <%s>",L["Currently anchored to"],frame:GetName()))
- end
- end
- GameTooltip:Show()
- end
-
- overlay:SetScript("OnDragStop",
- function()
- f:StopMovingOrSizing()
- f.isMoving = false
- f:SetScript("OnUpdate",nil)
-
- if IsShiftKeyDown() then
- local w, h = bar:GetButtonSize()
- local a, p, rp, x, y = GetClosestPointSnapped(f,w,h)
- if a then
- f:ClearAllPoints()
- f:SetPoint(p,a,rp,x,y)
- end
- HideSnapIndicator()
- end
-
- StoreExtents(bar)
- ReAction:RefreshEditor()
- UpdateDragTooltip()
- UpdateAnchorDecoration()
- end
- )
-
- overlay:SetScript("OnEnter",
- function()
- UpdateDragTooltip()
- end
- )
-
- overlay:SetScript("OnLeave", HideGameTooltip)
-
- overlay:SetScript("OnClick",
- function()
- ReAction:ShowEditor(bar)
- end
- )
-
- function overlay:RefreshControls()
- UpdateAnchorDecoration()
- end
-
- overlay:SetScript("OnShow", overlay.RefreshControls)
-
- if ReAction:GetKeybindMode() then
- overlay:SetFrameLevel(1)
- end
-
- UpdateLabelString(overlay)
- UpdateAnchorDecoration()
-
- return overlay
-end
-
-
--- export methods to the Bar prototype
-Bar.Overlay = { }
-function Bar.Overlay:New( bar )
- return setmetatable( {frame = CreateControls(bar)}, {__index=self} )
-end
-
-function Bar.Overlay:SetLabel(name)
- self.frame.labelName = name
- UpdateLabelString(self.frame)
-end
-
-function Bar.Overlay:SetLabelSubtext(text)
- self.frame.labelSubtext = text
- UpdateLabelString(self.frame)
-end
-
-function Bar.Overlay:Show()
- self.frame:Show()
-end
-
-function Bar.Overlay:Hide()
- self.frame:Hide()
-end
-
-function Bar.Overlay:IsShown()
- return self.frame:IsShown()
-end
-
-function Bar.Overlay:RefreshControls()
- self.frame:RefreshControls()
-end
\ No newline at end of file
diff -r f255cd69e890 -r 65f2805957a0 classes/PetActionButton.lua
--- a/classes/PetActionButton.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,324 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local GetCVar = GetCVar
-local InCombatLockdown = InCombatLockdown
-local GetPetActionInfo = GetPetActionInfo
-local GetPetActionSlotUsable = GetPetActionSlotUsable
-local GetPetActionCooldown = GetPetActionCooldown
-local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart
-local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop
-local SetDesaturation = SetDesaturation
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-
---
--- Secure snippets
--- These are run within the context of the bar's sandbox, as the
--- buttons themselves do not have their own sandbox.
---
-local _onDragStart = -- function(self, button, kind, value, ...)
-[[
- if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
- return kind, value, ...
- else
- return "petaction", self:GetAttribute("action")
- end
-]]
-
-local _onReceiveDrag = -- function(self, button, kind, value, ...)
-[[
- if kind then -- pet spells on the cursor return nil from GetCursorInfo(), which is very strange
- return kind, value, ...
- end
- return "petaction", self:GetAttribute("action")
-]]
-
---
--- private
---
-local eventList = {
-"PLAYER_CONTROL_LOST",
-"PLAYER_CONTROL_GAINED",
-"PLAYER_FARSIGHT_FOCUS_CHANGED",
-"UNIT_PET",
-"UNIT_FLAGS",
-"UNIT_AURA",
-"PET_BAR_UPDATE",
-"PET_BAR_UPDATE_COOLDOWN",
-"PET_BAR_UPDATE_USABLE",
-"UPDATE_BINDINGS",
-}
-
---
--- Pet Action Button class
---
-local buttonTypeID = "PetAction"
-local Super = ReAction.Button
-local Pet = setmetatable(
- {
- defaultBarConfig = {
- type = buttonTypeID,
- btnWidth = 30,
- btnHeight = 30,
- btnRows = 1,
- btnColumns = 10,
- spacing = 8,
- buttons = { }
- },
-
- barType = L["Pet Action Bar"],
- buttonTypeID = buttonTypeID
- },
- { __index = Super } )
-
-ReAction.Button.PetAction = Pet
-ReAction:RegisterBarType(Pet)
-
-function Pet:New( config, bar, idx, idHint )
- local name = format("ReAction_%s_PetAction_%d",bar:GetName(),idx)
-
- self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
-
- local f = self:GetFrame()
- if not f.autoCastTexture then
- -- store autocast stuff with the frame for recycling
- local tex = f:CreateTexture(nil,"OVERLAY")
- tex:SetTexture([[Interface\Buttons\UI-AutoCastableOverlay]])
- tex:SetHeight(58)
- tex:SetWidth(58)
- tex:SetPoint("CENTER")
- f.autoCastTexture = tex
- f.autoCastShine = CreateFrame("Frame",name.."Shine",f,"AutoCastShineTemplate") -- create after autocast texture so it's on top
- -- move the cooldown around
- local cd = self.frames.cooldown
- cd:ClearAllPoints()
- cd:SetWidth(33)
- cd:SetHeight(33)
- cd:SetPoint("CENTER", f, "CENTER", -2, -1)
- -- resize to 30x30
- f:SetHeight(30)
- f:SetWidth(30)
- local nt = _G[name.."NormalTexture"]
- nt:SetHeight(54)
- nt:SetWidth(54)
- end
- local barFrame = bar:GetFrame()
-
- -- set up the base action ID
- self:SetActionIDPool("pet",10)
- config.actionID = self:AcquireActionID(config.actionID, idHint, true)
-
- -- attribute setup
- -- There's no secure way to do PetAutoCastToggle by actionID, so use
- -- a click-through proxy to the Blizzard pet buttons for right-click
- -- Note that technically this doesn't do PetStopAttack() when
- -- IsPetAttackActive() is true: however that's only true when using
- -- Eyes of the Beast and appears not to really do anything (at least
- -- I can't find any difference)
- f:SetAttribute("type","pet")
- f:SetAttribute("type2","click")
- f:SetAttribute("clickbutton2",_G["PetActionButton"..config.actionID])
- f:SetAttribute("action",config.actionID)
- f:SetAttribute("checkselfcast", true)
- f:SetAttribute("checkfocuscast", true)
-
- -- non secure scripts
- f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
- f:SetScript("OnEnter", function(frame) self:OnEnter() end)
- f:SetScript("OnLeave", function(frame) self:OnLeave() end)
- f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
- f:SetScript("PreClick", function(frame) self:PreClick() end)
- f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
- f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
-
- -- secure handlers
- barFrame:WrapScript(f, "OnDragStart", _onDragStart)
- barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
-
- -- event registration
- f:EnableMouse(true)
- f:RegisterForDrag("LeftButton", "RightButton")
- f:RegisterForClicks("AnyUp")
- for _, evt in pairs(eventList) do
- f:RegisterEvent(evt)
- end
-
- -- attach to skinner
- bar:SkinButton(self,
- {
- AutoCast = f.autoCastShine,
- AutoCastable = f.autoCastTexture
- })
-
- self:Refresh()
- f:Show()
-
- return self
-end
-
-function Pet:SetupBar(bar)
- Super.SetupBar(self,bar)
-
- -- auto show/hide when pet exists
- bar:RegisterUnitWatch("pet",true)
-
- self:UpdateButtonLock(bar)
-end
-
-function Pet:UpdateButtonLock(bar)
- local f = bar:GetFrame()
- f:SetAttribute("lockbuttons",bar.config.lockButtons)
- f:SetAttribute("lockbuttonscombat",bar.config.lockButtonsCombat)
- f:Execute(
- [[
- lockButtons = self:GetAttribute("lockbuttons")
- lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
- ]])
-end
-
-function Pet:Refresh()
- Super.Refresh(self)
- self:Update()
- self:UpdateHotkey()
-end
-
-function Pet:GetActionID()
- return self.config.actionID
-end
-
-function Pet:SetActionID(id)
- if not InCombatLockdown() then
- if id < 0 or id > 10 then
- ReAction:UserError(L["Pet action ID range is 1-10"])
- return
- end
- self.config.actionID = id
- f:SetAttribute("clickbutton2",_G["PetActionButton"..id])
- f:SetAttribute("action",id)
- self:Update()
- self:UpdateHotkey()
- end
-end
-
-function Pet:Update()
- local action = self.config.actionID
- local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(action)
- local f = self:GetFrame()
- local icon = self.frames.icon
-
- if isToken then
- icon:SetTexture(_G[texture])
- self.tooltipName = _G[name]
- else
- icon:SetTexture(texture)
- self.tooltipName = name
- end
-
- self.isToken = isToken
- self.tooltipSubtext = subtext
- f:SetChecked( isActive and 1 or 0 )
-
- if autoCastAllowed then
- f.autoCastTexture:Show()
- else
- f.autoCastTexture:Hide()
- end
-
- if autoCastEnabled then
- AutoCastShine_AutoCastStart(f.autoCastShine)
- else
- AutoCastShine_AutoCastStop(f.autoCastShine)
- end
-
- if texture then
- if GetPetActionSlotUsable(action) then
- SetDesaturation(icon,nil)
- else
- SetDesaturation(icon,1)
- end
- icon:Show()
- f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
- else
- icon:Hide()
- f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
- end
-
- self:UpdateCooldown()
-end
-
-function Pet:UpdateCooldown()
- CooldownFrame_SetTimer(self.frames.cooldown, GetPetActionCooldown(self.config.actionID))
-end
-
-function Pet:SetTooltip()
- if self.tooltipName then
- local f = self:GetFrame()
- local uber = GetCVar("UberTooltips")
- if self.isToken or (uber == "0") then
- if uber == "0" then
- GameTooltip:SetOwner(f, "ANCHOR_RIGHT")
- else
- GameTooltip_SetDefaultAnchor(GameTooltip, f)
- end
- GameTooltip:SetText(self.tooltipName)
- if self.tooltipSubtext then
- GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5)
- end
- GameTooltip:Show()
- else
- GameTooltip_SetDefaultAnchor(GameTooltip, f)
- GameTooltip:SetPetAction(self.config.actionID)
- end
- else
- GameTooltip:Hide()
- end
-end
-
-function Pet:OnEvent(event, unit)
- if event =="PET_BAR_UPDATE_COOLDOWN" then
- self:UpdateCooldown()
- elseif event == "UPDATE_BINDINGS" then
- self:UpdateHotkey()
- elseif event == "UNIT_PET" then
- if unit == "player" then
- self:Update()
- end
- elseif event == "UNIT_FLAGS" or event == "UNIT_AURA" then
- if unit == "pet" then
- self:Update()
- end
- else
- self:Update()
- end
-end
-
-function Pet:OnEnter()
- self:SetTooltip()
-end
-
-function Pet:OnLeave()
- GameTooltip:Hide()
-end
-
-function Pet:OnAttributeChanged(attr,value)
- self:Update()
-end
-
-function Pet:PreClick()
- self:GetFrame():SetChecked(0)
-end
-
-function Pet:OnDragStart()
- self:SetChecked(0)
- self:Update()
-end
-
-function Pet:OnReceiveDrag()
- self:SetChecked(0)
- self:Update()
-end
-
diff -r f255cd69e890 -r 65f2805957a0 classes/StanceButton.lua
--- a/classes/StanceButton.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local GetCVar = GetCVar
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local InCombatLockdown = InCombatLockdown
-local GetNumShapeshiftForms = GetNumShapeshiftForms
-local GetShapeshiftFormInfo = GetShapeshiftFormInfo
-local IsUsableSpell = IsUsableSpell
-local GetSpellInfo = GetSpellInfo
-
---
--- private
---
-local playerClass = select(2,UnitClass("player"))
-
-local eventList = {
- "PLAYER_REGEN_ENABLED",
- "PLAYER_ENTERING_WORLD",
- "UPDATE_SHAPESHIFT_FORM",
- "UPDATE_SHAPESHIFT_FORMS",
- "UPDATE_SHAPESHIFT_USABLE",
- "UPDATE_SHAPESHIFT_COOLDOWN",
- "UPDATE_BINDINGS",
-}
-
---
--- Stance Button class
---
-local buttonTypeID = "Stance"
-local Super = ReAction.Button
-local Stance = setmetatable(
- {
- defaultConfig = {
- type = buttonTypeID,
- btnHeight = 36,
- btnWidth = 36,
- btnRows = 1,
- btnColumns = 6,
- spacing = 3
- },
-
- barType = L["Stance Bar"],
- buttonTypeID = buttonTypeID
- },
- { __index = Super } )
-
-ReAction.Button.Stance = Stance
-ReAction:RegisterBarType(Stance)
-
-function Stance:New( config, bar, idx, idHint )
- local name = format("ReAction_%s_Stance_%d",bar:GetName(),idx)
-
- self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
-
- local f = self:GetFrame()
- local barFrame = bar:GetFrame()
- local config = self:GetConfig()
-
- -- set up the base stance ID
- self:SetActionIDPool("stance",8)
- config.stanceID = self:AcquireActionID(config.stanceID, idHint, true)
-
- -- attribute setup
- f:SetAttribute("type","spell")
-
- -- non secure scripts
- f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
- f:SetScript("OnEnter", function(frame) self:OnEnter() end)
- f:SetScript("OnLeave", function(frame) self:OnLeave() end)
- f:SetScript("PreClick", function(frame, ...) self:PreClick(...) end)
-
- -- secure handlers
- -- (none)
-
- -- event registration
- f:EnableMouse(true)
- f:RegisterForClicks("AnyUp")
- for _, evt in pairs(eventList) do
- f:RegisterEvent(evt)
- end
-
- -- attach to skinner
- bar:SkinButton(self)
-
- -- initial display
- if ReAction:GetConfigMode() then
- self:GetFrame():Show()
- end
-
- self:Refresh()
-
- return self
-end
-
-function Stance:GetActionID()
- return self.config.stanceID
-end
-
-function Stance:UpdateAction()
- if InCombatLockdown() then
- self.updatePending = true
- else
- self.updatePending = false
- local idx = self:GetActionID()
- local f = self:GetFrame()
- if idx > GetNumShapeshiftForms() then
- f:Hide()
- else
- f:SetAttribute("spell", select(2,GetShapeshiftFormInfo(idx)))
- f:Show()
- self:Update()
- end
- end
-end
-
-function Stance:Refresh()
- Super.Refresh(self)
- self:UpdateHotkey()
- self:UpdateAction()
-end
-
-function Stance:Update()
- local texture, _, isActive, isCastable = GetShapeshiftFormInfo(self:GetActionID())
-
- local icon = self.frames.icon
- icon:SetTexture(texture)
- self:GetFrame():SetChecked( isActive and 1 or 0 )
- if isCastable then
- self.frames.hotkey:Show()
- icon:SetVertexColor(1.0, 1.0, 1.0)
- else
- icon:SetVertexColor(0.4, 0.4, 0.4)
- end
-
- self:UpdateCooldown()
-end
-
-function Stance:UpdateCooldown()
- local start, duration, enabled = GetShapeshiftFormCooldown(self:GetActionID())
- if start then
- CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enabled)
- end
-end
-
-function Stance:SetTooltip()
- if GetCVar("UberTooltips") == "1" then
- GameTooltip_SetDefaultAnchor(GameTooltip, self:GetFrame())
- else
- GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT")
- end
- GameTooltip:SetShapeshift(self:GetActionID())
-end
-
-function Stance:OnEnter()
- self:SetTooltip()
-end
-
-function Stance:OnLeave()
- GameTooltip:Hide()
-end
-
-function Stance:PreClick()
- local f = self:GetFrame()
- f:SetChecked( not f:GetChecked() )
-end
-
-function Stance:OnEvent(event, arg)
- if event == "PLAYER_REGEN_ENABLED" then
- if self.updatePending then
- self:UpdateAction()
- end
- elseif event == "UPDATE_SHAPESHIFT_COOLDOWN" then
- self:UpdateCooldown()
- elseif event == "UPDATE_SHAPESHIFT_FORMS" then
- self:UpdateAction()
- elseif event == "UNIT_AURA" then
- if arg == "player" then
- self:Update()
- end
- elseif event == "UPDATE_BINDINGS" then
- self:UpdateHotkey()
- else
- self:Update()
- end
-end
-
-function Stance:ShowGridTemp(show)
- if show then
- self:GetFrame():Show()
- else
- self:UpdateAction()
- end
-end
diff -r f255cd69e890 -r 65f2805957a0 classes/VehicleExitButton.lua
--- a/classes/VehicleExitButton.lua Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local format = string.format
-
---
--- VExitButton Button class
---
-local buttonTypeID = "VehicleExit"
-local Super = ReAction.Button
-local VExitButton = setmetatable(
- {
- defaultBarConfig = {
- type = buttonTypeID ,
- btnWidth = 36,
- btnHeight = 36,
- btnRows = 1,
- btnColumns = 1,
- spacing = 3,
- buttons = { }
- },
-
- barType = L["Exit Vehicle Floater"],
- buttonTypeID = buttonTypeID
- },
- { __index = Super } )
-
-ReAction.Button.VehicleExit = VExitButton
-ReAction:RegisterBarType(VExitButton)
-
-function VExitButton:New( config, bar, idx )
- local name = format("ReAction_%s_VehicleExit_%d",bar:GetName(),idx)
-
- self = Super.New(self, name, config, bar, idx, "SecureFrameTemplate, ActionButtonTemplate", "Button")
-
- -- frame setup
- local f = self:GetFrame()
- self.frames.icon:SetTexture("Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up")
- self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
-
- -- attribute setup
- -- (none)
-
- -- non secure scripts
- f:SetScript("OnClick", VehicleExit)
- f:SetScript("OnEnter", function(frame) GameTooltip_AddNewbieTip(frame, LEAVE_VEHICLE, 1.0, 1.0, 1.0, nil) end)
- f:SetScript("OnLeave", GameTooltip_Hide)
- f:SetScript("OnEvent", function(frame, evt, ...) self:OnEvent(evt,...) end)
-
- -- event registration
- f:EnableMouse(true)
- f:RegisterForClicks("AnyUp")
- f:RegisterEvent("UPDATE_BINDINGS")
-
- -- attach to skinner
- bar:SkinButton(self)
-
- self:Refresh()
- self:UpdateHotkey()
-
- return self
-end
-
-function VExitButton:SetupBar(bar)
- Super.SetupBar(self,bar)
- self:UpdateRegistration(bar)
-end
-
-function VExitButton:GetActionID()
- return 1
-end
-
-function VExitButton:Refresh()
- Super.Refresh(self)
- -- it seems that setscale kills the texcoord, have to refresh it
- self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
-end
-
-function VExitButton:OnEvent(event, ...)
- if self[event] then
- self[event](self, event, ...)
- end
-end
-
-function VExitButton:UPDATE_BINDINGS()
- self:UpdateHotkey()
-end
-
-function VExitButton:UpdateRegistration(bar)
- -- auto show/hide when on a vehicle
- local config = bar:GetConfig()
- local f = bar:GetFrame()
- if config.withControls then
- if bar.vehicleExitStateRegistered then
- UnregisterStateDriver(f, "unitexists")
- bar.vehicleExitStateRegistered = false
- end
- bar:RegisterUnitWatch("vehicle",true)
- else
- bar:RegisterUnitWatch("vehicle",false)
- if not bar.vehicleExitStateRegistered then
- f:SetAttribute("unit","vehicle")
- RegisterStateDriver(f, "unitexists", "[target=vehicle,exists,novehicleui] show; hide") -- spoof onstate-unitexists
- bar.vehicleExitStateRegistered = true
- end
- end
-end
-
diff -r f255cd69e890 -r 65f2805957a0 classes/classes.xml
--- a/classes/classes.xml Sat Mar 26 12:26:55 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file