Mercurial > wow > reaction
diff classes/ReAction.lua @ 7:f920db5fc6b1
version 0.3
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Tue, 20 Mar 2007 21:25:29 +0000 |
parents | dfd829db3ad0 |
children | c05fd3e18b4f |
line wrap: on
line diff
--- a/classes/ReAction.lua Tue Mar 20 21:20:20 2007 +0000 +++ b/classes/ReAction.lua Tue Mar 20 21:25:29 2007 +0000 @@ -1,19 +1,39 @@ +-- +-- ReAction is a base class for action button management. It provides a +-- framework for button setup, placement, recycling, keybinding, etc. +-- It does not define any layout or actual action functionality, +-- which is deferred to derived classes. +-- +-- ReAction implements the ReBar.IButton interface. It is designed to be used with ReBar +-- for grouping and laying out buttons. +-- +-- ReAction supports the ReBound keybinding interface (only). +-- +-- Each instance of a ReAction-derived object is associated with a single action +-- button frame, which may or may not have a one-to-one mapping with actionID. +-- +-- ReAction makes use of a configuration structure, which can (and should) be +-- extended by implementations. A single config structure is shared amongst all +-- ReAction class instances within a single ReBar group, so the structure should +-- contain sub-tables for any property that needs to be defined on a per-button +-- basis. Each button is passed a 'barIdx' parameter to be used as an index into +-- such tables. +-- +-- The base config structure is as follows: +-- +-- config = { +-- type = "ReAction", -- static string (used by ReBar) +-- subtype = "string", -- ReAction implementation identifier (index into ReAction.buttonTypes) +-- ids = { {paged list}, {paged list}, ... } -- indexed by self.barIdx +-- } +-- + + +local AceOO = AceLibrary("AceOO-2.0") +local kbValidate = AceLibrary("AceConsole-2.0").keybindingValidateFunc + + -- private constants -local namePrefix = "ReActionButton" -local _G = getfenv(0) -local ACTION_FREE = { } -local MAX_ACTIONS = 120 - -local hotKeyDefaultColor = { r=1.0, g=1.0, b=1.0, a=1.0 } -local hotKeyDisabledColor = { r=0.6, g=0.6, b=0.6, a=1.0 } -local hotKeyOutOfRangeColor = { r=1.0, g=0.2, b=0.2, a=1.0 } - -local hotKeyModifierColors = { - S = { r=0.6, g=0.6, b=1.0, a=1.0 }, -- shift - C = { r=1.0, g=0.82, b=0, a=1.0 }, -- ctrl - A = { r=0.1, g=1.0, b=0.1, a=1.0 }, -- alt -} - -- TODO: localize these key names with GetBindingText(KEY_) local keybindAbbreviations = { ["Mouse Button "] = "M-", @@ -24,750 +44,324 @@ [" Arrow"] = "", } -local equippedActionBorderColor = { r=0, g=1.0, b=0, a=0.35 } -local actionUsableColor = { r=1.0, g=1.0, b=1.0, a=1.0 } -local actionNotUsableColor = { r=0.4, g=0.4, b=0.4, a=1.0 } -local actionNotEnoughManaColor = { r=0.2, g=0.2, b=0.7, a=1.0 } -local actionOutOfRangeColor = { r=1.0, g=0.2, b=0.2, a=1.0 } +------------------------ +-- Interface Declarations +------------------------ --- private variables -local kbValidate = AceLibrary("AceConsole-2.0").keybindingValidateFunc -local actionButtonTbl = { } +-- The ActionType interface defines what the button does when it is clicked. At a +-- minimum it must do the equivalent of SetAttribute("type", ...) and handle events that +-- cause the action to change. +-- ReAction implementations must provide this interface (implicitly or explicitly). +local IActionType = AceOO.Interface { + SetID = "function", -- SetID(id, [page]) optional argument indicates page #: omitting indicates default. self.config.idx[barIdx] must be updated. + GetID = "function", -- id = GetID([page]) optional argument indicates page #: omitting indicates current page + IsActionEmpty = "function", -- bool = IsActionEmpty() + SetupAction = "function", -- one-time setup + UpdateAction = "function", -- general action properties should be refreshed + PickupAction = "function", -- pick up the action on the button and put on the cursor + PlaceAction = "function", -- place the action on the cursor + UpdateTooltip = "function", -- update the tooltip with the action's info +} +-- The Display interface defines the "look and feel" of the action button. It should define the +-- actual widgets and widget layout and provide methods to update the display. +-- ReAction implementations must provide this interface (implicitly or explicitly). +-- Note that ReAction implementations may also require additional display interfaces to be supported. +-- +-- Also note: the class 'new' method must take *only* the primary button ID as an argument. +local IDisplay = AceOO.Interface { + SetupDisplay = "function", -- SetupDisplay(buttonName), one-time setup + UpdateDisplay = "function", -- UpdateDisplay(), general display state should be refreshed + TempShow = "function", -- TempShow(visible), calls to this can be nested so keep track. + GetActionFrame = "function", -- f = GetActionFrame(), return a frame derived from SecureActionButtonTemplate (note: this is inherited unimplemented from ReBar.IButton) + GetBaseButtonSize = "function", -- sz = GetBaseButtonSize(), return size in pixels of the nominal button (square) + DisplayID = "function", -- DisplayID(id), show the action ID (or equivalent). Pass nil to hide. + DisplayHotkey = "function", -- DisplayHotkey(keyText), set the hotkey display text +} --- ReActionButton is a class prototype object. -ReActionButton = AceLibrary("AceOO-2.0").Class("AceEvent-2.0") +---------------------------- +-- ReAction class definition +---------------------------- -------------------- --- Class methods -------------------- +ReAction = AceOO.Class("AceEvent-2.0", ReBar.IButton, IActionType, IDisplay) +ReAction.virtual = true +ReAction.IActionType = IActionType +ReAction.IDisplay = IDisplay --- In addition to supporting the 'new' creation method (in which case an action ID must be specified directly), --- ReActionButton supports the 'acquire'/'release' creation method, which recycles objects and manages actionID assignment. -function ReActionButton:acquire(parent, config, barIdx) +----------------------- +-- Static class members +----------------------- + +ReAction.recycler = CreateFrame("Frame",nil,UIParent) +ReAction.recycler:SetAllPoints(UIParent) +ReAction.recycler:Hide() + +ReAction.buttonTypes = { } + + + +----------------------- +-- Static class methods +----------------------- + +function ReAction:AddButtonType( name, class, maxIDs ) + self.buttonTypes[name] = { subtype = class, maxIDs = maxIDs } +end + +function ReAction:GetButtonType( name ) + if name then + local t = self.buttonTypes[name] + if t then + return t.subtype, t.maxIDs + end + end +end + +function ReAction:GetButtonTypeList() + local list = { } + for name, _ in pairs(self.buttonTypes) do + table.insert(list,name) + end + return list +end + +function ReAction:GetAvailableID( subtype, hint ) + local class, maxIDs = self:GetButtonType(subtype) + + -- store the list of action buttons in use in the button type class factory + if class._idTbl == nil then class._idTbl = { } end + local t = class._idTbl local id = nil - for i = 1, MAX_ACTIONS do - if actionButtonTbl[i] == nil or actionButtonTbl[i].inUse == false then + + -- find lowest ID not in use + for i = 1, maxIDs do + if t[i] == nil or t[i].inUse == false then id = i break end end - if id == nil then return nil end -- all buttons and action ids are in use + if id == nil then return nil end -- all action ids are in use - local hint = config.actionIDs[barIdx] - if hint and (actionButtonTbl[hint] == nil or actionButtonTbl[hint].inUse == false) then + -- if a hint is given, see if that one is free instead + if hint and (t[hint] == nil or t[hint].inUse == false) then id = hint end - if actionButtonTbl[id] == nil then - actionButtonTbl[id] = { } + if t[id] == nil then + t[id] = { } end - local t = actionButtonTbl[id] + t[id].inUse = true - t.inUse = true - if t.button then - t.button:Configure(parent,config,barIdx) - else - t.button = self:new(parent,config,barIdx,id) + return id, t[id] +end + +function ReAction:Acquire(config, barIdx, pages, buttonsPerPage) + local btnType = self:GetButtonType(config.subtype) + if not btnType then + error("ReAction: Unknown button type specified.") + end + pages = pages or 1 + + local ids = { } + local primary = nil + + for i = 1, pages do + local hint = config.ids[barIdx] and config.ids[barIdx][i] + if hint == nil and i > 1 and ids[i-1] then + hint = ids[i-1] + (buttonsPerPage or 0) + end + local id, p = self:GetAvailableID(config.subtype, hint) + if id == nil then + break + end + primary = primary or p + if id then + ids[i] = id + end end - -- fix screwy config with overlapping IDs - config.actionIDs[barIdx] = id - return t.button + if primary then + if not primary.button then + primary.button = btnType:new(ids[1]) + end + if primary.button then + config.ids[barIdx] = ids + primary.button:Configure(config,barIdx) + end + end + + return primary and primary.button end -function ReActionButton:release( b ) +function ReAction:Release( b ) if b then - actionButtonTbl[b:GetActionID()].inUse = false + for i = 1, #b.config.ids[b.barIdx] do + local id = b:GetID(i) + if id then + b.class._idTbl[id].inUse = false + end + end + b.config = nil b:Recycle() end end - - -function ReActionButton:ShowAllActionIDs() - for _, b in ipairs(actionButtonTbl) do - b:ShowActionID() +function ReAction:ShowAllIds() + for _, t in pairs(self.buttonTypes) do + if t.subtype._idTbl then + for _, tbl in pairs(t.subtype._idTbl) do + if tbl.button then tbl.button:DisplayID(tbl.button:GetID()) end + end + end end + self.showIDs_ = true end -function ReActionButton:HideAllActionIDs() - for _, b in ipairs(actionButtonTbl) do - b:HideActionID() +function ReAction:HideAllIds() + for _, t in pairs(self.buttonTypes) do + if t.subtype._idTbl then + for _, tbl in pairs(t.subtype._idTbl) do + if tbl.button then tbl.button:DisplayID(nil) end + end + end end + self.showIDs_ = false end ---------------------- -- Instance methods ---------------------- -function ReActionButton.prototype:init( parentFrame, config, barIdx, id ) - ReActionButton.super.prototype.init(self) - -- create the button widget - self.name = namePrefix..id - self.button = CreateFrame("CheckButton", self.name, parentFrame, "ReActionButtonTemplate") - - -- store references to the various sub-frames so we don't have to look it up all the time - self.frames = { - hotkey = _G[self.name.."HotKey"], - count = _G[self.name.."Count"], - cooldown = _G[self.name.."Cooldown"], --- nCooldown = _G[self.name.."CooldownNumeric"], - macro = _G[self.name.."Name"], - icon = _G[self.name.."Icon"], - border = _G[self.name.."Border"], - normalTexture = _G[self.name.."NormalTexture"], - flash = _G[self.name.."Flash"], - actionID = _G[self.name.."ActionID"], - } +-- constructor - -- provide a reference back to this object for the frame to use in event handlers - self.button.rxnBtn = self - - -- set the action ID - self:SetActionID(id) - - -- register button with ReBinder for keybinding - ReBinder:AddKeybindTarget(self.button) - - -- initialize - self:Configure(parentFrame, config, barIdx) +function ReAction.prototype:init() + ReAction.super.prototype.init(self) end -local function tcopy(t) - local r = { } - for k, v in pairs(t) do - r[k] = (type(v) == "table" and tcopy(v) or v) - end - return r + +-- ReBar.IButton interface + +function ReAction.prototype:BarUnlocked() + self:TempShow(true) end -function ReActionButton.prototype:Recycle() - local b = self.button - - self:SetKeyBinding(nil) - self:UpdateDisplay() - b:UnregisterAllEvents() - b:SetParent(ReActionButtonRecycleFrame) - b:ClearAllPoints() - b:SetPoint("TOPLEFT",0,0) - b:Hide() - self.config = tcopy(self.config) -- ew, but necessary +function ReAction.prototype:BarLocked() + self:TempShow(false) end -function ReActionButton.prototype:BarUnlocked() - self:ShowGridTmp() -end - -function ReActionButton.prototype:BarLocked() - self:HideGridTmp() -end - - --- set the button location -function ReActionButton.prototype:PlaceButton(point, x, y, sz) - local b = self.button - local scale = sz / 36 +function ReAction.prototype:PlaceButton(parent, point, x, y, sz) + local b = self:GetActionFrame() + local baseSize = self:GetBaseButtonSize() + local scale = baseSize and baseSize ~= 0 and ((sz or 1) / baseSize) or 1 + if scale == 0 then scale = 1 end b:ClearAllPoints() - b:SetScale( scale ) + b:SetParent(parent) + b:SetScale(scale) b:SetPoint(point,x/scale,y/scale) end - -function ReActionButton.prototype:ShowActionID() - self.frames.actionID:Show() -end - -function ReActionButton.prototype:HideActionID() - self.frames.actionID:Hide() -end - - - --- configuration and setup -function ReActionButton.prototype:Configure( parentFrame, config, barIdx ) - self.config = config - self.barIdx = barIdx - self.showGridTmp_ = 0 - - self.button:ClearAllPoints() - self.button:SetParent(parentFrame) - - self:SetupAttributes() - self:RegisterStaticEvents() - - self:ApplyLayout() - self:ApplyStyle() - - self:UpdateDisplay() -end - -function ReActionButton.prototype:SetupAttributes() - local b = self.button - b:SetAttribute("type", "action") - b:SetAttribute("shift-type*", ATTRIBUTE_NOOP) - b:SetAttribute("checkselfcast", true) - b:SetAttribute("useparent-unit", true) -end - -function ReActionButton.prototype:RegisterStaticEvents() - self:RegisterEvent("PLAYER_ENTERING_WORLD") - self:RegisterEvent("ACTIONBAR_SLOT_CHANGED") - self:RegisterEvent("UPDATE_BINDINGS") - self:RegisterEvent("ACTIONBAR_SHOWGRID") - self:RegisterEvent("ACTIONBAR_HIDEGRID") -end - -function ReActionButton.prototype:RegisterActionEvents() - self:RegisterEvent("ACTIONBAR_UPDATE_STATE") - self:RegisterEvent("ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("UPDATE_INVENTORY_ALERTS", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("PLAYER_AURAS_CHANGED", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("PLAYER_TARGET_CHANGED", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("UNIT_INVENTORY_CHANGED") - self:RegisterEvent("CRAFT_SHOW") - self:RegisterEvent("CRAFT_CLOSE", "CRAFT_SHOW") - self:RegisterEvent("TRADE_SKILL_SHOW", "CRAFT_SHOW") - self:RegisterEvent("TRADE_SKILL_CLOSE", "CRAFT_SHOW") - self:RegisterEvent("PLAYER_ENTER_COMBAT", "CRAFT_SHOW") - self:RegisterEvent("PLAYER_LEAVE_COMBAT") - self:RegisterEvent("START_AUTOREPEAT_SPELL") - self:RegisterEvent("STOP_AUTOREPEAT_SPELL") - - self.button:SetScript("OnUpdate", function() self:OnUpdate(arg1) end) - self.actionEventsRegistered = true -end - -function ReActionButton.prototype:UnregisterActionEvents() - self:UnregisterEvent("ACTIONBAR_UPDATE_STATE") - self:UnregisterEvent("ACTIONBAR_UPDATE_USABLE") - self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN") - self:UnregisterEvent("UPDATE_INVENTORY_ALERTS") - self:UnregisterEvent("PLAYER_AURAS_CHANGED") - self:UnregisterEvent("PLAYER_TARGET_CHANGED") - self:UnregisterEvent("UNIT_INVENTORY_CHANGED") - self:UnregisterEvent("CRAFT_SHOW") - self:UnregisterEvent("CRAFT_CLOSE") - self:UnregisterEvent("TRADE_SKILL_SHOW") - self:UnregisterEvent("TRADE_SKILL_CLOSE") - self:UnregisterEvent("PLAYER_ENTER_COMBAT") - self:UnregisterEvent("PLAYER_LEAVE_COMBAT") - self:UnregisterEvent("START_AUTOREPEAT_SPELL") - self:UnregisterEvent("STOP_AUTOREPEAT_SPELL") - - self.button:SetScript("OnUpdate", nil) - self.actionEventsRegistered = false -end - - --- event handlers -function ReActionButton.prototype:ACTIONBAR_SLOT_CHANGED() - if arg1 == 0 or arg1 == self:GetActionID() then - self:UpdateDisplay() - end -end - -function ReActionButton.prototype:PLAYER_ENTERING_WORLD() - self:UpdateDisplay() -end - -function ReActionButton.prototype:UPDATE_BINDINGS() - self:UpdateDisplay() -end - -function ReActionButton.prototype:ACTIONBAR_SHOWGRID() - self:ShowGridTmp() -end - -function ReActionButton.prototype:ACTIONBAR_HIDEGRID() - self:HideGridTmp() -end - -function ReActionButton.prototype:ACTIONBAR_UPDATE_STATE() - self:UpdateCheckedState() -end - -function ReActionButton.prototype:ACTIONBAR_UPDATE_USABLE() - self:UpdateUsable() - self:UpdateCooldown() - self:ColorHotKey() -end - -function ReActionButton.prototype:UNIT_INVENTORY_CHANGED() - if arg1 == "player" then - self:UpdateDisplay() - end -end - -function ReActionButton.prototype:CRAFT_SHOW() - self:UpdateCheckedState() -end - -function ReActionButton.prototype:PLAYER_ENTER_COMBAT() - if IsAttackAction(self:GetActionID()) then - self:StartFlash() - end -end - -function ReActionButton.prototype:PLAYER_LEAVE_COMBAT() - if IsAttackAction(self:GetActionID()) then - self:StopFlash() - end -end - -function ReActionButton.prototype:START_AUTOREPEAT_SPELL() - if IsAutoRepeatAction(self:GetActionID()) then - self:StartFlash() - end -end - -function ReActionButton.prototype:STOP_AUTOREPEAT_SPELL() - if self:IsFlashing() and not IsAttackAction(self:GetActionID()) then - self:StopFlash() - end -end - - --- OnUpdate handler -function ReActionButton.prototype:OnUpdate(elapsed) - local action = self:GetActionID() - local f = self.frames - - -- handle flashing - if self:IsFlashing() then - self.flashtime = self.flashtime - elapsed - if self.flashtime <= 0 then - local overtime = -self.flashtime - if overtime >= ATTACK_BUTTON_FLASH_TIME then - overtime = 0 - end - self.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime - - if f.flash:IsVisible() then - f.flash:Hide() - else - f.flash:Show() - end - end - end - - -- Handle range indicator - if self.rangeTimer then - self.rangeTimer = self.rangeTimer - elapsed - if self.rangeTimer <= 0 then - self:ColorHotKey() - self:UpdateUsable() - self.rangeTimer = TOOLTIP_UPDATE_TIME - end - end - - -- handle toltip update - if self.tooltipTime then - self.tooltipTime = self.tooltipTime - elapsed - if self.tooltipTime <= 0 then - if GameTooltip:IsOwned(self.button) then - self:UpdateTooltip() - else - self.tooltipTime = nil +function ReAction.prototype:SetPages( n ) + n = tonumber(n) + local ids = self.config.ids[self.barIdx] + if n and n >= 1 then + -- note that as long as n >= 1 then id[1] will never be modified, which is what we want + -- because then the button frame ID would be out of sync with the static button name + while #ids < n do + local id = ReAction:GetAvailableID(self.config.subtype, ids[#ids] + #self.config.ids) + if id == nil then + break end + self:SetID( id, #ids + 1 ) + table.insert(ids, id) + end + while #ids > n do + local id = table.remove(ids) + self:SetID( nil, #ids + 1 ) + self.class._idTbl[id].inUse = false end end end +-- Event handlers +function ReAction.prototype:UPDATE_BINDINGS() + self:DisplayHotkey(self:GetKeyBindingText(nil, true)) +end --- keybinding functions -function ReActionButton.prototype:SetKeyBinding( k ) +-- Internal functions + +function ReAction.prototype:Recycle() + --self:SetKeyBinding(nil) -- TODO: only if we're using override bindings + self:UnregisterAllEvents() + + -- tuck the frame away + local b = self:GetActionFrame() + b:SetParent(ReAction.recycler) + b:ClearAllPoints() + b:SetPoint("TOPLEFT",0,0) + b:Hide() +end + +function ReAction.prototype:Configure( config, barIdx ) + self.config = config + self.barIdx = barIdx + + local ids = config.ids[barIdx] + self:SetID(ids[1]) -- default id + for i = 1, #ids do + self:SetID(ids[i], i) -- paged ids + end + self:UpdateAction() + self:UpdateDisplay() + self:DisplayHotkey(self:GetKeyBindingText(nil, true)) + + self:RegisterEvent("UPDATE_BINDINGS") +end + +function ReAction.prototype:SetKeyBinding( k, mouseBtn ) if k == nil or kbValidate(k) then - local current = self:GetKeyBinding() - ClearOverrideBindings(self.button) + local current = self:GetKeyBinding(mouseBtn) + -- !!!TODO: do we need this? + -- ClearOverrideBindings(self:GetActionFrame()) if current then SetBinding(current,nil) end if k then - SetBindingClick(k, self.name, "LeftButton") + -- TODO: use OverrideBinding and store the keybinding in the profile. + SetBindingClick(k, self:GetActionFrame():GetName(), mouseBtn or "LeftButton") end end end -function ReActionButton.prototype:GetKeyBinding() - return GetBindingKey("CLICK "..self.name..":LeftButton") +function ReAction.prototype:GetKeyBinding( mouseBtn ) + return GetBindingKey("CLICK "..self:GetActionFrame():GetName()..":"..(mouseBtn or "LeftButton")) end --- action ID functions -function ReActionButton.prototype:SetActionID( id ) - self.actionID = tonumber(id) -- force data integrity - self:ApplyActionID() +function ReAction.prototype:GetKeyBindingText( mouseBtn, abbrev ) + local key = self:GetKeyBinding(mouseBtn) + local txt = key and GetBindingText(key, "KEY_", abbrev and 1) or "" + + if txt and abbrev then + -- further abbreviate some key names + for pat, rep in pairs(keybindAbbreviations) do + txt = string.gsub(txt,pat,rep) + end + end + return txt end -function ReActionButton.prototype:GetActionID() - return self.actionID -end - -function ReActionButton.prototype:ApplyActionID() - local action = tonumber(self:GetActionID()) - self.button:SetAttribute("action",action) - self.frames.actionID:SetText(action or "") -end - -function ReActionButton.prototype:ShowActionID() - self.frames.actionID:Show() -end - -function ReActionButton.prototype:HideActionID() - self.frames.actionID:Hide() -end - -function ReActionButton:ShowAllActionIDs() -- class-wide function - for _, tbl in pairs(actionButtonTbl) do - if tbl.button then tbl.button:ShowActionID() end - end -end - -function ReActionButton:HideAllActionIDs() -- class-wide function - for _, tbl in pairs(actionButtonTbl) do - if tbl.button then tbl.button:HideActionID() end - end -end - - --- action transfer functions -function ReActionButton.prototype:ShouldPickupAction(mouseButton) - return IsShiftKeyDown() and not SecureButton_GetModifiedAttribute(self.button, "type", mouseButton) -end - -function ReActionButton.prototype:ShowGridTmp() - self.showGridTmp_ = self.showGridTmp_ + 1 - self:UpdateVisibility() -end - -function ReActionButton.prototype:HideGridTmp() - self.showGridTmp_ = self.showGridTmp_ - 1 - self:UpdateVisibility() -end - -function ReActionButton.prototype:ShowGrid() - self.config.showGrid = true - self:UpdateVisibility() -end - -function ReActionButton.prototype:HideGrid() - self.config.showGrid = false - self:UpdateVisibility() -end - - - --- layout & style functions -function ReActionButton.prototype:ApplyLayout() - local f = self.frames - - if self.config.keyBindLoc then - local h = f.hotkey - local loc = self.config.keyBindLoc - local top = string.match(loc,"TOP") - local bottom = string.match(loc, "BOTTOM") - h:ClearAllPoints() - h:SetWidth(40) - h:SetPoint(top or bottom,0,top and 2 or -2) - local j - if string.match(loc,"LEFT") then - j = "LEFT" - elseif string.match(loc,"RIGHT") then - j = "RIGHT" - else - j = "CENTER" - end - h:SetJustifyH(j) - end - - if self.config.stackCountLoc then - local c = f.count - local loc = self.config.stackCountLoc - local top = string.match(loc,"TOP") - local bottom = string.match(loc, "BOTTOM") - c:ClearAllPoints() - c:SetWidth(40) - c:SetPoint(top or bottom,0,top and 2 or -2) - local j - if string.match(loc,"LEFT") then - j = "LEFT" - elseif string.match(loc,"RIGHT") then - j = "RIGHT" - else - j = "CENTER" - end - c:SetJustifyH(j) - end - - if self.config.showKeyBind then - f.hotkey:Show() - else - f.hotkey:Hide() - end - - if self.config.showStackCount then - f.count:Show() - else - f.count:Hide() - end - ---[[ - if self.config.showNumericCooldown then - f.nCooldown:Show() - else - f.nCooldown:Hide() - end -]] - - if self.config.showMacroName then - f.macro:Show() - else - f.macro:Hide() - end -end - -function ReActionButton.prototype:ApplyStyle() - local f = self.frames - -- for now, just a static style - f.hotkey:SetFontObject(NumberFontNormal) - f.count:SetFontObject(NumberFontNormalYellow) -end - - - --- start/stop flashing -function ReActionButton.prototype:StartFlash() - self.flashing = true - self.flashtime = 0 - self:UpdateCheckedState() -end - -function ReActionButton.prototype:StopFlash() - self.flashing = false - self.frames.flash:Hide() - self:UpdateCheckedState() -end - -function ReActionButton.prototype:IsFlashing() - return self.flashing -end - - - - - --- set the tooltip -function ReActionButton.prototype:SetTooltip() - GameTooltip_SetDefaultAnchor(GameTooltip, self.button) +function ReAction.prototype:SetTooltip() + GameTooltip_SetDefaultAnchor(GameTooltip, self:GetActionFrame()) self:UpdateTooltip() end -function ReActionButton.prototype:ClearTooltip() +function ReAction.prototype:ClearTooltip() tooltipTime = nil GameTooltip:Hide() end - - - --- colorize the hotkey -function ReActionButton.prototype:ColorHotKey() - local action = self:GetActionID() - local c = hotKeyDefaultColor - - if action and HasAction(action) then - if IsActionInRange(action) == 0 then - c = hotKeyOutOfRangeColor - elseif self.config.keyBindColorCode then - local modKey = string.match( self.frames.hotkey:GetText() or "", "([ACS])%-") - c = modKey and hotKeyModifierColors[modKey] or c - end - else - c = hotKeyDisabledColor - end - - self.frames.hotkey:SetTextColor(c.r, c.g, c.b) -end - - - - --- display update functions -function ReActionButton.prototype:UpdateDisplay() - self:UpdateIcon() - self:UpdateHotkey() - self:UpdateCount() - self:UpdateMacroText() - self:UpdateUsable() - self:UpdateCooldown() - self:UpdateFlash() - self:UpdateEvents() - self:UpdateVisibility() - self:UpdateTooltip() -end - -function ReActionButton.prototype:UpdateIcon() - local f = self.frames - local b = self.button - - local action = self:GetActionID() - local texture = action and GetActionTexture(action) - - if action and texture then - f.icon:SetTexture(texture) - f.icon:Show() - self.rangeTimer = -1 - b:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2") - else - f.icon:Hide() - f.cooldown:Hide() - self.rangeTimer = nil - b:SetNormalTexture("Interface\\Buttons\\UI-Quickslot") - end - - self:UpdateCheckedState() - - -- Add a green border if action is an equipped item - if action and IsEquippedAction(action) then - local c = equippedActionBorderColor - f.border:SetVertexColor(c.r, c.g, c.b, c.a or 1) - f.border:Show() - else - f.border:Hide() - end -end - -function ReActionButton.prototype:UpdateCheckedState() - local action = self:GetActionID() - if action and (IsCurrentAction(action) or IsAutoRepeatAction(action)) then - self.button:SetChecked(1) - else - self.button:SetChecked(0) - end -end - - -function ReActionButton.prototype:UpdateHotkey() - local action = self:GetActionID() - local b = self.button - local f = self.frames - local key = self:GetKeyBinding() - local txt = GetBindingText(key, "KEY_",1) - - -- abbreviate long key names - for pat, rep in pairs(keybindAbbreviations) do - txt = string.gsub(txt,pat,rep) - end - - if txt then - f.hotkey:SetText(string.upper(txt)) - self:ColorHotKey() - else - f.hotkey:SetText("") - end -end - -function ReActionButton.prototype:UpdateCount() - local action = self:GetActionID() - if action and (IsConsumableAction(action) or IsStackableAction(action)) then - self.frames.count:SetText(GetActionCount(action)) - else - self.frames.count:SetText("") - end -end - -function ReActionButton.prototype:UpdateMacroText() - local action = self:GetActionID() - self.frames.macro:SetText(action and GetActionText(action) or "") -end - -function ReActionButton.prototype:UpdateUsable() - local f = self.frames - local action = self:GetActionID() - local isUsable, notEnoughMana - if action then - isUsable, notEnoughMana = IsUsableAction(action) - end - if isUsable then - local c = actionUsableColor - if IsActionInRange(action) == 0 then - c = actionOutOfRangeColor - else - f.normalTexture:SetVertexColor(c.r, c.g, c.b, c.a) - end - f.icon:SetVertexColor(c.r, c.g, c.b, c.a) - elseif notEnoughMana then - local c = actionNotEnoughManaColor - f.icon:SetVertexColor(c.r, c.g, c.b, c.a) - f.normalTexture:SetVertexColor(c.r, c.g, c.b, c.a) - else - local c = actionNotUsableColor - f.icon:SetVertexColor(c.r, c.g, c.b, c.a) - f.normalTexture:SetVertexColor(1.0, 1.0, 1.0) - end -end - -function ReActionButton.prototype:UpdateCooldown() - local action = self:GetActionID() - if action then - local start, duration, enable = GetActionCooldown(self:GetActionID()) - CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enable) - -- do numeric cooldown stuff here - end -end - -function ReActionButton.prototype:UpdateFlash() - local b = self.button - local action = self:GetActionID() - if action and ((IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action)) then - self:StartFlash() - else - self:StopFlash() - end -end - -function ReActionButton.prototype:UpdateVisibility() - local action = self:GetActionID() - local b = self.button - - if b:GetAttribute("statehidden") then - b:Hide() - elseif action and HasAction(action) then - b:GetNormalTexture():SetAlpha(1.0) - b:Show() - elseif self.showGridTmp_ > 0 or self.config.showGrid then - b:GetNormalTexture():SetAlpha(0.5) - self.frames.cooldown:Hide() - b:Show() - else - b:Hide() - end -end - -function ReActionButton.prototype:UpdateEvents() - local action = self:GetActionID() - if action and HasAction(action) then - self:RegisterActionEvents() - elseif self.actionEventsRegistered then - self:UnregisterActionEvents() - end -end - -function ReActionButton.prototype:UpdateTooltip() - local action = self:GetActionID() - if GameTooltip:IsOwned(self.button) and action and GameTooltip:SetAction(action) then - self.tooltipTime = TOOLTIP_UPDATE_TIME - else - self.tooltipTime = nil - end -end - - -