ActionButton.lua

ActionButton.lua (8.3.0.34963; unchanged since 8.2.5.31960)
  1. CURRENT_ACTIONBAR_PAGE = 1;
  2. NUM_ACTIONBAR_PAGES = 6;
  3. NUM_ACTIONBAR_BUTTONS = 12;
  4. NUM_OVERRIDE_BUTTONS = 6;
  5. ATTACK_BUTTON_FLASH_TIME = 0.4;
  6. BOTTOMLEFT_ACTIONBAR_PAGE = 6;
  7. BOTTOMRIGHT_ACTIONBAR_PAGE = 5;
  8. LEFT_ACTIONBAR_PAGE = 4;
  9. RIGHT_ACTIONBAR_PAGE = 3;
  10. RANGE_INDICATOR = "‚óŹ";
  11. COOLDOWN_TYPE_LOSS_OF_CONTROL = 1;
  12. COOLDOWN_TYPE_NORMAL = 2;
  13. -- Table of actionbar pages and whether they're viewable or not
  14. VIEWABLE_ACTION_BAR_PAGES = {1, 1, 1, 1, 1, 1};
  15. ACTION_HIGHLIGHT_MARKS = { };
  16. ON_BAR_HIGHLIGHT_MARKS = { };
  17. ACTION_BUTTON_SHOW_GRID_REASON_CVAR = 1;
  18. ACTION_BUTTON_SHOW_GRID_REASON_EVENT = 2;
  19. ACTION_BUTTON_SHOW_GRID_REASON_SPELLBOOK = 4;
  20. function MarkNewActionHighlight(action)
  21. ACTION_HIGHLIGHT_MARKS[action] = true;
  22. end
  23. function ClearNewActionHighlight(action, preventIdenticalActionsFromClearing)
  24. ACTION_HIGHLIGHT_MARKS[action] = nil;
  25. if preventIdenticalActionsFromClearing then
  26. return;
  27. end
  28. -- If we're unhighlighting this one because it was used/moused over/etc...
  29. -- then go find all other current actions that match this one that are also
  30. -- marked for highlight and unmark them. The next time they update the highlight
  31. -- will update; may need to actually force update the action button in some cases
  32. -- and that means that ACTION_HIGHLIGHT_MARKS needs to store more information
  33. local unmarkedType, unmarkedID = GetActionInfo(action);
  34. for actionKey, markValue in pairs(ACTION_HIGHLIGHT_MARKS) do
  35. if markValue then
  36. local actionType, actionID = GetActionInfo(actionKey);
  37. if actionType == unmarkedType and actionID == unmarkedID then
  38. ACTION_HIGHLIGHT_MARKS[actionKey] = nil;
  39. end
  40. end
  41. end
  42. end
  43. function GetNewActionHighlightMark(action)
  44. return ACTION_HIGHLIGHT_MARKS[action];
  45. end
  46. function ClearOnBarHighlightMarks()
  47. ON_BAR_HIGHLIGHT_MARKS = {};
  48. end
  49. function GetOnBarHighlightMark(action)
  50. return ON_BAR_HIGHLIGHT_MARKS[action];
  51. end
  52. local function UpdateOnBarHighlightMarks(actionButtonSlots)
  53. if actionButtonSlots then
  54. ON_BAR_HIGHLIGHT_MARKS = tInvert(actionButtonSlots);
  55. else
  56. ClearOnBarHighlightMarks();
  57. end
  58. end
  59. function UpdateOnBarHighlightMarksBySpell(spellID)
  60. UpdateOnBarHighlightMarks(C_ActionBar.FindSpellActionButtons(spellID));
  61. end
  62. function UpdateOnBarHighlightMarksByFlyout(flyoutID)
  63. UpdateOnBarHighlightMarks(C_ActionBar.FindFlyoutActionButtons(flyoutID));
  64. end
  65. function UpdateOnBarHighlightMarksByPetAction(petAction)
  66. UpdateOnBarHighlightMarks(C_ActionBar.FindPetActionButtons(petAction));
  67. end
  68. function GetActionButtonForID(id)
  69. if OverrideActionBar and OverrideActionBar:IsShown() then
  70. if id > NUM_OVERRIDE_BUTTONS then
  71. return;
  72. end
  73. return _G["OverrideActionBarButton"..id];
  74. end
  75. return _G["ActionButton"..id];
  76. end
  77. local function CheckUseActionButton(button, checkingFromDown)
  78. local actionButtonUseKeyDown = GetCVarBool("ActionButtonUseKeyDown");
  79. local doAction = (checkingFromDown and actionButtonUseKeyDown) or not (checkingFromDown or actionButtonUseKeyDown);
  80. if doAction then
  81. if not button.ZoneAbilityDisabled then
  82. SecureActionButton_OnClick(button, "LeftButton");
  83. if GetNewActionHighlightMark(button.action) then
  84. ClearNewActionHighlight(button.action);
  85. ActionButton_UpdateHighlightMark(button);
  86. end
  87. end
  88. ActionButton_UpdateState(button);
  89. end
  90. end
  91. local isInPetBattle = C_PetBattles.IsInBattle;
  92. local function CheckPetActionButtonEvent(id, isDown)
  93. if isInPetBattle() and PetBattleFrame then
  94. if isDown then
  95. PetBattleFrame_ButtonDown(id);
  96. else
  97. PetBattleFrame_ButtonUp(id);
  98. end
  99. return true;
  100. end
  101. return false;
  102. end
  103. function ActionButtonDown(id)
  104. if CheckPetActionButtonEvent(id, true) then
  105. return;
  106. end
  107. local button = GetActionButtonForID(id);
  108. if button then
  109. if button:GetButtonState() == "NORMAL" then
  110. button:SetButtonState("PUSHED");
  111. end
  112. CheckUseActionButton(button, true);
  113. end
  114. end
  115. function ActionButtonUp(id)
  116. if CheckPetActionButtonEvent(id, false) then
  117. return;
  118. end
  119. local button = GetActionButtonForID(id);
  120. if button then
  121. if ( button:GetButtonState() == "PUSHED" ) then
  122. button:SetButtonState("NORMAL");
  123. CheckUseActionButton(button, false);
  124. end
  125. end
  126. end
  127. function ActionBar_PageUp()
  128. local nextPage;
  129. for i=GetActionBarPage() + 1, NUM_ACTIONBAR_PAGES do
  130. if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
  131. nextPage = i;
  132. break;
  133. end
  134. end
  135. if ( not nextPage ) then
  136. nextPage = 1;
  137. end
  138. ChangeActionBarPage(nextPage);
  139. end
  140. function ActionBar_PageDown()
  141. local prevPage;
  142. for i=GetActionBarPage() - 1, 1, -1 do
  143. if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
  144. prevPage = i;
  145. break;
  146. end
  147. end
  148. if ( not prevPage ) then
  149. for i=NUM_ACTIONBAR_PAGES, 1, -1 do
  150. if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
  151. prevPage = i;
  152. break;
  153. end
  154. end
  155. end
  156. ChangeActionBarPage(prevPage);
  157. end
  158. function ActionBarButtonEventsFrame_OnLoad(self)
  159. self.frames = { };
  160. self:RegisterEvent("PLAYER_ENTERING_WORLD");
  161. self:RegisterEvent("ACTIONBAR_SHOWGRID");
  162. self:RegisterEvent("ACTIONBAR_HIDEGRID");
  163. self:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
  164. self:RegisterEvent("UPDATE_BINDINGS");
  165. self:RegisterEvent("UPDATE_SHAPESHIFT_FORM");
  166. self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
  167. self:RegisterEvent("PET_BAR_UPDATE");
  168. self:RegisterUnitEvent("UNIT_FLAGS", "pet");
  169. self:RegisterUnitEvent("UNIT_AURA", "pet");
  170. self:RegisterEvent("PLAYER_MOUNT_DISPLAY_CHANGED");
  171. end
  172. function ActionBarButtonEventsFrame_OnEvent(self, event, ...)
  173. -- pass event down to the buttons
  174. for k, frame in pairs(self.frames) do
  175. ActionButton_OnEvent(frame, event, ...);
  176. end
  177. end
  178. function ActionBarButtonEventsFrame_RegisterFrame(frame)
  179. tinsert(ActionBarButtonEventsFrame.frames, frame);
  180. end
  181. function ActionBarActionEventsFrame_OnLoad(self)
  182. self.frames = { };
  183. --self:RegisterEvent("ACTIONBAR_UPDATE_STATE"); not updating state from lua anymore, see SetActionUIButton
  184. self:RegisterEvent("ACTIONBAR_UPDATE_USABLE");
  185. --self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN"); not updating cooldown from lua anymore, see SetActionUIButton
  186. self:RegisterEvent("SPELL_UPDATE_CHARGES");
  187. self:RegisterEvent("UPDATE_INVENTORY_ALERTS");
  188. self:RegisterEvent("PLAYER_TARGET_CHANGED");
  189. self:RegisterEvent("TRADE_SKILL_SHOW");
  190. self:RegisterEvent("TRADE_SKILL_CLOSE");
  191. self:RegisterEvent("ARCHAEOLOGY_CLOSED");
  192. self:RegisterEvent("PLAYER_ENTER_COMBAT");
  193. self:RegisterEvent("PLAYER_LEAVE_COMBAT");
  194. self:RegisterEvent("START_AUTOREPEAT_SPELL");
  195. self:RegisterEvent("STOP_AUTOREPEAT_SPELL");
  196. self:RegisterEvent("UNIT_ENTERED_VEHICLE");
  197. self:RegisterEvent("UNIT_EXITED_VEHICLE");
  198. self:RegisterEvent("COMPANION_UPDATE");
  199. self:RegisterEvent("UNIT_INVENTORY_CHANGED");
  200. self:RegisterEvent("LEARNED_SPELL_IN_TAB");
  201. self:RegisterEvent("PET_STABLE_UPDATE");
  202. self:RegisterEvent("PET_STABLE_SHOW");
  203. self:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_SHOW");
  204. self:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_HIDE");
  205. self:RegisterEvent("UPDATE_SUMMONPETS_ACTION");
  206. self:RegisterEvent("LOSS_OF_CONTROL_ADDED");
  207. self:RegisterEvent("LOSS_OF_CONTROL_UPDATE");
  208. self:RegisterEvent("SPELL_UPDATE_ICON");
  209. end
  210. function ActionBarActionEventsFrame_OnEvent(self, event, ...)
  211. if ( event == "UNIT_INVENTORY_CHANGED" ) then
  212. local unit = ...;
  213. if ( unit == "player" and self.tooltipOwner and GameTooltip:GetOwner() == self.tooltipOwner ) then
  214. ActionButton_SetTooltip(self.tooltipOwner);
  215. end
  216. else
  217. for k, frame in pairs(self.frames) do
  218. ActionButton_OnEvent(frame, event, ...);
  219. end
  220. end
  221. end
  222. function ActionBarActionEventsFrame_RegisterFrame(frame)
  223. ActionBarActionEventsFrame.frames[frame] = frame;
  224. end
  225. function ActionBarActionEventsFrame_UnregisterFrame(frame)
  226. ActionBarActionEventsFrame.frames[frame] = nil;
  227. end
  228. function ActionButton_OnLoad(self)
  229. self.flashing = 0;
  230. self.flashtime = 0;
  231. self:SetAttribute("showgrid", 0);
  232. self:SetAttribute("type", "action");
  233. self:SetAttribute("checkselfcast", true);
  234. self:SetAttribute("checkfocuscast", true);
  235. self:SetAttribute("useparent-unit", true);
  236. self:SetAttribute("useparent-actionpage", true);
  237. self:RegisterForDrag("LeftButton", "RightButton");
  238. self:RegisterForClicks("AnyUp");
  239. ActionBarButtonEventsFrame_RegisterFrame(self);
  240. ActionButton_UpdateAction(self);
  241. ActionButton_UpdateHotkeys(self, self.buttonType);
  242. end
  243. function ActionButton_UpdateHotkeys(self, actionButtonType)
  244. local id;
  245. if ( not actionButtonType ) then
  246. actionButtonType = "ACTIONBUTTON";
  247. id = self:GetID();
  248. else
  249. if ( actionButtonType == "MULTICASTACTIONBUTTON" ) then
  250. id = self.buttonIndex;
  251. else
  252. id = self:GetID();
  253. end
  254. end
  255. local hotkey = self.HotKey;
  256. local key = GetBindingKey(actionButtonType..id) or
  257. GetBindingKey("CLICK "..self:GetName()..":LeftButton");
  258. local text = GetBindingText(key, 1);
  259. if ( text == "" ) then
  260. hotkey:SetText(RANGE_INDICATOR);
  261. hotkey:Hide();
  262. else
  263. hotkey:SetText(text);
  264. hotkey:Show();
  265. end
  266. end
  267. function ActionButton_CalculateAction(self, button)
  268. if ( not button ) then
  269. button = SecureButton_GetEffectiveButton(self);
  270. end
  271. if ( self:GetID() > 0 ) then
  272. local page = SecureButton_GetModifiedAttribute(self, "actionpage", button);
  273. if ( not page ) then
  274. page = GetActionBarPage();
  275. if ( self.isExtra ) then
  276. page = GetExtraBarIndex();
  277. elseif ( self.buttonType == "MULTICASTACTIONBUTTON" ) then
  278. page = GetMultiCastBarIndex();
  279. end
  280. end
  281. return (self:GetID() + ((page - 1) * NUM_ACTIONBAR_BUTTONS));
  282. else
  283. return SecureButton_GetModifiedAttribute(self, "action", button) or 1;
  284. end
  285. end
  286. function ActionButton_UpdateAction(self, force)
  287. local action = ActionButton_CalculateAction(self);
  288. if ( action ~= self.action or force ) then
  289. self.action = action;
  290. SetActionUIButton(self, action, self.cooldown);
  291. ActionButton_Update(self);
  292. end
  293. end
  294. function ActionButton_Update(self)
  295. local action = self.action;
  296. local icon = self.icon;
  297. local buttonCooldown = self.cooldown;
  298. local texture = GetActionTexture(action);
  299. self.zoneAbilityDisabled = false;
  300. icon:SetDesaturated(false);
  301. local type, id = GetActionInfo(action);
  302. if ((type == "spell" or type == "companion") and ZoneAbilityFrame and ZoneAbilityFrame.baseName and not HasZoneAbility()) then
  303. local name = GetSpellInfo(ZoneAbilityFrame.baseName);
  304. local abilityName = GetSpellInfo(id);
  305. if (name == abilityName) then
  306. texture = GetLastZoneAbilitySpellTexture();
  307. self.zoneAbilityDisabled = true;
  308. icon:SetDesaturated(true);
  309. end
  310. end
  311. if ( HasAction(action) ) then
  312. if ( not self.eventsRegistered ) then
  313. ActionBarActionEventsFrame_RegisterFrame(self);
  314. self.eventsRegistered = true;
  315. end
  316. if ( not self:GetAttribute("statehidden") ) then
  317. self:Show();
  318. end
  319. ActionButton_UpdateState(self);
  320. ActionButton_UpdateUsable(self);
  321. ActionButton_UpdateCooldown(self);
  322. ActionButton_UpdateFlash(self);
  323. ActionButton_UpdateHighlightMark(self);
  324. ActionButton_UpdateSpellHighlightMark(self);
  325. else
  326. if ( self.eventsRegistered ) then
  327. ActionBarActionEventsFrame_UnregisterFrame(self);
  328. self.eventsRegistered = nil;
  329. end
  330. if ( self:GetAttribute("showgrid") == 0 ) then
  331. self:Hide();
  332. else
  333. buttonCooldown:Hide();
  334. end
  335. ClearChargeCooldown(self);
  336. ActionButton_ClearFlash(self);
  337. self:SetChecked(false);
  338. if self.LevelLinkLockIcon then
  339. self.LevelLinkLockIcon:SetShown(false);
  340. end
  341. end
  342. -- Add a green border if button is an equipped item
  343. local border = self.Border;
  344. if border then
  345. if ( IsEquippedAction(action) ) then
  346. border:SetVertexColor(0, 1.0, 0, 0.35);
  347. border:Show();
  348. else
  349. border:Hide();
  350. end
  351. end
  352. -- Update Action Text
  353. local actionName = self.Name;
  354. if actionName then
  355. if ( not IsConsumableAction(action) and not IsStackableAction(action) and (IsItemAction(action) or GetActionCount(action) == 0) ) then
  356. actionName:SetText(GetActionText(action));
  357. else
  358. actionName:SetText("");
  359. end
  360. end
  361. -- Update icon and hotkey text
  362. if ( texture ) then
  363. icon:SetTexture(texture);
  364. icon:Show();
  365. self.rangeTimer = -1;
  366. ActionButton_UpdateCount(self);
  367. else
  368. self.Count:SetText("");
  369. icon:Hide();
  370. buttonCooldown:Hide();
  371. self.rangeTimer = nil;
  372. local hotkey = self.HotKey;
  373. if ( hotkey:GetText() == RANGE_INDICATOR ) then
  374. hotkey:Hide();
  375. else
  376. hotkey:SetVertexColor(0.6, 0.6, 0.6);
  377. end
  378. end
  379. -- Update flyout appearance
  380. ActionButton_UpdateFlyout(self);
  381. ActionButton_UpdateOverlayGlow(self);
  382. -- Update tooltip
  383. if ( GameTooltip:GetOwner() == self ) then
  384. ActionButton_SetTooltip(self);
  385. end
  386. self.feedback_action = action;
  387. end
  388. function ActionButton_UpdateHighlightMark(self)
  389. if ( self.NewActionTexture ) then
  390. self.NewActionTexture:SetShown(GetNewActionHighlightMark(self.action));
  391. end
  392. end
  393. -- Shared between the action bar and the pet bar.
  394. function SharedActionButton_RefreshSpellHighlight(self, shown)
  395. if ( shown ) then
  396. self.SpellHighlightTexture:Show();
  397. self.SpellHighlightAnim:Play();
  398. else
  399. self.SpellHighlightTexture:Hide();
  400. self.SpellHighlightAnim:Stop();
  401. end
  402. end
  403. function ActionButton_UpdateSpellHighlightMark(self)
  404. if ( self.SpellHighlightTexture and self.SpellHighlightAnim ) then
  405. SharedActionButton_RefreshSpellHighlight(self, GetOnBarHighlightMark(self.action));
  406. end
  407. end
  408. function ActionButton_ShowGrid(button, reason)
  409. assert(button and reason);
  410. if ( issecure() ) then
  411. button:SetAttribute("showgrid", bit.bor(button:GetAttribute("showgrid"), reason));
  412. end
  413. if ( button.NormalTexture ) then
  414. button.NormalTexture:SetVertexColor(1.0, 1.0, 1.0, 0.5);
  415. end
  416. if ( button:GetAttribute("showgrid") > 0 and not button:GetAttribute("statehidden") ) then
  417. button:Show();
  418. end
  419. end
  420. function ActionButton_HideGrid(button, reason)
  421. assert(button and reason);
  422. local showgrid = button:GetAttribute("showgrid");
  423. if ( issecure() ) then
  424. if ( showgrid > 0 ) then
  425. button:SetAttribute("showgrid", bit.band(showgrid, bit.bnot(reason)));
  426. end
  427. end
  428. if ( button:GetAttribute("showgrid") == 0 and not HasAction(button.action) ) then
  429. button:Hide();
  430. end
  431. end
  432. function ActionButton_UpdateState(button)
  433. assert(button);
  434. local action = button.action;
  435. local isChecked = IsCurrentAction(action) or IsAutoRepeatAction(action);
  436. button:SetChecked(isChecked);
  437. end
  438. function ActionButton_UpdateUsable(self)
  439. local icon = self.icon;
  440. local normalTexture = self.NormalTexture;
  441. if ( not normalTexture ) then
  442. return;
  443. end
  444. local isUsable, notEnoughMana = IsUsableAction(self.action);
  445. if ( isUsable ) then
  446. icon:SetVertexColor(1.0, 1.0, 1.0);
  447. normalTexture:SetVertexColor(1.0, 1.0, 1.0);
  448. elseif ( notEnoughMana ) then
  449. icon:SetVertexColor(0.5, 0.5, 1.0);
  450. normalTexture:SetVertexColor(0.5, 0.5, 1.0);
  451. else
  452. icon:SetVertexColor(0.4, 0.4, 0.4);
  453. normalTexture:SetVertexColor(1.0, 1.0, 1.0);
  454. end
  455. local isLevelLinkLocked = C_LevelLink.IsActionLocked(self.action);
  456. if not icon:IsDesaturated() then
  457. icon:SetDesaturated(isLevelLinkLocked);
  458. end
  459. if self.LevelLinkLockIcon then
  460. self.LevelLinkLockIcon:SetShown(isLevelLinkLocked);
  461. end
  462. end
  463. function ActionButton_UpdateCount(self)
  464. local text = self.Count;
  465. local action = self.action;
  466. if ( IsConsumableAction(action) or IsStackableAction(action) or (not IsItemAction(action) and GetActionCount(action) > 0) ) then
  467. local count = GetActionCount(action);
  468. if ( count > (self.maxDisplayCount or 9999 ) ) then
  469. text:SetText("*");
  470. else
  471. text:SetText(count);
  472. end
  473. else
  474. local charges, maxCharges, chargeStart, chargeDuration = GetActionCharges(action);
  475. if (maxCharges > 1) then
  476. text:SetText(charges);
  477. else
  478. text:SetText("");
  479. end
  480. end
  481. end
  482. function ActionButton_UpdateCooldown(self)
  483. local locStart, locDuration;
  484. local start, duration, enable, charges, maxCharges, chargeStart, chargeDuration;
  485. local modRate = 1.0;
  486. local chargeModRate = 1.0;
  487. if ( self.spellID ) then
  488. locStart, locDuration = GetSpellLossOfControlCooldown(self.spellID);
  489. start, duration, enable, modRate = GetSpellCooldown(self.spellID);
  490. charges, maxCharges, chargeStart, chargeDuration, chargeModRate = GetSpellCharges(self.spellID);
  491. else
  492. locStart, locDuration = GetActionLossOfControlCooldown(self.action);
  493. start, duration, enable, modRate = GetActionCooldown(self.action);
  494. charges, maxCharges, chargeStart, chargeDuration, chargeModRate = GetActionCharges(self.action);
  495. end
  496. if ( (locStart + locDuration) > (start + duration) ) then
  497. if ( self.cooldown.currentCooldownType ~= COOLDOWN_TYPE_LOSS_OF_CONTROL ) then
  498. self.cooldown:SetEdgeTexture("Interface\\Cooldown\\edge-LoC");
  499. self.cooldown:SetSwipeColor(0.17, 0, 0);
  500. self.cooldown:SetHideCountdownNumbers(true);
  501. self.cooldown.currentCooldownType = COOLDOWN_TYPE_LOSS_OF_CONTROL;
  502. end
  503. CooldownFrame_Set(self.cooldown, locStart, locDuration, true, true, modRate);
  504. ClearChargeCooldown(self);
  505. else
  506. if ( self.cooldown.currentCooldownType ~= COOLDOWN_TYPE_NORMAL ) then
  507. self.cooldown:SetEdgeTexture("Interface\\Cooldown\\edge");
  508. self.cooldown:SetSwipeColor(0, 0, 0);
  509. self.cooldown:SetHideCountdownNumbers(false);
  510. self.cooldown.currentCooldownType = COOLDOWN_TYPE_NORMAL;
  511. end
  512. if( locStart > 0 ) then
  513. self.cooldown:SetScript("OnCooldownDone", ActionButton_OnCooldownDone );
  514. end
  515. if ( charges and maxCharges and maxCharges > 1 and charges < maxCharges ) then
  516. StartChargeCooldown(self, chargeStart, chargeDuration, chargeModRate);
  517. else
  518. ClearChargeCooldown(self);
  519. end
  520. CooldownFrame_Set(self.cooldown, start, duration, enable, false, modRate);
  521. end
  522. end
  523. function ActionButton_OnCooldownDone(self)
  524. self:SetScript("OnCooldownDone", nil);
  525. ActionButton_UpdateCooldown(self:GetParent());
  526. end
  527. -- Charge Cooldown stuff
  528. local numChargeCooldowns = 0;
  529. local function CreateChargeCooldownFrame(parent)
  530. numChargeCooldowns = numChargeCooldowns + 1;
  531. cooldown = CreateFrame("Cooldown", "ChargeCooldown"..numChargeCooldowns, parent, "CooldownFrameTemplate");
  532. cooldown:SetHideCountdownNumbers(true);
  533. cooldown:SetDrawSwipe(false);
  534. cooldown:SetAllPoints(parent);
  535. cooldown:SetFrameStrata("TOOLTIP");
  536. return cooldown;
  537. end
  538. function StartChargeCooldown(parent, chargeStart, chargeDuration, chargeModRate)
  539. if chargeStart == 0 then
  540. ClearChargeCooldown(parent);
  541. return;
  542. end
  543. parent.chargeCooldown = parent.chargeCooldown or CreateChargeCooldownFrame(parent);
  544. CooldownFrame_Set(parent.chargeCooldown, chargeStart, chargeDuration, true, true, chargeModRate);
  545. end
  546. function ClearChargeCooldown(parent)
  547. if parent.chargeCooldown then
  548. CooldownFrame_Clear(parent.chargeCooldown);
  549. end
  550. end
  551. --Overlay stuff
  552. local unusedOverlayGlows = {};
  553. local numOverlays = 0;
  554. function ActionButton_GetOverlayGlow()
  555. local overlay = tremove(unusedOverlayGlows);
  556. if ( not overlay ) then
  557. numOverlays = numOverlays + 1;
  558. overlay = CreateFrame("Frame", "ActionButtonOverlay"..numOverlays, UIParent, "ActionBarButtonSpellActivationAlert");
  559. end
  560. return overlay;
  561. end
  562. function ActionButton_UpdateOverlayGlow(self)
  563. local spellType, id, subType = GetActionInfo(self.action);
  564. if ( spellType == "spell" and IsSpellOverlayed(id) ) then
  565. ActionButton_ShowOverlayGlow(self);
  566. elseif ( spellType == "macro" ) then
  567. local spellId = GetMacroSpell(id);
  568. if ( spellId and IsSpellOverlayed(spellId) ) then
  569. ActionButton_ShowOverlayGlow(self);
  570. else
  571. ActionButton_HideOverlayGlow(self);
  572. end
  573. else
  574. ActionButton_HideOverlayGlow(self);
  575. end
  576. end
  577. function ActionButton_ShowOverlayGlow(self)
  578. if ( self.overlay ) then
  579. if ( self.overlay.animOut:IsPlaying() ) then
  580. self.overlay.animOut:Stop();
  581. self.overlay.animIn:Play();
  582. end
  583. else
  584. self.overlay = ActionButton_GetOverlayGlow();
  585. local frameWidth, frameHeight = self:GetSize();
  586. self.overlay:SetParent(self);
  587. self.overlay:ClearAllPoints();
  588. --Make the height/width available before the next frame:
  589. self.overlay:SetSize(frameWidth * 1.4, frameHeight * 1.4);
  590. self.overlay:SetPoint("TOPLEFT", self, "TOPLEFT", -frameWidth * 0.2, frameHeight * 0.2);
  591. self.overlay:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", frameWidth * 0.2, -frameHeight * 0.2);
  592. self.overlay.animIn:Play();
  593. end
  594. end
  595. function ActionButton_HideOverlayGlow(self)
  596. if ( self.overlay ) then
  597. if ( self.overlay.animIn:IsPlaying() ) then
  598. self.overlay.animIn:Stop();
  599. end
  600. if ( self:IsVisible() ) then
  601. self.overlay.animOut:Play();
  602. else
  603. ActionButton_OverlayGlowAnimOutFinished(self.overlay.animOut); --We aren't shown anyway, so we'll instantly hide it.
  604. end
  605. end
  606. end
  607. function ActionButton_OverlayGlowAnimOutFinished(animGroup)
  608. local overlay = animGroup:GetParent();
  609. local actionButton = overlay:GetParent();
  610. overlay:Hide();
  611. tinsert(unusedOverlayGlows, overlay);
  612. actionButton.overlay = nil;
  613. end
  614. function ActionButton_OverlayGlowOnUpdate(self, elapsed)
  615. AnimateTexCoords(self.ants, 256, 256, 48, 48, 22, elapsed, 0.01);
  616. local cooldown = self:GetParent().cooldown;
  617. -- we need some threshold to avoid dimming the glow during the gdc
  618. -- (using 1500 exactly seems risky, what if casting speed is slowed or something?)
  619. if(cooldown and cooldown:IsShown() and cooldown:GetCooldownDuration() > 3000) then
  620. self:SetAlpha(0.5);
  621. else
  622. self:SetAlpha(1.0);
  623. end
  624. end
  625. function ActionButton_OnEvent(self, event, ...)
  626. local arg1 = ...;
  627. if ((event == "UNIT_INVENTORY_CHANGED" and arg1 == "player") or event == "LEARNED_SPELL_IN_TAB") then
  628. if ( GameTooltip:GetOwner() == self ) then
  629. ActionButton_SetTooltip(self);
  630. end
  631. elseif ( event == "ACTIONBAR_SLOT_CHANGED" ) then
  632. if ( arg1 == 0 or arg1 == tonumber(self.action) ) then
  633. ClearNewActionHighlight(self.action, true);
  634. ActionButton_Update(self);
  635. end
  636. elseif ( event == "PLAYER_ENTERING_WORLD" ) then
  637. ActionButton_Update(self);
  638. elseif ( event == "UPDATE_SHAPESHIFT_FORM" ) then
  639. -- need to listen for UPDATE_SHAPESHIFT_FORM because attack icons change when the shapeshift form changes
  640. -- This is NOT intended to update everything about shapeshifting; most stuff should be handled by ActionBar-specific events such as UPDATE_BONUS_ACTIONBAR, UPDATE_USABLE, etc.
  641. local texture = GetActionTexture(self.action);
  642. if (texture) then
  643. self.icon:SetTexture(texture);
  644. end
  645. elseif ( event == "ACTIONBAR_SHOWGRID" ) then
  646. ActionButton_ShowGrid(self, ACTION_BUTTON_SHOW_GRID_REASON_EVENT);
  647. elseif ( event == "ACTIONBAR_HIDEGRID" ) then
  648. ActionButton_HideGrid(self, ACTION_BUTTON_SHOW_GRID_REASON_EVENT);
  649. elseif ( event == "UPDATE_BINDINGS" ) then
  650. ActionButton_UpdateHotkeys(self, self.buttonType);
  651. elseif ( event == "PLAYER_TARGET_CHANGED" ) then -- All event handlers below this line are only set when the button has an action
  652. self.rangeTimer = -1;
  653. elseif ( event == "UNIT_FLAGS" or event == "UNIT_AURA" or event == "PET_BAR_UPDATE" ) then
  654. -- Pet actions can also change the state of action buttons.
  655. ActionButton_UpdateState(self);
  656. ActionButton_UpdateFlash(self);
  657. elseif ( (event == "ACTIONBAR_UPDATE_STATE") or
  658. ((event == "UNIT_ENTERED_VEHICLE" or event == "UNIT_EXITED_VEHICLE") and (arg1 == "player")) or
  659. ((event == "COMPANION_UPDATE") and (arg1 == "MOUNT")) ) then
  660. ActionButton_UpdateState(self);
  661. elseif ( event == "ACTIONBAR_UPDATE_USABLE" or event == "PLAYER_MOUNT_DISPLAY_CHANGED" ) then
  662. ActionButton_UpdateUsable(self);
  663. elseif ( event == "LOSS_OF_CONTROL_UPDATE" ) then
  664. ActionButton_UpdateCooldown(self);
  665. elseif ( event == "ACTIONBAR_UPDATE_COOLDOWN" or event == "LOSS_OF_CONTROL_ADDED" ) then
  666. ActionButton_UpdateCooldown(self);
  667. -- Update tooltip
  668. if ( GameTooltip:GetOwner() == self ) then
  669. ActionButton_SetTooltip(self);
  670. end
  671. elseif ( event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" or event == "ARCHAEOLOGY_CLOSED" ) then
  672. ActionButton_UpdateState(self);
  673. elseif ( event == "PLAYER_ENTER_COMBAT" ) then
  674. if ( IsAttackAction(self.action) ) then
  675. ActionButton_StartFlash(self);
  676. end
  677. elseif ( event == "PLAYER_LEAVE_COMBAT" ) then
  678. if ( IsAttackAction(self.action) ) then
  679. ActionButton_StopFlash(self);
  680. end
  681. elseif ( event == "START_AUTOREPEAT_SPELL" ) then
  682. if ( IsAutoRepeatAction(self.action) ) then
  683. ActionButton_StartFlash(self);
  684. end
  685. elseif ( event == "STOP_AUTOREPEAT_SPELL" ) then
  686. if ( ActionButton_IsFlashing(self) and not IsAttackAction(self.action) ) then
  687. ActionButton_StopFlash(self);
  688. end
  689. elseif ( event == "PET_STABLE_UPDATE" or event == "PET_STABLE_SHOW") then
  690. -- Has to update everything for now, but this event should happen infrequently
  691. ActionButton_Update(self);
  692. elseif ( event == "SPELL_ACTIVATION_OVERLAY_GLOW_SHOW" ) then
  693. local actionType, id, subType = GetActionInfo(self.action);
  694. if ( actionType == "spell" and id == arg1 ) then
  695. ActionButton_ShowOverlayGlow(self);
  696. elseif ( actionType == "macro" ) then
  697. local spellId = GetMacroSpell(id);
  698. if ( spellId and spellId == arg1 ) then
  699. ActionButton_ShowOverlayGlow(self);
  700. end
  701. elseif (actionType == "flyout" and FlyoutHasSpell(id, arg1)) then
  702. ActionButton_ShowOverlayGlow(self);
  703. end
  704. elseif ( event == "SPELL_ACTIVATION_OVERLAY_GLOW_HIDE" ) then
  705. local actionType, id, subType = GetActionInfo(self.action);
  706. if ( actionType == "spell" and id == arg1 ) then
  707. ActionButton_HideOverlayGlow(self);
  708. elseif ( actionType == "macro" ) then
  709. local spellId = GetMacroSpell(id);
  710. if (spellId and spellId == arg1 ) then
  711. ActionButton_HideOverlayGlow(self);
  712. end
  713. elseif (actionType == "flyout" and FlyoutHasSpell(id, arg1)) then
  714. ActionButton_HideOverlayGlow(self);
  715. end
  716. elseif ( event == "SPELL_UPDATE_CHARGES" ) then
  717. ActionButton_UpdateCount(self);
  718. elseif ( event == "UPDATE_SUMMONPETS_ACTION" ) then
  719. local actionType, id = GetActionInfo(self.action);
  720. if (actionType == "summonpet") then
  721. local texture = GetActionTexture(self.action);
  722. if (texture) then
  723. self.icon:SetTexture(texture);
  724. end
  725. end
  726. elseif ( event == "SPELL_UPDATE_ICON" ) then
  727. ActionButton_Update(self);
  728. end
  729. end
  730. function ActionButton_SetTooltip(self)
  731. if ( GetCVar("UberTooltips") == "1" ) then
  732. GameTooltip_SetDefaultAnchor(GameTooltip, self);
  733. else
  734. local parent = self:GetParent();
  735. if ( parent == MultiBarBottomRight or parent == MultiBarRight or parent == MultiBarLeft ) then
  736. GameTooltip:SetOwner(self, "ANCHOR_LEFT");
  737. else
  738. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  739. end
  740. end
  741. if ( GameTooltip:SetAction(self.action) ) then
  742. self.UpdateTooltip = ActionButton_SetTooltip;
  743. else
  744. self.UpdateTooltip = nil;
  745. end
  746. end
  747. function ActionButton_OnUpdate(self, elapsed)
  748. if ( ActionButton_IsFlashing(self) ) then
  749. local flashtime = self.flashtime;
  750. flashtime = flashtime - elapsed;
  751. if ( flashtime <= 0 ) then
  752. local overtime = -flashtime;
  753. if ( overtime >= ATTACK_BUTTON_FLASH_TIME ) then
  754. overtime = 0;
  755. end
  756. flashtime = ATTACK_BUTTON_FLASH_TIME - overtime;
  757. local flashTexture = self.Flash;
  758. if ( flashTexture:IsShown() ) then
  759. flashTexture:Hide();
  760. else
  761. flashTexture:Show();
  762. end
  763. end
  764. self.flashtime = flashtime;
  765. end
  766. -- Handle range indicator
  767. local rangeTimer = self.rangeTimer;
  768. if ( rangeTimer ) then
  769. rangeTimer = rangeTimer - elapsed;
  770. if ( rangeTimer <= 0 ) then
  771. local valid = IsActionInRange(self.action);
  772. local checksRange = (valid ~= nil);
  773. local inRange = checksRange and valid;
  774. ActionButton_UpdateRangeIndicator(self, checksRange, inRange);
  775. rangeTimer = TOOLTIP_UPDATE_TIME;
  776. end
  777. self.rangeTimer = rangeTimer;
  778. end
  779. end
  780. function ActionButton_UpdateRangeIndicator(self, checksRange, inRange)
  781. if ( self.HotKey:GetText() == RANGE_INDICATOR ) then
  782. if ( checksRange ) then
  783. self.HotKey:Show();
  784. if ( inRange ) then
  785. self.HotKey:SetVertexColor(LIGHTGRAY_FONT_COLOR:GetRGB());
  786. else
  787. self.HotKey:SetVertexColor(RED_FONT_COLOR:GetRGB());
  788. end
  789. else
  790. self.HotKey:Hide();
  791. end
  792. else
  793. if ( checksRange and not inRange ) then
  794. self.HotKey:SetVertexColor(RED_FONT_COLOR:GetRGB());
  795. else
  796. self.HotKey:SetVertexColor(LIGHTGRAY_FONT_COLOR:GetRGB());
  797. end
  798. end
  799. end
  800. function ActionButton_GetPagedID(self)
  801. return self.action;
  802. end
  803. function ActionButton_UpdateFlash(self)
  804. local action = self.action;
  805. if ( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) ) then
  806. ActionButton_StartFlash(self);
  807. local actionType, actionID, actionSubtype = GetActionInfo(action);
  808. if ( actionSubtype == "pet" ) then
  809. self:GetCheckedTexture():SetAlpha(0.5);
  810. else
  811. self:GetCheckedTexture():SetAlpha(1.0);
  812. end
  813. else
  814. ActionButton_StopFlash(self);
  815. end
  816. if ( self.AutoCastable ) then
  817. self.AutoCastable:SetShown(C_ActionBar.IsAutoCastPetAction(action));
  818. if ( C_ActionBar.IsEnabledAutoCastPetAction(action) ) then
  819. self.AutoCastShine:Show();
  820. AutoCastShine_AutoCastStart(self.AutoCastShine);
  821. else
  822. self.AutoCastShine:Hide();
  823. AutoCastShine_AutoCastStop(self.AutoCastShine);
  824. end
  825. end
  826. end
  827. function ActionButton_ClearFlash(self)
  828. if ( self.AutoCastable ) then
  829. self.AutoCastable:Hide();
  830. self.AutoCastShine:Hide();
  831. AutoCastShine_AutoCastStop(self.AutoCastShine);
  832. end
  833. end
  834. function ActionButton_StartFlash(self)
  835. self.flashing = 1;
  836. self.flashtime = 0;
  837. ActionButton_UpdateState(self);
  838. end
  839. function ActionButton_StopFlash(self)
  840. self.flashing = 0;
  841. self.Flash:Hide();
  842. ActionButton_UpdateState (self);
  843. end
  844. function ActionButton_IsFlashing(self)
  845. if ( self.flashing == 1 ) then
  846. return 1;
  847. end
  848. return nil;
  849. end
  850. function ActionButton_UpdateFlyout(self)
  851. if not self.FlyoutArrow then
  852. return;
  853. end
  854. local actionType = GetActionInfo(self.action);
  855. if (actionType == "flyout") then
  856. -- Update border and determine arrow position
  857. local arrowDistance;
  858. if ((SpellFlyout and SpellFlyout:IsShown() and SpellFlyout:GetParent() == self) or GetMouseFocus() == self) then
  859. self.FlyoutBorder:Show();
  860. self.FlyoutBorderShadow:Show();
  861. arrowDistance = 5;
  862. else
  863. self.FlyoutBorder:Hide();
  864. self.FlyoutBorderShadow:Hide();
  865. arrowDistance = 2;
  866. end
  867. -- Update arrow
  868. self.FlyoutArrow:Show();
  869. self.FlyoutArrow:ClearAllPoints();
  870. local direction = self:GetAttribute("flyoutDirection");
  871. if (direction == "LEFT") then
  872. self.FlyoutArrow:SetPoint("LEFT", self, "LEFT", -arrowDistance, 0);
  873. SetClampedTextureRotation(self.FlyoutArrow, 270);
  874. elseif (direction == "RIGHT") then
  875. self.FlyoutArrow:SetPoint("RIGHT", self, "RIGHT", arrowDistance, 0);
  876. SetClampedTextureRotation(self.FlyoutArrow, 90);
  877. elseif (direction == "DOWN") then
  878. self.FlyoutArrow:SetPoint("BOTTOM", self, "BOTTOM", 0, -arrowDistance);
  879. SetClampedTextureRotation(self.FlyoutArrow, 180);
  880. else
  881. self.FlyoutArrow:SetPoint("TOP", self, "TOP", 0, arrowDistance);
  882. SetClampedTextureRotation(self.FlyoutArrow, 0);
  883. end
  884. else
  885. self.FlyoutBorder:Hide();
  886. self.FlyoutBorderShadow:Hide();
  887. self.FlyoutArrow:Hide();
  888. end
  889. end