# HG changeset patch # User Flick # Date 1174425574 0 # Node ID dfd829db3ad07d21f65dcf54d3222eee453e3b0f # Parent f5607e135c37859433b14a9fa9005d3facf8cb05 diff -r f5607e135c37 -r dfd829db3ad0 Button.lua --- a/Button.lua Tue Mar 20 21:11:15 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,773 +0,0 @@ --- 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-", - ["Spacebar"] = "Sp", - ["Num Pad "] = "Num-", - ["Page Up"] = "PgUp", - ["Page Down"] = "PgDn", - [" 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 } - --- private variables -local kbValidate = AceLibrary("AceConsole-2.0").keybindingValidateFunc -local actionButtonTbl = { } - - - --- ReActionButton is a class prototype object. -ReActionButton = AceLibrary("AceOO-2.0").Class("AceEvent-2.0") - -------------------- --- Class methods -------------------- - --- 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) - local id = nil - for i = 1, MAX_ACTIONS do - if actionButtonTbl[i] == nil or actionButtonTbl[i].inUse == false then - id = i - break - end - end - - if id == nil then return nil end -- all buttons and action ids are in use - - local hint = config.actionIDs[barIdx] - if hint and (actionButtonTbl[hint] == nil or actionButtonTbl[hint].inUse == false) then - id = hint - end - - if actionButtonTbl[id] == nil then - actionButtonTbl[id] = { } - end - local t = actionButtonTbl[id] - - t.inUse = true - if t.button then - t.button:Configure(parent,config,barIdx) - else - t.button = self:new(parent,config,barIdx,id) - end - - -- fix screwy config with overlapping IDs - config.actionIDs[barIdx] = id - return t.button -end - -function ReActionButton:release( b ) - if b then - actionButtonTbl[b:GetActionID()].inUse = false - b:Recycle() - end -end - - - -function ReActionButton:ShowAllActionIDs() - for _, b in ipairs(actionButtonTbl) do - b:ShowActionID() - end -end - -function ReActionButton:HideAllActionIDs() - for _, b in ipairs(actionButtonTbl) do - b:HideActionID() - end -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"], - } - - -- 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) -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 -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 -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 - b:ClearAllPoints() - 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 - end - end - end -end - - - - --- keybinding functions -function ReActionButton.prototype:SetKeyBinding( k ) - if k == nil or kbValidate(k) then - local current = self:GetKeyBinding() - ClearOverrideBindings(self.button) - if current then - SetBinding(current,nil) - end - if k then - SetBindingClick(k, self.name, "LeftButton") - end - end -end - -function ReActionButton.prototype:GetKeyBinding() - return GetBindingKey("CLICK "..self.name..":LeftButton") -end - --- action ID functions -function ReActionButton.prototype:SetActionID( id ) - self.actionID = tonumber(id) -- force data integrity - self:ApplyActionID() -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) - self:UpdateTooltip() -end - -function ReActionButton.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 - - - diff -r f5607e135c37 -r dfd829db3ad0 ReAction.lua --- a/ReAction.lua Tue Mar 20 21:11:15 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,314 +0,0 @@ --- ReAction.lua --- --- Top-level file for the ReAction Action Bar add-on --- --- ReAction is implemented in terms of the Ace 2 library: http://www.wowace.com --- - --- key binding label constants -BINDING_HEADER_REACTION = "ReAction" -BINDING_NAME_REACTION_TOGGLELOCK = "Lock/Unlock ReAction Bars" -BINDING_NAME_REBINDER_TOGGLEBINDINGMODE = "Toggle ReAction keybinding mode" - --- ReAction addon setup via Ace 2 -ReAction = AceLibrary("AceAddon-2.0"):new( - "AceConsole-2.0", - "AceEvent-2.0", - "AceDB-2.0", - "FuBarPlugin-2.0" -) - -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 -end - --- FuBar plugin setup -ReAction.hasIcon = false -ReAction.hasNoColor = true -ReAction.hideMenuTitle = true -ReAction.defaultPosition = "RIGHT" -ReAction.defaultMinimapPosition = 240 -- degrees -ReAction.OnMenuRequest = tcopy(ReActionGlobalMenuOptions) - --- initial non-persistent state -ReAction.locked = true - --- localization --- local L = AceLibrary("AceLocale-2.0"):new("ReAction") - - - --- Event handling -function ReAction:OnInitialize() - self:RegisterChatCommand( {"/reaction", "/rxn"}, ReActionConsoleOptions, "REACTION" ) - - self:RegisterDB("ReActionDB","ReActionDBPC") - self:RegisterDefaults("profile", ReActionProfileDefaults) - self:RegisterEvent("PLAYER_REGEN_DISABLED","CombatLockdown") - self:RegisterEvent("PLAYER_ENTERING_WORLD","HideDefaultBars") -end - -function ReAction:OnEnable() - if self.db.profile.firstRunDone ~= true then - -- Do some "first-run" setup - self.db.profile.firstRunDone = true - elseif self.db.profile.disabled == true then - -- print some kind of a warning - end - self:SetupBars() -end - -function ReAction:OnDisable() - self:Lock() -end - -function ReAction:OnProfileEnable() - -- handle profile switching - self:Lock() - self:SetupBars() -end - -function ReAction:CombatLockdown() - if not self:IsLocked() then - self:Lock() - UIErrorsFrame:AddMessage("ReAction bars locked when in combat") - end -end - - --- lock/unlock ReAction -function ReAction:SetLocked( lock ) - if lock ~= self.locked then - if not lock then - self:Print("Buttons disabled while unlocked") - end - if not lock and InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - self.locked = lock and true or false -- force data integrity - for _, bar in pairs(self.bars) do - if self.locked then bar:HideControls() else bar:ShowControls() end - end - end - end -end - -function ReAction:IsLocked() - return self.locked -end - -function ReAction:Lock() - self:SetLocked(true) -end - -function ReAction:Unlock() - self:SetLocked(false) -end - -function ReAction:ToggleLocked() - ReAction:SetLocked( not(self.locked) ) -end - - - --- Hide the default Blizzard main bar artwork -function ReAction:HideArt() - if self.db.profile.hideArt then - MainMenuBar:Hide() -- this also hides the bags, xp bar, lag meter, and micro menu buttons. - else - MainMenuBar:Show() - end -end - -function ReAction:IsArtHidden() - return self.db.profile.hideArt -end - -function ReAction:SetHideArt( hide ) - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - self.db.profile.hideArt = hide and true or false -- force data integrity - self:HideArt() - end -end - -function ReAction:ToggleHideArt() - self:SetHideArt( not self:IsArtHidden() ) -end - - - --- Keybinding color coding -function ReAction:SetKeyColorCoding( cc ) - self.db.profile.keyColorCode = cc -end - -function ReAction:IsKeyColorCodeEnabled() - return self.db.profile.keyColorCode -end - -function ReAction:ToggleKeyColorCoding() - self:SetKeyColorCoding(not self.db.profile.keyColorCode) -end - - - --- Hide default Blizzard bars -local blizzDefaultBars = { - ActionButton1, - ActionButton2, - ActionButton3, - ActionButton4, - ActionButton5, - ActionButton6, - ActionButton7, - ActionButton8, - ActionButton9, - ActionButton10, - ActionButton11, - ActionButton12, - BonusActionBarFrame, - MultiBarLeft, - MultiBarRight, - MultiBarBottomLeft, - MultiBarBottomRight -} - -function ReAction:HideDefaultBars() - for _, f in pairs(blizzDefaultBars) do - f:UnregisterAllEvents() - f:Hide() - f:SetParent(ReActionButtonRecycler) -- I mean it! - f:ClearAllPoints() -- no, I really mean it! - end -end - - --- Reset bars to defaults -function ReAction:ResetBars() - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - self.db.profile.bars = ReActionProfileDefaults.bars - self:SetupBars() - end -end - - --- re-sync action IDs -function ReAction:ResyncActionIDs() - -- TODO -end - - - --- Bar manipulation -ReAction.bars = { } - -function ReAction:SetupBars() - -- hide the default Blizzard art, if configued - self:HideArt() - -- hide the default Blizzard bars - self:HideDefaultBars() - - -- set up the bars from the profile - -- note the use of table.maxn rather than # or ipairs: - -- our array of bars can in fact contain holes - for id = 1, table.maxn(self.db.profile.bars) do - local config = self.db.profile.bars[id] - if self.bars[id] then - self.bars[id]:Destroy() -- remove old version of bar if switching profiles - end - if config then - self.bars[id] = ReBar:new(config, id) - end - end - - -- remove excess bars - for id = table.maxn(self.db.profile.bars) + 1, table.maxn(self.bars) do - if self.bars[id] then - self.bars[id]:Destroy() - self.bars[id] = nil - end - end - - -- anchor the bars, have to do this in a second pass because - -- they might be anchored to each other in a non-ordered way - for _, bar in pairs(self.bars) do - bar:ApplyAnchor() - end -end - - -function ReAction:NewBar() - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - local c = tcopy(ReActionBarConfigDefaults) - local bar = ReBar:new(c, #self.bars+1) - table.insert(self.bars, bar) - table.insert(self.db.profile.bars, c) - if not self.locked then - bar:ShowControls() - end - end -end - - -function ReAction:DeleteBar(id) - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - if self.bars[id] then - -- we can't do tremove because each bar ID is encoded into the - -- frame names as they're created. Need a nil entry in the table. - -- The nice thing is that table.insert in NewBar() will automatically - -- find the first nil slot. - self.bars[id]:Destroy() - self.bars[id] = nil - self.db.profile.bars[id] = nil - end - end -end - -function ReAction:ToggleActionID() - if self.showActionIDs then - ReActionButton:HideAllActionIDs() - else - ReActionButton:ShowAllActionIDs() - end - self.showActionIDs = not self.showActionIDs -end - -function ReAction:IsActionIDVisible() - return self.showActionIDs -end - - - --- FuBar plugin methods -local tablet = AceLibrary("Tablet-2.0") - -function ReAction:OnTooltipUpdate() - local c = tablet:AddCategory("columns", 2) - c:AddLine("text", "Bar lock", "text2", self.locked and "|cffcc0000Locked|r" or "|cff00cc00Unlocked|r") - c:AddLine("text", "Button lock", "text2", LOCK_ACTIONBAR == "1" and "|cffcc0000Locked|r" or "|cff00cc00Unlocked|r") - c:AddLine("text", "Kebinding mode", "text2", ReBinder:IsEnabled() and "|cff33ff33On|r" or "|cffffcc00Off|r") - tablet:SetHint("|cffffcc00Shift-Click|r for bar lock|n".. - "|cff33ff33Alt-Click|r for keybindings|n".. - "Right-click for menu") -end - -function ReAction:OnClick(button) - if IsShiftKeyDown() then - self:ToggleLocked() - self:UpdateDisplay() - elseif IsAltKeyDown() then - ReBinder:ToggleEnabled() - end -end diff -r f5607e135c37 -r dfd829db3ad0 ReBar.lua --- a/ReBar.lua Tue Mar 20 21:11:15 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,527 +0,0 @@ - --- private constants -local insideFrame = 1 -local outsideFrame = 2 - -local pointFindTable = { - 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, -} - -local oppositePointTable = { - BOTTOMLEFT = "TOPRIGHT", - BOTTOM = "TOP", - BOTTOMRIGHT = "TOPLEFT", - RIGHT = "LEFT", - TOPRIGHT = "BOTTOMLEFT", - TOP = "BOTTOM", - TOPLEFT = "BOTTOMRIGHT", - LEFT = "RIGHT" -} - -local anchoredLabelColor = { r =0.6, g = 0.2, b = 1.0 } -local nonAnchoredLabelColor = { r = 1.0, g = 0.82, b = 0.0 } - --- private variables -local stickyTargets = { - [UIParent] = insideFrame, - [WorldFrame] = insideFrame -} - --- ReBar is an Ace 2 class prototype object. -ReBar = AceLibrary("AceOO-2.0").Class("AceEvent-2.0") - -local dewdrop = AceLibrary("Dewdrop-2.0") - -function ReBar.prototype:init( config, id ) - ReBar.super.prototype.init(self) - - local buttonClass = config and config.btnConfig and config.btnConfig.type and getglobal(config.btnConfig.type) - self.config = config - self.barID = id - self.class = { button = buttonClass } - self.buttons = { } - - -- create the bar and control widgets - self.barFrame = CreateFrame("Frame", "ReBar_"..self.barID, UIParent, "ReBarTemplate") - self.controlFrame = getglobal(self.barFrame:GetName().."Controls") - self.controlFrame.reBar = self - self.barFrame:SetClampedToScreen(true) - - -- set the text label on the control widget - self.labelString = getglobal(self.controlFrame:GetName().."LabelString") - self.labelString:SetText(id) - - -- initialize the bar layout - self:ApplySize() - self:ApplyAnchor() - self:LayoutButtons() - self:ApplyVisibility() - - -- add bar to stickyTargets list - stickyTargets[self.barFrame] = outsideFrame - - -- initialize dewdrop menu - dewdrop:Register(self.controlFrame, 'children', function() - dewdrop:FeedAceOptionsTable(ReActionGlobalMenuOptions) - dewdrop:FeedAceOptionsTable(GenerateReActionBarOptions(self)) - dewdrop:FeedAceOptionsTable(GenerateReActionButtonOptions(self)) - end, - 'cursorX', true, - 'cursorY', true - ) -end - - -function ReBar.prototype:Destroy() - if self.barFrame == dewdrop:GetOpenedParent() then - dewdrop:Close() - dewdrop:Unregister(self.barFrame) - end - - self:HideControls() - self.barFrame:Hide() - self.barFrame:ClearAllPoints() - self.barFrame:SetParent(nil) - self.barFrame:SetPoint("BOTTOMRIGHT", UIParent, "TOPLEFT", 0, 0) - - -- need to keep around self.config for dewdrop menus in the process of deleting self - - while #self.buttons > 0 do - self.class.button:release(table.remove(self.buttons)) - end - - -- remove from sticky targets table - stickyTargets[self.barFrame] = nil - - -- remove from global table - -- for some reason after a destroy/recreate the globals still reference - -- the old frames - setglobal(self.barFrame:GetName(), nil) - setglobal(self.barFrame:GetName().."Controls", nil) - setglobal(self.controlFrame:GetName().."LabelString", nil) -end - - --- show/hide the control frame -function ReBar.prototype:ShowControls() - self.controlFrame:Show() - for _, b in ipairs(self.buttons) do - b:BarUnlocked() - end -end - -function ReBar.prototype:HideControls() - local b = self.barFrame - if b.isMoving or b.resizing then - b:StopMovingOrSizing() - b:SetScript("OnUpdate",nil) - end - -- close any dewdrop menu owned by us - if self.barFrame == dewdrop:GetOpenedParent() then - dewdrop:Close() - end - for _, b in ipairs(self.buttons) do - b:BarLocked() - end - self.controlFrame:Hide() -end - - - - --- accessors -function ReBar.prototype:GetVisibility() - return self.config.visible -end - -function ReBar.prototype:ToggleVisibility() - self.config.visible = not self.config.visible - self:ApplyVisibility() -end - -function ReBar.prototype:GetOpacity() - return self.config.opacity or 100 -end - -function ReBar.prototype:SetOpacity( o ) - self.config.opacity = tonumber(o) - self:ApplyVisibility() - return self.config.opacity -end - - --- layout methods -function ReBar.prototype:ApplySize() - local buttonSz = self.config.size or 36 - local spacing = self.config.spacing or 4 - local rows = self.config.rows or 1 - local columns = self.config.columns or 12 - local w = buttonSz * columns + spacing * (columns + 1) - local h = buttonSz * rows + spacing * (rows + 1) - local f = self.barFrame - - -- +1: avoid resizing oddities caused by fractional UI scale setting - f:SetMinResize(buttonSz + spacing*2 + 1, buttonSz + spacing*2 + 1) - f:SetWidth(w + 1) - f:SetHeight(h + 1) -end - -function ReBar.prototype:ApplyAnchor() - local a = self.config.anchor - local f = self.barFrame - if a then - f:ClearAllPoints() - f:SetPoint(a.point,getglobal(a.to),a.relPoint,a.x,a.y) - local color = anchoredLabelColor - if a.to == "UIParent" or a.to == "WorldFrame" then - color = nonAnchoredLabelColor - end - self.labelString:SetTextColor(color.r, color.g, color.b) - end -end - -function ReBar.prototype:ApplyVisibility() - local v = self.config.visibility - if type(v) == "table" then - if v.class then - local _, c = UnitClass("player") - v = v.class[c] - end - elseif type(v) == "string" then - local value = getglobal(v) - v = value - end - - if self.config.opacity then - self.barFrame:SetAlpha(self.config.opacity / 100) - end - - if v then - self.barFrame:Show() - else - self.barFrame:Hide() - end -end - -function ReBar.prototype:LayoutButtons() - local r = self.config.rows - local c = self.config.columns - local n = r * c - local sp = self.config.spacing - local sz = self.config.size - local gSize = sp + sz - - for i = 1, n do - if self.buttons[i] == nil then - table.insert(self.buttons, self.class.button:acquire(self.barFrame, self.config.btnConfig, i)) - end - local b = self.buttons[i] - if b == nil then - break -- handling for button types that support limited numbers - end - b:PlaceButton("TOPLEFT", sp + gSize * math.fmod(i-1,c), - (sp + gSize * math.floor((i-1)/c)), sz) - end - - -- b == nil, above, should always be the case if and only if i == n. ReBar never monkeys - -- with buttons in the middle of the sequence: it always adds or removes on the array end - while #self.buttons > n do - self.class.button:release(table.remove(self.buttons)) - end - -end - - -function ReBar.prototype:StoreAnchor(f, p, rp, x, y) - local name = f:GetName() - -- no point if we can't store the name or the offsets are incomplete - if name and x and y then - self.config.anchor = { - to = name, - point = p, - relPoint = rp or p, - x = x, - y = y - } - end -end - - - --- mouse event handlers (clicking/dragging/resizing the bar) -function ReBar.prototype:BeginDrag() - local f = self.barFrame - f:StartMoving() - f.isMoving = true - f:SetScript("OnUpdate", function() self:StickyIndicatorUpdate() end) -end - -function ReBar.prototype:FinishDrag() - local f, p, rp, x, y - local bf = self.barFrame - - bf:StopMovingOrSizing() - bf.isMoving = false - - bf:SetScript("OnUpdate",nil) - if IsShiftKeyDown() then - f, p, rp, x, y = self:GetStickyAnchor() - ReBarStickyIndicator1:Hide() - ReBarStickyIndicator2:Hide() - end - - if f == nil then - f = UIParent - local _ - _, p,rp,x,y = self:GetClosestPointTo(f) - end - - if f then - self:StoreAnchor(f,p,rp,x,y) - self:ApplyAnchor() - end -end - -function ReBar.prototype:BeginBarResize( sizingPoint ) - local f = self.barFrame - f:StartSizing(sizingPoint) - f.resizing = true - f:SetScript("OnUpdate",function() self:ReflowButtons() end) -end - -function ReBar.prototype:BeginButtonResize( sizingPoint, mouseBtn ) - local f = self.barFrame - f:StartSizing(sizingPoint) - f.resizing = true - local r = self.config.rows - local c = self.config.columns - local s = self.config.spacing - local sz = self.config.size - if mouseBtn == "LeftButton" then - f:SetMinResize(c*(12 + 2*s) +1, r*(12 + 2*s) +1) - f:SetScript("OnUpdate",function() self:DragSizeButtons() end) - elseif mouseBtn == "RightButton" then - f:SetMinResize(c*sz+1, r*sz+1) - f:SetScript("OnUpdate",function() self:DragSizeSpacing() end) - end -end - -function ReBar.prototype:FinishResize() - local f = self.barFrame - f:StopMovingOrSizing() - f.resizing = false - f:SetScript("OnUpdate",nil) - self:ApplySize() -end - - - - --- sticky anchoring functions -function ReBar.prototype:StickyIndicatorUpdate() - local si1 = ReBarStickyIndicator1 - local si2 = ReBarStickyIndicator2 - if IsShiftKeyDown() then - local f, p, rp, x, y = self:GetStickyAnchor() - if f then - si1:ClearAllPoints() - si2:ClearAllPoints() - si1:SetPoint("CENTER",self.barFrame,p,0,0) - si2:SetPoint("CENTER",f,rp,x,y) - si1:Show() - si2:Show() - return nil - end - end - si1:Hide() - si2:Hide() - si1:ClearAllPoints() - si2:ClearAllPoints() -end - -function ReBar.prototype:CheckAnchorable(f) - -- can't anchor to self or to a hidden frame - if f == self.barFrame or not(f:IsShown()) then return false end - - -- also can't anchor to frames that are anchored to self - for i = 1, f:GetNumPoints() do - local _, f2 = f:GetPoint(i) - if f2 == self.barFrame then return false end - end - - return true -end - - -function ReBar.prototype:GetStickyAnchor() - local snapRange = (self.config.size + self.config.spacing) - local r2, f, p, rp, x, y = self:GetClosestAnchor() - - if f and p then - local xx, yy = pointFindTable[p](f) - if r2 and r2 < (snapRange*snapRange) then - if xx or math.abs(x) < snapRange then x = 0 end - if yy or math.abs(y) < snapRange then y = 0 end - elseif not(yy) and math.abs(x) < snapRange then - x = 0 - elseif not(xx) and math.abs(y) < snapRange then - y = 0 - else - f = nil -- nothing in range - end - end - return f, p, rp, x, y -end - -function ReBar.prototype:GetClosestAnchor() - -- choose the closest anchor point on the list of target frames - local range2, frame, point, relPoint, offsetX, offsetY - - for f, tgtRegion in pairs(stickyTargets) do - if self:CheckAnchorable(f) then - local r2 ,p, rp, x, y = self:GetClosestPointTo(f,tgtRegion) - if r2 then - if not(range2 and range2 < r2) then - range2, frame, point, relPoint, offsetX, offsetY = r2, f, p, rp, x, y - end - end - end - end - - return range2, frame, point, relPoint, offsetX, offsetY -end - -function ReBar.prototype:GetClosestPointTo(f,inside) - local range2, point, relPoint, offsetX, offsetY - local pft = pointFindTable - local cx, cy = self.barFrame:GetCenter() - local fcx, fcy = f:GetCenter() - local fh = f:GetHeight() - local fw = f:GetWidth() - - -- compute whether edge bisector intersects target edge - local dcx = math.abs(cx-fcx) < fw/2 and (cx-fcx) - local dcy = math.abs(cy-fcy) < fh/2 and (cy-fcy) - - for p, func in pairs(pft) do - local rp, x, y - if inside == outsideFrame then - rp = oppositePointTable[p] - x, y = self:GetOffsetToPoint(f, func, pft[rp]) - else - rp = p - x, y = self:GetOffsetToPoint(f, func, func) - end - - -- if anchoring to an edge, only anchor if the center point overlaps the other edge - if (x or dcx) and (y or dcy) then - local r2 = (x or 0)^2 + (y or 0)^2 - if range2 == nil or r2 < range2 then - range2, point, relPoint, offsetX, offsetY = r2, p, rp, x or dcx, y or dcy - end - end - end - return range2, point, relPoint, offsetX, offsetY -end - -function ReBar.prototype:GetOffsetToPoint(f,func,ffunc) - local x, y = func(self.barFrame) -- coordinates of the point on this frame - local fx, fy = ffunc(f) -- coordinates of the point on the target frame - -- guarantees: if x then fx, if y then fy - return x and (x-fx), y and (y-fy) -end - - - - - - --- utility function to get the height, width, and button size attributes -function ReBar.prototype:GetLayout() - local c = self.config - local f = self.barFrame - return f:GetWidth(), f:GetHeight(), c.size, c.rows, c.columns, c.spacing -end - --- add and remove buttons dynamically as the bar is resized -function ReBar.prototype:ReflowButtons() - local w, h, sz, r, c, sp = self:GetLayout() - - self.config.rows = math.floor( (h - sp) / (sz + sp) ) - self.config.columns = math.floor( (w - sp) / (sz + sp) ) - - if self.config.rows ~= r or self.config.columns ~= c then - self:LayoutButtons() - end -end - - --- change the size of buttons as the bar is resized -function ReBar.prototype:DragSizeButtons() - local w, h, sz, r, c, sp = self:GetLayout() - - local newSzW = math.floor((w - (c+1)*sp)/c) - local newSzH = math.floor((h - (r+1)*sp)/r) - - self.config.size = math.max(12, math.min(newSzW, newSzH)) - - if self.config.size ~= sz then - self:LayoutButtons() - self:UpdateResizeTooltip() - end -end - - --- change the spacing of buttons as the bar is resized -function ReBar.prototype:DragSizeSpacing() - local w, h, sz, r, c, sp = self:GetLayout() - - local newSpW = math.floor((w - c*sz)/(c+1)) - local newSpH = math.floor((h - r*sz)/(r+1)) - - self.config.spacing = math.max(0, math.min(newSpW, newSpH)) - - if self.config.spacing ~= sp then - self:LayoutButtons() - self:UpdateResizeTooltip() - end -end - - --- update the drag tooltip to indicate current sizes -function ReBar.prototype:UpdateResizeTooltip() - GameTooltipTextRight4:SetText(self.config.size) - GameTooltipTextRight5:SetText(self.config.spacing) - GameTooltip:Show() -end - -function ReBar.prototype:ShowTooltip() - GameTooltip:SetOwner(self.barFrame, "ANCHOR_TOPRIGHT") - GameTooltip:AddLine("Bar "..self.barID) - GameTooltip:AddLine("Drag to move") - GameTooltip:AddLine("Shift-drag for sticky mode") - GameTooltip:AddLine("Right-click for options") - GameTooltip:Show() -end - -function ReBar.prototype:ShowButtonResizeTooltip(point) - GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) - GameTooltip:AddLine("Drag to resize buttons") - GameTooltip:AddLine("Right-click-drag") - GameTooltip:AddLine("to change spacing") - GameTooltip:AddDoubleLine("Size: ", "0") - GameTooltip:AddDoubleLine("Spacing: ", "0") - self:UpdateResizeTooltip() -end - -function ReBar.prototype:ShowBarResizeTooltip(point) - GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) - GameTooltip:AddLine("Drag to add/remove buttons") - GameTooltip:Show() -end diff -r f5607e135c37 -r dfd829db3ad0 ReBar.xml --- a/ReBar.xml Tue Mar 20 21:11:15 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - this:RegisterForDrag("LeftButton") - - - this:GetParent().reBar:BeginBarResize(this.sizingPoint) - - - this:GetParent().reBar:FinishResize() - - - this:GetParent().reBar:ShowBarResizeTooltip(this.sizingPoint) - - - GameTooltip:Hide() - - - - - - - - - - - - - - - - - - - this:RegisterForDrag("LeftButton","RightButton") - - - this:GetParent():GetParent().reBar:BeginButtonResize(this.sizingPoint, arg1) - - - this:GetParent():GetParent().reBar:FinishResize() - - - this:GetParent():GetParent().reBar:ShowButtonResizeTooltip(this.sizingPoint) - - - GameTooltip:Hide() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r f5607e135c37 -r dfd829db3ad0 ReBinder.lua --- a/ReBinder.lua Tue Mar 20 21:11:15 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ --- ReBinder.lua --- - -ReBinder = { } - --- initial values -ReBinder.active = false - -ReBinder.targets = { } - -function ReBinder:AddKeybindTarget( t ) - if t then - self.targets[t] = CreateFrame("Button", nil, t, "ReBinderClickBindingTemplate") - self.targets[t].keybindTarget = t:GetName() - end -end - -function ReBinder:RemoveKeybindTarget( t ) - if t then - self.targets[t] = nil - end -end - -function ReBinder:ShowClickBindingButtons() - for _, clickFrame in pairs(self.targets) do - clickFrame:Show() - end -end - -function ReBinder:HideClickBindingButtons() - for _, clickFrame in pairs(self.targets) do - clickFrame:Hide() - end -end - -function ReBinder:ClearSelectedKey() - self.selectedKey = nil -end - -function ReBinder:ToggleEnabled() - if self:IsEnabled() then - self:Disable() - else - self:Enable() - end -end - -function ReBinder:IsEnabled() - return ReBinderFrame:IsVisible() -end - -function ReBinder:Enable() - ReBinderFrame:Show() -end - -function ReBinder:Disable() - ReBinderFrame:Hide() -end - - -function ReBinder:HandleKeyPressed( key ) - if key == nil or key == "UNKNOWN" or key == "SHIFT" or key == "CTRL" or key == "ALT" then - return - end - if IsShiftKeyDown() then - key = "SHIFT-"..key - end - if IsControlKeyDown() then - key = "CTRL-"..key - end - if IsAltKeyDown() then - key = "ALT-"..key - end - if key == "ESCAPE" or GetBindingAction(key) == "REBINDER_TOGGLEBINDINGMODE" then - ReBinderFrame:Hide() - return nil, nil - end - - self.selectedKey = key - - local keyTxt = GetBindingText(key, "KEY_") - local cmd = GetBindingAction(key) - local cmdTxt - - if cmd then - cmdTxt = GetBindingText(cmd, "BINDING_NAME_") - end - - -- make click-bindings look prettier - local btnName - if cmdTxt then - btnName = string.match(cmdTxt,"CLICK (.+)\:LeftButton") - btnName = btnName or string.match(cmdTxt,"CLICK (.+)\:RightButton") - end - - return keyTxt, btnName or cmdTxt -end - --- TODO: move to override-binding model and store data in profile -function ReBinder:BindSelectedKeyTo( btnName ) - if self.selectedKey and btnName then - self:ClearBinding(btnName) - SetBindingClick(self.selectedKey, btnName, "LeftButton") - SaveBindings(2) -- 2 = character-specific - ReBinderFrame.statusMsg:SetText(GetBindingText(self.selectedKey, "KEY_") .. " is now bound to " .. btnName) - ReBinderFrame.selectedKey:SetText("(none)") - ReBinderFrame.currentAction:SetText("(none)") - self.selectedKey = nil - end -end - - -function ReBinder:ClearBinding( btnName ) - if btnName then - local current = GetBindingKey("CLICK "..btnName..":LeftButton") - if current then - SetBinding(current, nil) - ReBinderFrame.statusMsg:SetText("|cFFFF3333"..btnName .. " is now unbound|r") - end - end -end - - -function ReBinder:UpdateCurrentTarget( btnName ) - local msg = "" - if btnName then - msg = btnName.." is currently " - local current = GetBindingKey("CLICK "..btnName..":LeftButton") - if current then - msg = msg .. "bound to " .. GetBindingText(current, "KEY_") - else - msg = msg .. " not bound" - end - end - ReBinderFrame.statusMsg:SetText(msg) -end diff -r f5607e135c37 -r dfd829db3ad0 ReBinder.xml --- a/ReBinder.xml Tue Mar 20 21:11:15 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,242 +0,0 @@ - - - - - - - - - - - - - - this.selectedKey = getglobal(this:GetName().."SelectedKeyText") - this.currentAction = getglobal(this:GetName().."CurrentActionText") - this:RegisterForClicks("MiddleButtonUp","Button4Up","Button5Up") - - - local k, a = ReBinder:HandleKeyPressed(arg1) - if k then - this.selectedKey:SetText(k) - this.currentAction:SetText(a or "(none)") - end - - - - - - - this.selectedKey = getglobal(this:GetName().."DialogSelectedKeyText") - this.currentAction = getglobal(this:GetName().."DialogCurrentActionText") - this.statusMsg = getglobal(this:GetName().."DialogStatusMsg") - tinsert(UISpecialFrames,this:GetName()) - this:RegisterForClicks("MiddleButtonUp","Button4Up","Button5Up") - - - this.selectedKey:SetText("(none)") - this.currentAction:SetText("(none)") - this.statusMsg:SetText("") - ReBinder:ShowClickBindingButtons() - - - ReBinder:HideClickBindingButtons() - ReBinder:ClearSelectedKey() - - - local k, a = ReBinder:HandleKeyPressed(arg1) - if k then - this.selectedKey:SetText(k) - this.currentAction:SetText(a or "(none)") - end - - - local k, a = ReBinder:HandleKeyPressed(arg1) - if k then - this.selectedKey:SetText(k) - this.currentAction:SetText(a or "(none)") - end - - - - - diff -r f5607e135c37 -r dfd829db3ad0 classes/ReAction.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/classes/ReAction.lua Tue Mar 20 21:19:34 2007 +0000 @@ -0,0 +1,773 @@ +-- 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-", + ["Spacebar"] = "Sp", + ["Num Pad "] = "Num-", + ["Page Up"] = "PgUp", + ["Page Down"] = "PgDn", + [" 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 } + +-- private variables +local kbValidate = AceLibrary("AceConsole-2.0").keybindingValidateFunc +local actionButtonTbl = { } + + + +-- ReActionButton is a class prototype object. +ReActionButton = AceLibrary("AceOO-2.0").Class("AceEvent-2.0") + +------------------- +-- Class methods +------------------- + +-- 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) + local id = nil + for i = 1, MAX_ACTIONS do + if actionButtonTbl[i] == nil or actionButtonTbl[i].inUse == false then + id = i + break + end + end + + if id == nil then return nil end -- all buttons and action ids are in use + + local hint = config.actionIDs[barIdx] + if hint and (actionButtonTbl[hint] == nil or actionButtonTbl[hint].inUse == false) then + id = hint + end + + if actionButtonTbl[id] == nil then + actionButtonTbl[id] = { } + end + local t = actionButtonTbl[id] + + t.inUse = true + if t.button then + t.button:Configure(parent,config,barIdx) + else + t.button = self:new(parent,config,barIdx,id) + end + + -- fix screwy config with overlapping IDs + config.actionIDs[barIdx] = id + return t.button +end + +function ReActionButton:release( b ) + if b then + actionButtonTbl[b:GetActionID()].inUse = false + b:Recycle() + end +end + + + +function ReActionButton:ShowAllActionIDs() + for _, b in ipairs(actionButtonTbl) do + b:ShowActionID() + end +end + +function ReActionButton:HideAllActionIDs() + for _, b in ipairs(actionButtonTbl) do + b:HideActionID() + end +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"], + } + + -- 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) +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 +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 +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 + b:ClearAllPoints() + 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 + end + end + end +end + + + + +-- keybinding functions +function ReActionButton.prototype:SetKeyBinding( k ) + if k == nil or kbValidate(k) then + local current = self:GetKeyBinding() + ClearOverrideBindings(self.button) + if current then + SetBinding(current,nil) + end + if k then + SetBindingClick(k, self.name, "LeftButton") + end + end +end + +function ReActionButton.prototype:GetKeyBinding() + return GetBindingKey("CLICK "..self.name..":LeftButton") +end + +-- action ID functions +function ReActionButton.prototype:SetActionID( id ) + self.actionID = tonumber(id) -- force data integrity + self:ApplyActionID() +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) + self:UpdateTooltip() +end + +function ReActionButton.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 + + + diff -r f5607e135c37 -r dfd829db3ad0 classes/ReBar.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/classes/ReBar.lua Tue Mar 20 21:19:34 2007 +0000 @@ -0,0 +1,527 @@ + +-- private constants +local insideFrame = 1 +local outsideFrame = 2 + +local pointFindTable = { + 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, +} + +local oppositePointTable = { + BOTTOMLEFT = "TOPRIGHT", + BOTTOM = "TOP", + BOTTOMRIGHT = "TOPLEFT", + RIGHT = "LEFT", + TOPRIGHT = "BOTTOMLEFT", + TOP = "BOTTOM", + TOPLEFT = "BOTTOMRIGHT", + LEFT = "RIGHT" +} + +local anchoredLabelColor = { r =0.6, g = 0.2, b = 1.0 } +local nonAnchoredLabelColor = { r = 1.0, g = 0.82, b = 0.0 } + +-- private variables +local stickyTargets = { + [UIParent] = insideFrame, + [WorldFrame] = insideFrame +} + +-- ReBar is an Ace 2 class prototype object. +ReBar = AceLibrary("AceOO-2.0").Class("AceEvent-2.0") + +local dewdrop = AceLibrary("Dewdrop-2.0") + +function ReBar.prototype:init( config, id ) + ReBar.super.prototype.init(self) + + local buttonClass = config and config.btnConfig and config.btnConfig.type and getglobal(config.btnConfig.type) + self.config = config + self.barID = id + self.class = { button = buttonClass } + self.buttons = { } + + -- create the bar and control widgets + self.barFrame = CreateFrame("Frame", "ReBar_"..self.barID, UIParent, "ReBarTemplate") + self.controlFrame = getglobal(self.barFrame:GetName().."Controls") + self.controlFrame.reBar = self + self.barFrame:SetClampedToScreen(true) + + -- set the text label on the control widget + self.labelString = getglobal(self.controlFrame:GetName().."LabelString") + self.labelString:SetText(id) + + -- initialize the bar layout + self:ApplySize() + self:ApplyAnchor() + self:LayoutButtons() + self:ApplyVisibility() + + -- add bar to stickyTargets list + stickyTargets[self.barFrame] = outsideFrame + + -- initialize dewdrop menu + dewdrop:Register(self.controlFrame, 'children', function() + dewdrop:FeedAceOptionsTable(ReActionGlobalMenuOptions) + dewdrop:FeedAceOptionsTable(GenerateReActionBarOptions(self)) + dewdrop:FeedAceOptionsTable(GenerateReActionButtonOptions(self)) + end, + 'cursorX', true, + 'cursorY', true + ) +end + + +function ReBar.prototype:Destroy() + if self.barFrame == dewdrop:GetOpenedParent() then + dewdrop:Close() + dewdrop:Unregister(self.barFrame) + end + + self:HideControls() + self.barFrame:Hide() + self.barFrame:ClearAllPoints() + self.barFrame:SetParent(nil) + self.barFrame:SetPoint("BOTTOMRIGHT", UIParent, "TOPLEFT", 0, 0) + + -- need to keep around self.config for dewdrop menus in the process of deleting self + + while #self.buttons > 0 do + self.class.button:release(table.remove(self.buttons)) + end + + -- remove from sticky targets table + stickyTargets[self.barFrame] = nil + + -- remove from global table + -- for some reason after a destroy/recreate the globals still reference + -- the old frames + setglobal(self.barFrame:GetName(), nil) + setglobal(self.barFrame:GetName().."Controls", nil) + setglobal(self.controlFrame:GetName().."LabelString", nil) +end + + +-- show/hide the control frame +function ReBar.prototype:ShowControls() + self.controlFrame:Show() + for _, b in ipairs(self.buttons) do + b:BarUnlocked() + end +end + +function ReBar.prototype:HideControls() + local b = self.barFrame + if b.isMoving or b.resizing then + b:StopMovingOrSizing() + b:SetScript("OnUpdate",nil) + end + -- close any dewdrop menu owned by us + if self.barFrame == dewdrop:GetOpenedParent() then + dewdrop:Close() + end + for _, b in ipairs(self.buttons) do + b:BarLocked() + end + self.controlFrame:Hide() +end + + + + +-- accessors +function ReBar.prototype:GetVisibility() + return self.config.visible +end + +function ReBar.prototype:ToggleVisibility() + self.config.visible = not self.config.visible + self:ApplyVisibility() +end + +function ReBar.prototype:GetOpacity() + return self.config.opacity or 100 +end + +function ReBar.prototype:SetOpacity( o ) + self.config.opacity = tonumber(o) + self:ApplyVisibility() + return self.config.opacity +end + + +-- layout methods +function ReBar.prototype:ApplySize() + local buttonSz = self.config.size or 36 + local spacing = self.config.spacing or 4 + local rows = self.config.rows or 1 + local columns = self.config.columns or 12 + local w = buttonSz * columns + spacing * (columns + 1) + local h = buttonSz * rows + spacing * (rows + 1) + local f = self.barFrame + + -- +1: avoid resizing oddities caused by fractional UI scale setting + f:SetMinResize(buttonSz + spacing*2 + 1, buttonSz + spacing*2 + 1) + f:SetWidth(w + 1) + f:SetHeight(h + 1) +end + +function ReBar.prototype:ApplyAnchor() + local a = self.config.anchor + local f = self.barFrame + if a then + f:ClearAllPoints() + f:SetPoint(a.point,getglobal(a.to),a.relPoint,a.x,a.y) + local color = anchoredLabelColor + if a.to == "UIParent" or a.to == "WorldFrame" then + color = nonAnchoredLabelColor + end + self.labelString:SetTextColor(color.r, color.g, color.b) + end +end + +function ReBar.prototype:ApplyVisibility() + local v = self.config.visibility + if type(v) == "table" then + if v.class then + local _, c = UnitClass("player") + v = v.class[c] + end + elseif type(v) == "string" then + local value = getglobal(v) + v = value + end + + if self.config.opacity then + self.barFrame:SetAlpha(self.config.opacity / 100) + end + + if v then + self.barFrame:Show() + else + self.barFrame:Hide() + end +end + +function ReBar.prototype:LayoutButtons() + local r = self.config.rows + local c = self.config.columns + local n = r * c + local sp = self.config.spacing + local sz = self.config.size + local gSize = sp + sz + + for i = 1, n do + if self.buttons[i] == nil then + table.insert(self.buttons, self.class.button:acquire(self.barFrame, self.config.btnConfig, i)) + end + local b = self.buttons[i] + if b == nil then + break -- handling for button types that support limited numbers + end + b:PlaceButton("TOPLEFT", sp + gSize * math.fmod(i-1,c), - (sp + gSize * math.floor((i-1)/c)), sz) + end + + -- b == nil, above, should always be the case if and only if i == n. ReBar never monkeys + -- with buttons in the middle of the sequence: it always adds or removes on the array end + while #self.buttons > n do + self.class.button:release(table.remove(self.buttons)) + end + +end + + +function ReBar.prototype:StoreAnchor(f, p, rp, x, y) + local name = f:GetName() + -- no point if we can't store the name or the offsets are incomplete + if name and x and y then + self.config.anchor = { + to = name, + point = p, + relPoint = rp or p, + x = x, + y = y + } + end +end + + + +-- mouse event handlers (clicking/dragging/resizing the bar) +function ReBar.prototype:BeginDrag() + local f = self.barFrame + f:StartMoving() + f.isMoving = true + f:SetScript("OnUpdate", function() self:StickyIndicatorUpdate() end) +end + +function ReBar.prototype:FinishDrag() + local f, p, rp, x, y + local bf = self.barFrame + + bf:StopMovingOrSizing() + bf.isMoving = false + + bf:SetScript("OnUpdate",nil) + if IsShiftKeyDown() then + f, p, rp, x, y = self:GetStickyAnchor() + ReBarStickyIndicator1:Hide() + ReBarStickyIndicator2:Hide() + end + + if f == nil then + f = UIParent + local _ + _, p,rp,x,y = self:GetClosestPointTo(f) + end + + if f then + self:StoreAnchor(f,p,rp,x,y) + self:ApplyAnchor() + end +end + +function ReBar.prototype:BeginBarResize( sizingPoint ) + local f = self.barFrame + f:StartSizing(sizingPoint) + f.resizing = true + f:SetScript("OnUpdate",function() self:ReflowButtons() end) +end + +function ReBar.prototype:BeginButtonResize( sizingPoint, mouseBtn ) + local f = self.barFrame + f:StartSizing(sizingPoint) + f.resizing = true + local r = self.config.rows + local c = self.config.columns + local s = self.config.spacing + local sz = self.config.size + if mouseBtn == "LeftButton" then + f:SetMinResize(c*(12 + 2*s) +1, r*(12 + 2*s) +1) + f:SetScript("OnUpdate",function() self:DragSizeButtons() end) + elseif mouseBtn == "RightButton" then + f:SetMinResize(c*sz+1, r*sz+1) + f:SetScript("OnUpdate",function() self:DragSizeSpacing() end) + end +end + +function ReBar.prototype:FinishResize() + local f = self.barFrame + f:StopMovingOrSizing() + f.resizing = false + f:SetScript("OnUpdate",nil) + self:ApplySize() +end + + + + +-- sticky anchoring functions +function ReBar.prototype:StickyIndicatorUpdate() + local si1 = ReBarStickyIndicator1 + local si2 = ReBarStickyIndicator2 + if IsShiftKeyDown() then + local f, p, rp, x, y = self:GetStickyAnchor() + if f then + si1:ClearAllPoints() + si2:ClearAllPoints() + si1:SetPoint("CENTER",self.barFrame,p,0,0) + si2:SetPoint("CENTER",f,rp,x,y) + si1:Show() + si2:Show() + return nil + end + end + si1:Hide() + si2:Hide() + si1:ClearAllPoints() + si2:ClearAllPoints() +end + +function ReBar.prototype:CheckAnchorable(f) + -- can't anchor to self or to a hidden frame + if f == self.barFrame or not(f:IsShown()) then return false end + + -- also can't anchor to frames that are anchored to self + for i = 1, f:GetNumPoints() do + local _, f2 = f:GetPoint(i) + if f2 == self.barFrame then return false end + end + + return true +end + + +function ReBar.prototype:GetStickyAnchor() + local snapRange = (self.config.size + self.config.spacing) + local r2, f, p, rp, x, y = self:GetClosestAnchor() + + if f and p then + local xx, yy = pointFindTable[p](f) + if r2 and r2 < (snapRange*snapRange) then + if xx or math.abs(x) < snapRange then x = 0 end + if yy or math.abs(y) < snapRange then y = 0 end + elseif not(yy) and math.abs(x) < snapRange then + x = 0 + elseif not(xx) and math.abs(y) < snapRange then + y = 0 + else + f = nil -- nothing in range + end + end + return f, p, rp, x, y +end + +function ReBar.prototype:GetClosestAnchor() + -- choose the closest anchor point on the list of target frames + local range2, frame, point, relPoint, offsetX, offsetY + + for f, tgtRegion in pairs(stickyTargets) do + if self:CheckAnchorable(f) then + local r2 ,p, rp, x, y = self:GetClosestPointTo(f,tgtRegion) + if r2 then + if not(range2 and range2 < r2) then + range2, frame, point, relPoint, offsetX, offsetY = r2, f, p, rp, x, y + end + end + end + end + + return range2, frame, point, relPoint, offsetX, offsetY +end + +function ReBar.prototype:GetClosestPointTo(f,inside) + local range2, point, relPoint, offsetX, offsetY + local pft = pointFindTable + local cx, cy = self.barFrame:GetCenter() + local fcx, fcy = f:GetCenter() + local fh = f:GetHeight() + local fw = f:GetWidth() + + -- compute whether edge bisector intersects target edge + local dcx = math.abs(cx-fcx) < fw/2 and (cx-fcx) + local dcy = math.abs(cy-fcy) < fh/2 and (cy-fcy) + + for p, func in pairs(pft) do + local rp, x, y + if inside == outsideFrame then + rp = oppositePointTable[p] + x, y = self:GetOffsetToPoint(f, func, pft[rp]) + else + rp = p + x, y = self:GetOffsetToPoint(f, func, func) + end + + -- if anchoring to an edge, only anchor if the center point overlaps the other edge + if (x or dcx) and (y or dcy) then + local r2 = (x or 0)^2 + (y or 0)^2 + if range2 == nil or r2 < range2 then + range2, point, relPoint, offsetX, offsetY = r2, p, rp, x or dcx, y or dcy + end + end + end + return range2, point, relPoint, offsetX, offsetY +end + +function ReBar.prototype:GetOffsetToPoint(f,func,ffunc) + local x, y = func(self.barFrame) -- coordinates of the point on this frame + local fx, fy = ffunc(f) -- coordinates of the point on the target frame + -- guarantees: if x then fx, if y then fy + return x and (x-fx), y and (y-fy) +end + + + + + + +-- utility function to get the height, width, and button size attributes +function ReBar.prototype:GetLayout() + local c = self.config + local f = self.barFrame + return f:GetWidth(), f:GetHeight(), c.size, c.rows, c.columns, c.spacing +end + +-- add and remove buttons dynamically as the bar is resized +function ReBar.prototype:ReflowButtons() + local w, h, sz, r, c, sp = self:GetLayout() + + self.config.rows = math.floor( (h - sp) / (sz + sp) ) + self.config.columns = math.floor( (w - sp) / (sz + sp) ) + + if self.config.rows ~= r or self.config.columns ~= c then + self:LayoutButtons() + end +end + + +-- change the size of buttons as the bar is resized +function ReBar.prototype:DragSizeButtons() + local w, h, sz, r, c, sp = self:GetLayout() + + local newSzW = math.floor((w - (c+1)*sp)/c) + local newSzH = math.floor((h - (r+1)*sp)/r) + + self.config.size = math.max(12, math.min(newSzW, newSzH)) + + if self.config.size ~= sz then + self:LayoutButtons() + self:UpdateResizeTooltip() + end +end + + +-- change the spacing of buttons as the bar is resized +function ReBar.prototype:DragSizeSpacing() + local w, h, sz, r, c, sp = self:GetLayout() + + local newSpW = math.floor((w - c*sz)/(c+1)) + local newSpH = math.floor((h - r*sz)/(r+1)) + + self.config.spacing = math.max(0, math.min(newSpW, newSpH)) + + if self.config.spacing ~= sp then + self:LayoutButtons() + self:UpdateResizeTooltip() + end +end + + +-- update the drag tooltip to indicate current sizes +function ReBar.prototype:UpdateResizeTooltip() + GameTooltipTextRight4:SetText(self.config.size) + GameTooltipTextRight5:SetText(self.config.spacing) + GameTooltip:Show() +end + +function ReBar.prototype:ShowTooltip() + GameTooltip:SetOwner(self.barFrame, "ANCHOR_TOPRIGHT") + GameTooltip:AddLine("Bar "..self.barID) + GameTooltip:AddLine("Drag to move") + GameTooltip:AddLine("Shift-drag for sticky mode") + GameTooltip:AddLine("Right-click for options") + GameTooltip:Show() +end + +function ReBar.prototype:ShowButtonResizeTooltip(point) + GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) + GameTooltip:AddLine("Drag to resize buttons") + GameTooltip:AddLine("Right-click-drag") + GameTooltip:AddLine("to change spacing") + GameTooltip:AddDoubleLine("Size: ", "0") + GameTooltip:AddDoubleLine("Spacing: ", "0") + self:UpdateResizeTooltip() +end + +function ReBar.prototype:ShowBarResizeTooltip(point) + GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) + GameTooltip:AddLine("Drag to add/remove buttons") + GameTooltip:Show() +end diff -r f5607e135c37 -r dfd829db3ad0 classes/ReBar.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/classes/ReBar.xml Tue Mar 20 21:19:34 2007 +0000 @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + this:RegisterForDrag("LeftButton") + + + this:GetParent().reBar:BeginBarResize(this.sizingPoint) + + + this:GetParent().reBar:FinishResize() + + + this:GetParent().reBar:ShowBarResizeTooltip(this.sizingPoint) + + + GameTooltip:Hide() + + + + + + + + + + + + + + + + + + + this:RegisterForDrag("LeftButton","RightButton") + + + this:GetParent():GetParent().reBar:BeginButtonResize(this.sizingPoint, arg1) + + + this:GetParent():GetParent().reBar:FinishResize() + + + this:GetParent():GetParent().reBar:ShowButtonResizeTooltip(this.sizingPoint) + + + GameTooltip:Hide() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r f5607e135c37 -r dfd829db3ad0 classes/ReBinder.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/classes/ReBinder.lua Tue Mar 20 21:19:34 2007 +0000 @@ -0,0 +1,136 @@ +-- ReBinder.lua +-- + +ReBinder = { } + +-- initial values +ReBinder.active = false + +ReBinder.targets = { } + +function ReBinder:AddKeybindTarget( t ) + if t then + self.targets[t] = CreateFrame("Button", nil, t, "ReBinderClickBindingTemplate") + self.targets[t].keybindTarget = t:GetName() + end +end + +function ReBinder:RemoveKeybindTarget( t ) + if t then + self.targets[t] = nil + end +end + +function ReBinder:ShowClickBindingButtons() + for _, clickFrame in pairs(self.targets) do + clickFrame:Show() + end +end + +function ReBinder:HideClickBindingButtons() + for _, clickFrame in pairs(self.targets) do + clickFrame:Hide() + end +end + +function ReBinder:ClearSelectedKey() + self.selectedKey = nil +end + +function ReBinder:ToggleEnabled() + if self:IsEnabled() then + self:Disable() + else + self:Enable() + end +end + +function ReBinder:IsEnabled() + return ReBinderFrame:IsVisible() +end + +function ReBinder:Enable() + ReBinderFrame:Show() +end + +function ReBinder:Disable() + ReBinderFrame:Hide() +end + + +function ReBinder:HandleKeyPressed( key ) + if key == nil or key == "UNKNOWN" or key == "SHIFT" or key == "CTRL" or key == "ALT" then + return + end + if IsShiftKeyDown() then + key = "SHIFT-"..key + end + if IsControlKeyDown() then + key = "CTRL-"..key + end + if IsAltKeyDown() then + key = "ALT-"..key + end + if key == "ESCAPE" or GetBindingAction(key) == "REBINDER_TOGGLEBINDINGMODE" then + ReBinderFrame:Hide() + return nil, nil + end + + self.selectedKey = key + + local keyTxt = GetBindingText(key, "KEY_") + local cmd = GetBindingAction(key) + local cmdTxt + + if cmd then + cmdTxt = GetBindingText(cmd, "BINDING_NAME_") + end + + -- make click-bindings look prettier + local btnName + if cmdTxt then + btnName = string.match(cmdTxt,"CLICK (.+)\:LeftButton") + btnName = btnName or string.match(cmdTxt,"CLICK (.+)\:RightButton") + end + + return keyTxt, btnName or cmdTxt +end + +-- TODO: move to override-binding model and store data in profile +function ReBinder:BindSelectedKeyTo( btnName ) + if self.selectedKey and btnName then + self:ClearBinding(btnName) + SetBindingClick(self.selectedKey, btnName, "LeftButton") + SaveBindings(2) -- 2 = character-specific + ReBinderFrame.statusMsg:SetText(GetBindingText(self.selectedKey, "KEY_") .. " is now bound to " .. btnName) + ReBinderFrame.selectedKey:SetText("(none)") + ReBinderFrame.currentAction:SetText("(none)") + self.selectedKey = nil + end +end + + +function ReBinder:ClearBinding( btnName ) + if btnName then + local current = GetBindingKey("CLICK "..btnName..":LeftButton") + if current then + SetBinding(current, nil) + ReBinderFrame.statusMsg:SetText("|cFFFF3333"..btnName .. " is now unbound|r") + end + end +end + + +function ReBinder:UpdateCurrentTarget( btnName ) + local msg = "" + if btnName then + msg = btnName.." is currently " + local current = GetBindingKey("CLICK "..btnName..":LeftButton") + if current then + msg = msg .. "bound to " .. GetBindingText(current, "KEY_") + else + msg = msg .. " not bound" + end + end + ReBinderFrame.statusMsg:SetText(msg) +end diff -r f5607e135c37 -r dfd829db3ad0 classes/ReBinder.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/classes/ReBinder.xml Tue Mar 20 21:19:34 2007 +0000 @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + this.selectedKey = getglobal(this:GetName().."SelectedKeyText") + this.currentAction = getglobal(this:GetName().."CurrentActionText") + this:RegisterForClicks("MiddleButtonUp","Button4Up","Button5Up") + + + local k, a = ReBinder:HandleKeyPressed(arg1) + if k then + this.selectedKey:SetText(k) + this.currentAction:SetText(a or "(none)") + end + + + + + + + this.selectedKey = getglobal(this:GetName().."DialogSelectedKeyText") + this.currentAction = getglobal(this:GetName().."DialogCurrentActionText") + this.statusMsg = getglobal(this:GetName().."DialogStatusMsg") + tinsert(UISpecialFrames,this:GetName()) + this:RegisterForClicks("MiddleButtonUp","Button4Up","Button5Up") + + + this.selectedKey:SetText("(none)") + this.currentAction:SetText("(none)") + this.statusMsg:SetText("") + ReBinder:ShowClickBindingButtons() + + + ReBinder:HideClickBindingButtons() + ReBinder:ClearSelectedKey() + + + local k, a = ReBinder:HandleKeyPressed(arg1) + if k then + this.selectedKey:SetText(k) + this.currentAction:SetText(a or "(none)") + end + + + local k, a = ReBinder:HandleKeyPressed(arg1) + if k then + this.selectedKey:SetText(k) + this.currentAction:SetText(a or "(none)") + end + + + + + diff -r f5607e135c37 -r dfd829db3ad0 main.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.lua Tue Mar 20 21:19:34 2007 +0000 @@ -0,0 +1,314 @@ +-- ReAction.lua +-- +-- Top-level file for the ReAction Action Bar add-on +-- +-- ReAction is implemented in terms of the Ace 2 library: http://www.wowace.com +-- + +-- key binding label constants +BINDING_HEADER_REACTION = "ReAction" +BINDING_NAME_REACTION_TOGGLELOCK = "Lock/Unlock ReAction Bars" +BINDING_NAME_REBINDER_TOGGLEBINDINGMODE = "Toggle ReAction keybinding mode" + +-- ReAction addon setup via Ace 2 +ReAction = AceLibrary("AceAddon-2.0"):new( + "AceConsole-2.0", + "AceEvent-2.0", + "AceDB-2.0", + "FuBarPlugin-2.0" +) + +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 +end + +-- FuBar plugin setup +ReAction.hasIcon = false +ReAction.hasNoColor = true +ReAction.hideMenuTitle = true +ReAction.defaultPosition = "RIGHT" +ReAction.defaultMinimapPosition = 240 -- degrees +ReAction.OnMenuRequest = tcopy(ReActionGlobalMenuOptions) + +-- initial non-persistent state +ReAction.locked = true + +-- localization +-- local L = AceLibrary("AceLocale-2.0"):new("ReAction") + + + +-- Event handling +function ReAction:OnInitialize() + self:RegisterChatCommand( {"/reaction", "/rxn"}, ReActionConsoleOptions, "REACTION" ) + + self:RegisterDB("ReActionDB","ReActionDBPC") + self:RegisterDefaults("profile", ReActionProfileDefaults) + self:RegisterEvent("PLAYER_REGEN_DISABLED","CombatLockdown") + self:RegisterEvent("PLAYER_ENTERING_WORLD","HideDefaultBars") +end + +function ReAction:OnEnable() + if self.db.profile.firstRunDone ~= true then + -- Do some "first-run" setup + self.db.profile.firstRunDone = true + elseif self.db.profile.disabled == true then + -- print some kind of a warning + end + self:SetupBars() +end + +function ReAction:OnDisable() + self:Lock() +end + +function ReAction:OnProfileEnable() + -- handle profile switching + self:Lock() + self:SetupBars() +end + +function ReAction:CombatLockdown() + if not self:IsLocked() then + self:Lock() + UIErrorsFrame:AddMessage("ReAction bars locked when in combat") + end +end + + +-- lock/unlock ReAction +function ReAction:SetLocked( lock ) + if lock ~= self.locked then + if not lock then + self:Print("Buttons disabled while unlocked") + end + if not lock and InCombatLockdown() then + UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) + else + self.locked = lock and true or false -- force data integrity + for _, bar in pairs(self.bars) do + if self.locked then bar:HideControls() else bar:ShowControls() end + end + end + end +end + +function ReAction:IsLocked() + return self.locked +end + +function ReAction:Lock() + self:SetLocked(true) +end + +function ReAction:Unlock() + self:SetLocked(false) +end + +function ReAction:ToggleLocked() + ReAction:SetLocked( not(self.locked) ) +end + + + +-- Hide the default Blizzard main bar artwork +function ReAction:HideArt() + if self.db.profile.hideArt then + MainMenuBar:Hide() -- this also hides the bags, xp bar, lag meter, and micro menu buttons. + else + MainMenuBar:Show() + end +end + +function ReAction:IsArtHidden() + return self.db.profile.hideArt +end + +function ReAction:SetHideArt( hide ) + if InCombatLockdown() then + UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) + else + self.db.profile.hideArt = hide and true or false -- force data integrity + self:HideArt() + end +end + +function ReAction:ToggleHideArt() + self:SetHideArt( not self:IsArtHidden() ) +end + + + +-- Keybinding color coding +function ReAction:SetKeyColorCoding( cc ) + self.db.profile.keyColorCode = cc +end + +function ReAction:IsKeyColorCodeEnabled() + return self.db.profile.keyColorCode +end + +function ReAction:ToggleKeyColorCoding() + self:SetKeyColorCoding(not self.db.profile.keyColorCode) +end + + + +-- Hide default Blizzard bars +local blizzDefaultBars = { + ActionButton1, + ActionButton2, + ActionButton3, + ActionButton4, + ActionButton5, + ActionButton6, + ActionButton7, + ActionButton8, + ActionButton9, + ActionButton10, + ActionButton11, + ActionButton12, + BonusActionBarFrame, + MultiBarLeft, + MultiBarRight, + MultiBarBottomLeft, + MultiBarBottomRight +} + +function ReAction:HideDefaultBars() + for _, f in pairs(blizzDefaultBars) do + f:UnregisterAllEvents() + f:Hide() + f:SetParent(ReActionButtonRecycler) -- I mean it! + f:ClearAllPoints() -- no, I really mean it! + end +end + + +-- Reset bars to defaults +function ReAction:ResetBars() + if InCombatLockdown() then + UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) + else + self.db.profile.bars = ReActionProfileDefaults.bars + self:SetupBars() + end +end + + +-- re-sync action IDs +function ReAction:ResyncActionIDs() + -- TODO +end + + + +-- Bar manipulation +ReAction.bars = { } + +function ReAction:SetupBars() + -- hide the default Blizzard art, if configued + self:HideArt() + -- hide the default Blizzard bars + self:HideDefaultBars() + + -- set up the bars from the profile + -- note the use of table.maxn rather than # or ipairs: + -- our array of bars can in fact contain holes + for id = 1, table.maxn(self.db.profile.bars) do + local config = self.db.profile.bars[id] + if self.bars[id] then + self.bars[id]:Destroy() -- remove old version of bar if switching profiles + end + if config then + self.bars[id] = ReBar:new(config, id) + end + end + + -- remove excess bars + for id = table.maxn(self.db.profile.bars) + 1, table.maxn(self.bars) do + if self.bars[id] then + self.bars[id]:Destroy() + self.bars[id] = nil + end + end + + -- anchor the bars, have to do this in a second pass because + -- they might be anchored to each other in a non-ordered way + for _, bar in pairs(self.bars) do + bar:ApplyAnchor() + end +end + + +function ReAction:NewBar() + if InCombatLockdown() then + UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) + else + local c = tcopy(ReActionBarConfigDefaults) + local bar = ReBar:new(c, #self.bars+1) + table.insert(self.bars, bar) + table.insert(self.db.profile.bars, c) + if not self.locked then + bar:ShowControls() + end + end +end + + +function ReAction:DeleteBar(id) + if InCombatLockdown() then + UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) + else + if self.bars[id] then + -- we can't do tremove because each bar ID is encoded into the + -- frame names as they're created. Need a nil entry in the table. + -- The nice thing is that table.insert in NewBar() will automatically + -- find the first nil slot. + self.bars[id]:Destroy() + self.bars[id] = nil + self.db.profile.bars[id] = nil + end + end +end + +function ReAction:ToggleActionID() + if self.showActionIDs then + ReActionButton:HideAllActionIDs() + else + ReActionButton:ShowAllActionIDs() + end + self.showActionIDs = not self.showActionIDs +end + +function ReAction:IsActionIDVisible() + return self.showActionIDs +end + + + +-- FuBar plugin methods +local tablet = AceLibrary("Tablet-2.0") + +function ReAction:OnTooltipUpdate() + local c = tablet:AddCategory("columns", 2) + c:AddLine("text", "Bar lock", "text2", self.locked and "|cffcc0000Locked|r" or "|cff00cc00Unlocked|r") + c:AddLine("text", "Button lock", "text2", LOCK_ACTIONBAR == "1" and "|cffcc0000Locked|r" or "|cff00cc00Unlocked|r") + c:AddLine("text", "Kebinding mode", "text2", ReBinder:IsEnabled() and "|cff33ff33On|r" or "|cffffcc00Off|r") + tablet:SetHint("|cffffcc00Shift-Click|r for bar lock|n".. + "|cff33ff33Alt-Click|r for keybindings|n".. + "Right-click for menu") +end + +function ReAction:OnClick(button) + if IsShiftKeyDown() then + self:ToggleLocked() + self:UpdateDisplay() + elseif IsAltKeyDown() then + ReBinder:ToggleEnabled() + end +end