SpellBookFrame.lua

SpellBookFrame.lua (9.0.2.37176; unchanged since 9.0.1.36230)
  1. MAX_SPELLS = 1024;
  2. MAX_SKILLLINE_TABS = 8;
  3. SPELLS_PER_PAGE = 12;
  4. MAX_SPELL_PAGES = ceil(MAX_SPELLS / SPELLS_PER_PAGE);
  5. BOOKTYPE_SPELL = "spell";
  6. BOOKTYPE_PROFESSION = "professions";
  7. BOOKTYPE_PET = "pet";
  8. local MaxSpellBookTypes = 5;
  9. local SpellBookInfo = {};
  10. SpellBookInfo[BOOKTYPE_SPELL] = { showFrames = {"SpellBookSpellIconsFrame", "SpellBookSideTabsFrame", "SpellBookPageNavigationFrame"},
  11. title = SPELLBOOK,
  12. updateFunc = function() SpellBook_UpdatePlayerTab(); end,
  13. mousewheelNavigation = true,
  14. };
  15. SpellBookInfo[BOOKTYPE_PROFESSION] = { showFrames = {"SpellBookProfessionFrame"},
  16. title = TRADE_SKILLS,
  17. updateFunc = function() SpellBook_UpdateProfTab(); end,
  18. bgFileL="Interface\\Spellbook\\Professions-Book-Left",
  19. bgFileR="Interface\\Spellbook\\Professions-Book-Right",
  20. mousewheelNavigation = false,
  21. };
  22. SpellBookInfo[BOOKTYPE_PET] = { showFrames = {"SpellBookSpellIconsFrame", "SpellBookPageNavigationFrame"},
  23. title = PET,
  24. updateFunc = function() SpellBook_UpdatePetTab(); end,
  25. mousewheelNavigation = true,
  26. };
  27. SPELLBOOK_PAGENUMBERS = {};
  28. SpellBookFrames = { "SpellBookSpellIconsFrame", "SpellBookProfessionFrame", "SpellBookSideTabsFrame", "SpellBookPageNavigationFrame" };
  29. PROFESSION_RANKS = {};
  30. PROFESSION_RANKS[1] = {75, APPRENTICE};
  31. PROFESSION_RANKS[2] = {150, JOURNEYMAN};
  32. PROFESSION_RANKS[3] = {225, EXPERT};
  33. PROFESSION_RANKS[4] = {300, ARTISAN};
  34. PROFESSION_RANKS[5] = {375, MASTER};
  35. PROFESSION_RANKS[6] = {450, GRAND_MASTER};
  36. PROFESSION_RANKS[7] = {525, ILLUSTRIOUS};
  37. PROFESSION_RANKS[8] = {600, ZEN_MASTER};
  38. PROFESSION_RANKS[9] = {700, DRAENOR_MASTER};
  39. PROFESSION_RANKS[10] = {800, LEGION_MASTER};
  40. PROFESSION_RANKS[11] = {950, BATTLE_FOR_AZEROTH_MASTER};
  41. OPEN_REASON_PENDING_GLYPH = "pendingglyph";
  42. OPEN_REASON_ACTIVATED_GLYPH = "activatedglyph";
  43. local SKILL_LINE_CLASS = 2;
  44. local SKILL_LINE_SPEC = 3;
  45. local ceil = ceil;
  46. local strlen = strlen;
  47. local tinsert = tinsert;
  48. local tremove = tremove;
  49. function ToggleSpellBook(bookType)
  50. HelpPlate_Hide();
  51. if ( (not HasPetSpells() or not PetHasSpellbook()) and bookType == BOOKTYPE_PET ) then
  52. return;
  53. end
  54. local isShown = SpellBookFrame:IsShown();
  55. if ( isShown and (SpellBookFrame.bookType == bookType) ) then
  56. HideUIPanel(SpellBookFrame);
  57. return;
  58. elseif isShown then
  59. SpellBookFrame_PlayOpenSound()
  60. SpellBookFrame.bookType = bookType;
  61. SpellBookFrame_Update();
  62. else
  63. SpellBookFrame.bookType = bookType;
  64. ShowUIPanel(SpellBookFrame);
  65. end
  66. end
  67. function SpellBookFrame_UpdateHelpPlate()
  68. if ( IsPlayerInitialSpec() ) then
  69. SpellBookFrame_HelpPlate[2].HighLightBox.height = 100;
  70. SpellBookFrame_HelpPlate[3].HighLightBox.height = GetNumSpecializations() * 50;
  71. SpellBookFrame_HelpPlate[3].HighLightBox.y = -125;
  72. else
  73. SpellBookFrame_HelpPlate[2].HighLightBox.height = 150;
  74. SpellBookFrame_HelpPlate[3].HighLightBox.height = (GetNumSpecializations() - 1) * 50;
  75. SpellBookFrame_HelpPlate[3].HighLightBox.y = -175;
  76. end
  77. end
  78. function SpellBookFrame_GetTutorialEnum()
  79. local helpPlate;
  80. local tutorial;
  81. if ( SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  82. helpPlate = SpellBookFrame_HelpPlate;
  83. tutorial = LE_FRAME_TUTORIAL_SPELLBOOK;
  84. elseif ( SpellBookFrame.bookType == BOOKTYPE_PROFESSION ) then
  85. helpPlate = ProfessionsFrame_HelpPlate;
  86. tutorial = LE_FRAME_TUTORIAL_PROFESSIONS;
  87. end
  88. return tutorial, helpPlate;
  89. end
  90. function SpellBookFrame_OnLoad(self)
  91. self:RegisterEvent("LEARNED_SPELL_IN_TAB");
  92. self:RegisterEvent("SKILL_LINES_CHANGED");
  93. self:RegisterEvent("TRIAL_STATUS_UPDATE");
  94. self:RegisterEvent("USE_GLYPH");
  95. self:RegisterEvent("CANCEL_GLYPH_CAST");
  96. self:RegisterEvent("ACTIVATE_GLYPH");
  97. self:RegisterEvent("CURRENT_SPELL_CAST_CHANGED");
  98. SpellBookFrame.bookType = BOOKTYPE_SPELL;
  99. -- Init page nums
  100. SPELLBOOK_PAGENUMBERS[1] = 1;
  101. SPELLBOOK_PAGENUMBERS[2] = 1;
  102. SPELLBOOK_PAGENUMBERS[3] = 1;
  103. SPELLBOOK_PAGENUMBERS[4] = 1;
  104. SPELLBOOK_PAGENUMBERS[5] = 1;
  105. SPELLBOOK_PAGENUMBERS[6] = 1;
  106. SPELLBOOK_PAGENUMBERS[7] = 1;
  107. SPELLBOOK_PAGENUMBERS[8] = 1;
  108. SPELLBOOK_PAGENUMBERS[BOOKTYPE_PET] = 1;
  109. -- Set to the class tab by default
  110. SpellBookFrame.selectedSkillLine = SKILL_LINE_CLASS;
  111. -- Initialize tab flashing
  112. SpellBookFrame.flashTabs = nil;
  113. -- Initialize portrait texture
  114. self:SetPortraitToAsset("Interface\\Spellbook\\Spellbook-Icon");
  115. ButtonFrameTemplate_HideButtonBar(SpellBookFrame);
  116. ButtonFrameTemplate_HideAttic(SpellBookFrame);
  117. end
  118. function SpellBookFrame_OnEvent(self, event, ...)
  119. if ( event == "SPELLS_CHANGED" ) then
  120. SpellBookFrame_Update();
  121. elseif ( event == "CURRENT_SPELL_CAST_CHANGED" ) then
  122. if (self.castingGlyphSlot and not IsCastingGlyph()) then
  123. SpellBookFrame.castingGlyphSlot = nil;
  124. SpellBookFrame_Update();
  125. end
  126. elseif ( event == "LEARNED_SPELL_IN_TAB" ) then
  127. SpellBookFrame_Update();
  128. local spellID, tabNum, isGuildSpell = ...;
  129. local flashFrame = _G["SpellBookSkillLineTab"..tabNum.."Flash"];
  130. if ( SpellBookFrame.bookType == BOOKTYPE_PET or isGuildSpell) then
  131. return;
  132. elseif ( tabNum <= GetNumSpellTabs() ) then
  133. if ( flashFrame ) then
  134. flashFrame:Show();
  135. SpellBookFrame.flashTabs = 1;
  136. end
  137. end
  138. elseif (event == "SKILL_LINES_CHANGED" or event == "TRIAL_STATUS_UPDATE") then
  139. SpellBook_UpdateProfTab();
  140. elseif (event == "PLAYER_GUILD_UPDATE") then
  141. -- default to class tab if the selected one is gone - happens if you leave a guild with perks
  142. if ( GetNumSpellTabs() < SpellBookFrame.selectedSkillLine ) then
  143. SpellBookFrame_Update();
  144. else
  145. SpellBookFrame_UpdateSkillLineTabs();
  146. end
  147. elseif ( event == "PLAYER_SPECIALIZATION_CHANGED" ) then
  148. SpellBookFrame_Update();
  149. elseif ( event == "USE_GLYPH" ) then
  150. local spellID = ...;
  151. SpellBookFrame_OpenToPageForGlyph(spellID, OPEN_REASON_PENDING_GLYPH);
  152. elseif ( event == "CANCEL_GLYPH_CAST" ) then
  153. SpellBookFrame_ClearAbilityHighlights();
  154. SpellFlyout:Hide();
  155. elseif ( event == "ACTIVATE_GLYPH" ) then
  156. local spellID = ...;
  157. SpellBookFrame_OpenToPageForGlyph(spellID, OPEN_REASON_ACTIVATED_GLYPH);
  158. end
  159. end
  160. function SpellBookFrame_OnShow(self)
  161. SpellBookFrame_Update();
  162. EventRegistry:TriggerEvent("SpellBookFrame.Show");
  163. -- If there are tabs waiting to flash, then flash them... yeah..
  164. if ( self.flashTabs ) then
  165. UIFrameFlash(SpellBookTabFlashFrame, 0.5, 0.5, 30, nil);
  166. end
  167. -- Show multibar slots
  168. MultiActionBar_ShowAllGrids(ACTION_BUTTON_SHOW_GRID_REASON_SPELLBOOK);
  169. UpdateMicroButtons();
  170. SpellBookFrame_PlayOpenSound();
  171. MicroButtonPulseStop(SpellbookMicroButton);
  172. self:RegisterEvent("SPELLS_CHANGED");
  173. self:RegisterUnitEvent("PLAYER_GUILD_UPDATE", "player");
  174. self:RegisterUnitEvent("PLAYER_SPECIALIZATION_CHANGED", "player");
  175. end
  176. function SpellBookFrame_Update()
  177. -- Reset if selected skillline button is gone
  178. if ( GetNumSpellTabs() < SpellBookFrame.selectedSkillLine ) then
  179. SpellBookFrame.selectedSkillLine = SKILL_LINE_CLASS;
  180. end
  181. -- Hide all tabs
  182. SpellBookFrameTabButton3:Hide();
  183. SpellBookFrameTabButton4:Hide();
  184. SpellBookFrameTabButton5:Hide();
  185. -- Setup tabs
  186. -- player spells and professions are always shown
  187. SpellBookFrameTabButton1:Show();
  188. SpellBookFrameTabButton1.bookType = BOOKTYPE_SPELL;
  189. SpellBookFrameTabButton1.binding = "TOGGLESPELLBOOK";
  190. SpellBookFrameTabButton1:SetText(SpellBookInfo[BOOKTYPE_SPELL].title);
  191. SpellBookFrameTabButton2:Show();
  192. SpellBookFrameTabButton2.bookType = BOOKTYPE_PROFESSION;
  193. SpellBookFrameTabButton2:SetText(SpellBookInfo[BOOKTYPE_PROFESSION].title);
  194. SpellBookFrameTabButton2.binding = "TOGGLEPROFESSIONBOOK";
  195. local tabIndex = 3;
  196. -- check to see if we have a pet
  197. local hasPetSpells, petToken = HasPetSpells();
  198. SpellBookFrame.petTitle = nil;
  199. if ( hasPetSpells and PetHasSpellbook() ) then
  200. SpellBookFrame.petTitle = _G["PET_TYPE_"..petToken];
  201. local nextTab = _G["SpellBookFrameTabButton"..tabIndex];
  202. nextTab:Show();
  203. nextTab.bookType = BOOKTYPE_PET;
  204. nextTab.binding = "TOGGLEPETBOOK";
  205. nextTab:SetText(SpellBookInfo[BOOKTYPE_PET].title);
  206. tabIndex = tabIndex+1;
  207. elseif (SpellBookFrame.bookType == BOOKTYPE_PET) then
  208. SpellBookFrame.bookType = _G["SpellBookFrameTabButton"..tabIndex-1].bookType;
  209. end
  210. local level = UnitLevel("player");
  211. -- Make sure the correct tab is selected
  212. for i=1,MaxSpellBookTypes do
  213. local tab = _G["SpellBookFrameTabButton"..i];
  214. PanelTemplates_TabResize(tab, 0, nil, 40);
  215. if ( tab.bookType == SpellBookFrame.bookType ) then
  216. PanelTemplates_SelectTab(tab);
  217. SpellBookFrame.currentTab = tab;
  218. else
  219. PanelTemplates_DeselectTab(tab);
  220. end
  221. end
  222. -- setup display
  223. for i, frame in ipairs(SpellBookFrames) do
  224. local found = false;
  225. for j,frame2 in ipairs(SpellBookInfo[SpellBookFrame.bookType].showFrames) do
  226. if (frame == frame2) then
  227. _G[frame]:Show();
  228. found = true;
  229. break;
  230. end
  231. end
  232. if (found == false) then
  233. _G[frame]:Hide();
  234. end
  235. end
  236. if SpellBookInfo[SpellBookFrame.bookType].bgFileL then
  237. SpellBookPage1:SetTexture(SpellBookInfo[SpellBookFrame.bookType].bgFileL);
  238. else
  239. SpellBookPage1:SetTexture("Interface\\Spellbook\\Spellbook-Page-1");
  240. end
  241. if SpellBookInfo[SpellBookFrame.bookType].bgFileR then
  242. SpellBookPage2:SetTexture(SpellBookInfo[SpellBookFrame.bookType].bgFileR);
  243. else
  244. SpellBookPage2:SetTexture("Interface\\Spellbook\\Spellbook-Page-2");
  245. end
  246. SpellBookFrame:SetTitle(SpellBookInfo[SpellBookFrame.bookType].title);
  247. local tabUpdate = SpellBookInfo[SpellBookFrame.bookType].updateFunc;
  248. if(tabUpdate) then
  249. tabUpdate()
  250. end
  251. -- if boosted, find the first locked spell and display a tip next to it
  252. HelpTip:Hide(SpellBookFrame, BOOSTED_CHAR_LOCKED_SPELL_TIP);
  253. if ( SpellBookFrame.bookType == BOOKTYPE_SPELL and IsCharacterNewlyBoosted() and not GetCVarBitfield("closedInfoFrames", LE_FRAME_TUTORIAL_BOOSTED_SPELL_BOOK) ) then
  254. local spellSlot;
  255. for i = 1, SPELLS_PER_PAGE do
  256. local spellBtn = _G["SpellButton" .. i];
  257. local slotType = select(2,SpellBook_GetSpellBookSlot(spellBtn));
  258. if (slotType == "FUTURESPELL") then
  259. if ( not spellSlot or spellBtn:GetID() < spellSlot:GetID() ) then
  260. spellSlot = spellBtn;
  261. end
  262. end
  263. end
  264. if ( spellSlot ) then
  265. local helpTipInfo = {
  266. text = BOOSTED_CHAR_LOCKED_SPELL_TIP,
  267. buttonStyle = HelpTip.ButtonStyle.Close,
  268. cvarBitfield = "closedInfoFrames",
  269. bitfieldFlag = LE_FRAME_TUTORIAL_BOOSTED_SPELL_BOOK,
  270. targetPoint = HelpTip.Point.RightEdgeCenter,
  271. offsetX = -6,
  272. };
  273. HelpTip:Show(SpellBookFrame, helpTipInfo, spellSlot);
  274. end
  275. end
  276. end
  277. function SpellBookFrame_UpdateSpells ()
  278. for i = 1, SPELLS_PER_PAGE do
  279. _G["SpellButton" .. i]:Show();
  280. SpellButton_UpdateButton(_G["SpellButton" .. i]);
  281. end
  282. if ( SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  283. SpellBookPage1:SetDesaturated(_G["SpellBookSkillLineTab"..SpellBookFrame.selectedSkillLine].isOffSpec);
  284. SpellBookPage2:SetDesaturated(_G["SpellBookSkillLineTab"..SpellBookFrame.selectedSkillLine].isOffSpec);
  285. else
  286. SpellBookPage1:SetDesaturated(false);
  287. SpellBookPage2:SetDesaturated(false);
  288. end
  289. end
  290. function SpellBookFrame_UpdatePages()
  291. local currentPage, maxPages = SpellBook_GetCurrentPage();
  292. if ( maxPages == nil or maxPages == 0 ) then
  293. return;
  294. end
  295. if ( currentPage > maxPages ) then
  296. if (SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  297. SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] = maxPages;
  298. else
  299. SPELLBOOK_PAGENUMBERS[SpellBookFrame.bookType] = maxPages;
  300. end
  301. currentPage = maxPages;
  302. if ( currentPage == 1 ) then
  303. SpellBookPrevPageButton:Disable();
  304. else
  305. SpellBookPrevPageButton:Enable();
  306. end
  307. if ( currentPage == maxPages ) then
  308. SpellBookNextPageButton:Disable();
  309. else
  310. SpellBookNextPageButton:Enable();
  311. end
  312. end
  313. if ( currentPage == 1 ) then
  314. SpellBookPrevPageButton:Disable();
  315. else
  316. SpellBookPrevPageButton:Enable();
  317. end
  318. if ( currentPage == maxPages ) then
  319. SpellBookNextPageButton:Disable();
  320. else
  321. SpellBookNextPageButton:Enable();
  322. end
  323. SpellBookPageText:SetFormattedText(PAGE_NUMBER, currentPage);
  324. end
  325. -- ------------------------------------------------------------------------------------------------------------
  326. -- returns the spell button, if it can find it, for the spellID passed in
  327. local buttonOrder = {1,3,5,7,9,11,2,4,6,8,10,12};
  328. function SpellBookFrame_OpenToSpell(spellID, toggleFlyout, reason)
  329. SpellBookFrame.bookType = BOOKTYPE_SPELL;
  330. ShowUIPanel(SpellBookFrame);
  331. local numTabs = GetNumSpellTabs();
  332. local slot = FindFlyoutSlotBySpellID(spellID);
  333. if (slot <= 0) then
  334. slot = FindSpellBookSlotBySpellID(spellID);
  335. end
  336. if slot then
  337. for tabIndex = 1, numTabs do
  338. local _, _, offset, numSlots = GetSpellTabInfo(tabIndex);
  339. if slot <= offset + numSlots then
  340. -- get to the correct tab and page
  341. local spellIndex = slot - offset;
  342. local page = 1;
  343. if spellIndex > SPELLS_PER_PAGE then
  344. page = math.ceil(spellIndex / SPELLS_PER_PAGE);
  345. spellIndex = spellIndex - ((page - 1) * SPELLS_PER_PAGE);
  346. end
  347. SPELLBOOK_PAGENUMBERS[tabIndex] = page;
  348. SpellBookFrame.selectedSkillLine = tabIndex;
  349. SpellBookFrame_Update();
  350. --now we need to find the spell button, which COULD be a flyout button
  351. local slotType, actionID = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  352. if ( slotType == "FLYOUT" ) then
  353. -- find the ACTUAL flyout button
  354. local buttonIndex = buttonOrder[spellIndex];
  355. local flyoutButton = _G["SpellButton" .. buttonIndex];
  356. --find the spellbutton INSIDE the flyout
  357. local numButtons = 1;
  358. local _, _, numSlots = GetFlyoutInfo(actionID);
  359. for i = 1, numSlots do
  360. local flyoutSpellID, overrideSpellID, isKnown, spellName, slotSpecID = GetFlyoutSlotInfo(actionID, i);
  361. if spellID == flyoutSpellID then -- we found it
  362. --open the flyout
  363. if toggleFlyout then
  364. SpellFlyout:Toggle(actionID, flyoutButton, "RIGHT", 1, false, flyoutButton.offSpecID, true, reason);
  365. end
  366. local returnButton = _G["SpellFlyoutButton"..i];
  367. return returnButton, flyoutButton;
  368. end
  369. local button = _G["SpellFlyoutButton"..i];
  370. if (button and button:IsShown()) then
  371. numButtons = numButtons + 1;
  372. end
  373. end
  374. else
  375. -- this is just a regular spell button
  376. local buttonIndex = buttonOrder[spellIndex];
  377. local returnButton = _G["SpellButton" .. buttonIndex];
  378. return returnButton;
  379. end
  380. end
  381. end
  382. end
  383. end
  384. function SpellBookFrame_PlayOpenSound()
  385. if ( SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  386. PlaySound(SOUNDKIT.IG_SPELLBOOK_OPEN);
  387. elseif ( SpellBookFrame.bookType == BOOKTYPE_PET ) then
  388. -- Need to change to pet book open sound
  389. PlaySound(SOUNDKIT.IG_ABILITY_OPEN);
  390. else
  391. PlaySound(SOUNDKIT.IG_SPELLBOOK_OPEN);
  392. end
  393. end
  394. function SpellBookFrame_PlayCloseSound()
  395. if ( SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  396. PlaySound(SOUNDKIT.IG_SPELLBOOK_CLOSE);
  397. else
  398. -- Need to change to pet book close sound
  399. PlaySound(SOUNDKIT.IG_ABILITY_CLOSE);
  400. end
  401. end
  402. function SpellBookFrame_OnHide(self)
  403. HelpPlate_Hide();
  404. SpellBookFrame_PlayCloseSound();
  405. EventRegistry:TriggerEvent("SpellBookFrame.Hide");
  406. -- Stop the flash frame from flashing if its still flashing.. flash flash flash
  407. UIFrameFlashStop(SpellBookTabFlashFrame);
  408. -- Hide all the flashing textures
  409. for i=1, MAX_SKILLLINE_TABS do
  410. _G["SpellBookSkillLineTab"..i.."Flash"]:Hide();
  411. end
  412. -- Hide multibar slots
  413. MultiActionBar_HideAllGrids(ACTION_BUTTON_SHOW_GRID_REASON_SPELLBOOK);
  414. -- Do this last, it can cause taint.
  415. UpdateMicroButtons();
  416. self:UnregisterEvent("SPELLS_CHANGED");
  417. self:UnregisterEvent("PLAYER_GUILD_UPDATE");
  418. self:UnregisterEvent("PLAYER_SPECIALIZATION_CHANGED");
  419. end
  420. function SpellButton_OnLoad(self)
  421. self:RegisterForDrag("LeftButton");
  422. self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
  423. end
  424. function SpellButton_OnEvent(self, event, ...)
  425. if ( event == "SPELLS_CHANGED" or event == "UPDATE_SHAPESHIFT_FORM" ) then
  426. -- need to listen for UPDATE_SHAPESHIFT_FORM because attack icons change when the shapeshift form changes
  427. SpellButton_UpdateButton(self);
  428. elseif ( event == "SPELL_UPDATE_COOLDOWN" ) then
  429. SpellButton_UpdateCooldown(self);
  430. -- Update tooltip
  431. if ( GameTooltip:GetOwner() == self ) then
  432. SpellButton_OnEnter(self);
  433. end
  434. elseif ( event == "CURRENT_SPELL_CAST_CHANGED" ) then
  435. SpellButton_UpdateSelection(self);
  436. elseif ( event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" or event == "ARCHAEOLOGY_CLOSED" ) then
  437. SpellButton_UpdateSelection(self);
  438. elseif ( event == "PET_BAR_UPDATE" ) then
  439. if ( SpellBookFrame.bookType == BOOKTYPE_PET ) then
  440. SpellButton_UpdateButton(self);
  441. end
  442. elseif ( event == "CURSOR_UPDATE" ) then
  443. if ( self.spellGrabbed ) then
  444. SpellButton_UpdateButton(self);
  445. self.spellGrabbed = false;
  446. end
  447. elseif ( event == "ACTIONBAR_SLOT_CHANGED" ) then
  448. local slot, slotType, slotID = SpellBook_GetSpellBookSlot(self);
  449. if ( not slot ) then
  450. return;
  451. end
  452. local _, actionID = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  453. local onActionBar = false;
  454. if ( slotType == "SPELL" ) then
  455. if (FindFlyoutSlotBySpellID(actionID) > 0) then
  456. -- We're part of a flyout
  457. SpellBookFrame_UpdateSpells();
  458. else
  459. onActionBar = C_ActionBar.IsOnBarOrSpecialBar(actionID);
  460. end
  461. elseif ( slotType == "FLYOUT" ) then
  462. onActionBar = C_ActionBar.HasFlyoutActionButtons(actionID);
  463. elseif ( slotType == "PETACTION" ) then
  464. onActionBar = C_ActionBar.HasPetActionButtons(actionID) or C_ActionBar.HasPetActionPetBarIndices(actionID);
  465. end
  466. if ( self.SpellHighlightTexture and self.SpellHighlightTexture:IsShown() == onActionBar ) then
  467. SpellButton_UpdateButton(self);
  468. end
  469. end
  470. end
  471. function SpellButton_OnShow(self)
  472. self:RegisterEvent("SPELLS_CHANGED");
  473. self:RegisterEvent("SPELL_UPDATE_COOLDOWN");
  474. self:RegisterEvent("UPDATE_SHAPESHIFT_FORM");
  475. self:RegisterEvent("CURRENT_SPELL_CAST_CHANGED");
  476. self:RegisterEvent("TRADE_SKILL_SHOW");
  477. self:RegisterEvent("TRADE_SKILL_CLOSE");
  478. self:RegisterEvent("ARCHAEOLOGY_CLOSED");
  479. self:RegisterEvent("PET_BAR_UPDATE");
  480. self:RegisterEvent("CURSOR_UPDATE");
  481. self:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
  482. --SpellButton_UpdateButton(self);
  483. end
  484. function SpellButton_OnHide(self)
  485. self:UnregisterEvent("SPELLS_CHANGED");
  486. self:UnregisterEvent("SPELL_UPDATE_COOLDOWN");
  487. self:UnregisterEvent("UPDATE_SHAPESHIFT_FORM");
  488. self:UnregisterEvent("CURRENT_SPELL_CAST_CHANGED");
  489. self:UnregisterEvent("TRADE_SKILL_SHOW");
  490. self:UnregisterEvent("TRADE_SKILL_CLOSE");
  491. self:UnregisterEvent("ARCHAEOLOGY_CLOSED");
  492. self:UnregisterEvent("PET_BAR_UPDATE");
  493. self:UnregisterEvent("CURSOR_UPDATE");
  494. self:UnregisterEvent("ACTIONBAR_SLOT_CHANGED");
  495. end
  496. function SpellButton_OnEnter(self)
  497. local slot = SpellBook_GetSpellBookSlot(self);
  498. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  499. if ( GameTooltip:SetSpellBookItem(slot, SpellBookFrame.bookType) ) then
  500. self.UpdateTooltip = SpellButton_OnEnter;
  501. else
  502. self.UpdateTooltip = nil;
  503. end
  504. ClearOnBarHighlightMarks();
  505. ClearPetActionHighlightMarks();
  506. local slotType, actionID = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  507. if ( slotType == "SPELL" ) then
  508. UpdateOnBarHighlightMarksBySpell(actionID);
  509. elseif ( slotType == "FLYOUT" ) then
  510. UpdateOnBarHighlightMarksByFlyout(actionID);
  511. elseif ( slotType == "PETACTION" ) then
  512. UpdateOnBarHighlightMarksByPetAction(actionID);
  513. UpdatePetActionHighlightMarks(actionID);
  514. PetActionBar_Update(PetActionBarFrame);
  515. end
  516. if ( self.SpellHighlightTexture and self.SpellHighlightTexture:IsShown() ) then
  517. GameTooltip:AddLine(SPELLBOOK_SPELL_NOT_ON_ACTION_BAR, LIGHTBLUE_FONT_COLOR.r, LIGHTBLUE_FONT_COLOR.g, LIGHTBLUE_FONT_COLOR.b);
  518. end
  519. -- Update action bar highlights
  520. ActionBarController_UpdateAll(true);
  521. GameTooltip:Show();
  522. end
  523. function SpellButton_OnLeave(self)
  524. ClearOnBarHighlightMarks();
  525. ClearPetActionHighlightMarks();
  526. -- Update action bar highlights
  527. ActionBarController_UpdateAll(true);
  528. PetActionBar_Update(PetActionBarFrame);
  529. GameTooltip:Hide();
  530. end
  531. function SpellButton_OnClick(self, button)
  532. local slot, slotType = SpellBook_GetSpellBookSlot(self);
  533. if ( slot > MAX_SPELLS or slotType == "FUTURESPELL") then
  534. return;
  535. end
  536. if ( HasPendingGlyphCast() and SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  537. local slotType, spellID = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  538. if (slotType == "SPELL") then
  539. if ( HasAttachedGlyph(spellID) ) then
  540. if ( IsPendingGlyphRemoval() ) then
  541. StaticPopup_Show("CONFIRM_GLYPH_REMOVAL", nil, nil, {name = GetCurrentGlyphNameForSpell(spellID), id = spellID});
  542. else
  543. StaticPopup_Show("CONFIRM_GLYPH_PLACEMENT", nil, nil, {name = GetPendingGlyphName(), currentName = GetCurrentGlyphNameForSpell(spellID), id = spellID});
  544. end
  545. else
  546. AttachGlyphToSpell(spellID);
  547. end
  548. elseif (slotType == "FLYOUT") then
  549. SpellFlyout:Toggle(spellID, self, "RIGHT", 1, false, self.offSpecID, true);
  550. SpellFlyout:SetBorderColor(181/256, 162/256, 90/256);
  551. end
  552. return;
  553. end
  554. if (self.isPassive) then
  555. return;
  556. end
  557. if ( button ~= "LeftButton" and SpellBookFrame.bookType == BOOKTYPE_PET ) then
  558. if ( self.offSpecID == 0 ) then
  559. ToggleSpellAutocast(slot, SpellBookFrame.bookType);
  560. end
  561. else
  562. local _, id = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  563. if (slotType == "FLYOUT") then
  564. SpellFlyout:Toggle(id, self, "RIGHT", 1, false, self.offSpecID, true);
  565. SpellFlyout:SetBorderColor(181/256, 162/256, 90/256);
  566. else
  567. if ( SpellBookFrame.bookType ~= BOOKTYPE_SPELLBOOK or self.offSpecID == 0 ) then
  568. CastSpell(slot, SpellBookFrame.bookType);
  569. end
  570. end
  571. SpellButton_UpdateSelection(self);
  572. end
  573. end
  574. function SpellButton_OnModifiedClick(self, button)
  575. local slot = SpellBook_GetSpellBookSlot(self);
  576. if ( slot > MAX_SPELLS ) then
  577. return;
  578. end
  579. if ( IsModifiedClick("CHATLINK") ) then
  580. if ( MacroFrameText and MacroFrameText:HasFocus() ) then
  581. local spellName, subSpellName = GetSpellBookItemName(slot, SpellBookFrame.bookType);
  582. if ( spellName and not IsPassiveSpell(slot, SpellBookFrame.bookType) ) then
  583. if ( subSpellName and (strlen(subSpellName) > 0) ) then
  584. ChatEdit_InsertLink(spellName.."("..subSpellName..")");
  585. else
  586. ChatEdit_InsertLink(spellName);
  587. end
  588. end
  589. return;
  590. else
  591. local tradeSkillLink, tradeSkillSpellID = GetSpellTradeSkillLink(slot, SpellBookFrame.bookType);
  592. if ( tradeSkillSpellID ) then
  593. ChatEdit_InsertLink(tradeSkillLink);
  594. else
  595. local spellLink = GetSpellLink(slot, SpellBookFrame.bookType);
  596. ChatEdit_InsertLink(spellLink);
  597. end
  598. return;
  599. end
  600. end
  601. if ( IsModifiedClick("PICKUPACTION") ) then
  602. PickupSpellBookItem(slot, SpellBookFrame.bookType);
  603. return;
  604. end
  605. if ( IsModifiedClick("SELFCAST") ) then
  606. CastSpell(slot, SpellBookFrame.bookType, true);
  607. SpellButton_UpdateSelection(self);
  608. return;
  609. end
  610. end
  611. function SpellButton_OnDrag(self)
  612. local slot, slotType = SpellBook_GetSpellBookSlot(self);
  613. if (not slot or slot > MAX_SPELLS or not _G[self:GetName().."IconTexture"]:IsShown() or (slotType == "FUTURESPELL")) then
  614. return;
  615. end
  616. self:SetChecked(false);
  617. PickupSpellBookItem(slot, SpellBookFrame.bookType);
  618. end
  619. function SpellButton_OnReceiveDrag(self)
  620. SpellButton_OnDrag(self);
  621. end
  622. function SpellButton_OnDragStart(self)
  623. SpellButton_OnDrag(self);
  624. self.spellGrabbed = true;
  625. if self.SpellHighlightTexture then
  626. self.SpellHighlightTexture:Hide();
  627. end
  628. end
  629. function SpellButton_UpdateSelection(self)
  630. -- We only highlight professions that are open. We used to highlight active shapeshifts and pet
  631. -- stances but we removed the highlight on those to avoid conflicting with the not-on-your-action-bar highlights.
  632. if SpellBookFrame.bookType == BOOKTYPE_PROFESSION then
  633. local slot = SpellBook_GetSpellBookSlot(self);
  634. if ( slot and IsSelectedSpellBookItem(slot, SpellBookFrame.bookType) ) then
  635. self:SetChecked(true);
  636. else
  637. self:SetChecked(false);
  638. end
  639. end
  640. end
  641. function SpellButton_UpdateCooldown(self)
  642. local cooldown = self.cooldown;
  643. local slot, slotType = SpellBook_GetSpellBookSlot(self);
  644. if (slot) then
  645. local start, duration, enable, modRate = GetSpellCooldown(slot, SpellBookFrame.bookType);
  646. if (cooldown and start and duration) then
  647. if (enable) then
  648. cooldown:Hide();
  649. else
  650. cooldown:Show();
  651. end
  652. CooldownFrame_Set(cooldown, start, duration, enable, false, modRate);
  653. else
  654. cooldown:Hide();
  655. end
  656. end
  657. end
  658. function SpellButton_UpdateButton(self)
  659. if SpellBookFrame.bookType == BOOKTYPE_PROFESSION then
  660. UpdateProfessionButton(self);
  661. return;
  662. end
  663. if ( not SpellBookFrame.selectedSkillLine ) then
  664. SpellBookFrame.selectedSkillLine = SKILL_LINE_CLASS;
  665. end
  666. local _, _, offset, numSlots, _, offSpecID, shouldHide, specID = GetSpellTabInfo(SpellBookFrame.selectedSkillLine);
  667. SpellBookFrame.selectedSkillLineNumSlots = numSlots;
  668. SpellBookFrame.selectedSkillLineOffset = offset;
  669. local isOffSpec = (offSpecID ~= 0) and (SpellBookFrame.bookType == BOOKTYPE_SPELL);
  670. self.offSpecID = offSpecID;
  671. if (not self.SpellName.shadowX) then
  672. self.SpellName.shadowX, self.SpellName.shadowY = self.SpellName:GetShadowOffset();
  673. end
  674. local slot, slotType, slotID = SpellBook_GetSpellBookSlot(self);
  675. local name = self:GetName();
  676. local iconTexture = _G[name.."IconTexture"];
  677. local levelLinkLockTexture = _G[name.."LevelLinkLockTexture"];
  678. local levelLinkLockBg = _G[name.."LevelLinkLockBg"];
  679. local spellString = _G[name.."SpellName"];
  680. local subSpellString = _G[name.."SubSpellName"];
  681. local cooldown = _G[name.."Cooldown"];
  682. local autoCastableTexture = _G[name.."AutoCastable"];
  683. local slotFrame = _G[name.."SlotFrame"];
  684. -- Hide flyout if it's currently open
  685. if (SpellFlyout:IsShown() and SpellFlyout:GetParent() == self and not HasPendingGlyphCast() and not SpellFlyout.glyphActivating) then
  686. SpellFlyout:Hide();
  687. end
  688. local highlightTexture = _G[name.."Highlight"];
  689. local texture;
  690. if ( slot ) then
  691. texture = GetSpellBookItemTexture(slot, SpellBookFrame.bookType);
  692. end
  693. -- If no spell, hide everything and return, or kiosk mode and future spell
  694. if ( not texture or (strlen(texture) == 0) or (slotType == "FUTURESPELL" and Kiosk.IsEnabled())) then
  695. iconTexture:Hide();
  696. levelLinkLockTexture:Hide();
  697. levelLinkLockBg:Hide();
  698. spellString:Hide();
  699. subSpellString:Hide();
  700. cooldown:Hide();
  701. autoCastableTexture:Hide();
  702. SpellBook_ReleaseAutoCastShine(self.shine);
  703. self.shine = nil;
  704. highlightTexture:SetTexture("Interface\\Buttons\\ButtonHilight-Square");
  705. self:SetChecked(false);
  706. slotFrame:Hide();
  707. self.IconTextureBg:Hide();
  708. self.SeeTrainerString:Hide();
  709. self.RequiredLevelString:Hide();
  710. self.UnlearnedFrame:Hide();
  711. self.TrainFrame:Hide();
  712. self.TrainTextBackground:Hide();
  713. self.TrainBook:Hide();
  714. self.FlyoutArrow:Hide();
  715. self.AbilityHighlightAnim:Stop();
  716. self.AbilityHighlight:Hide();
  717. self.GlyphIcon:Hide();
  718. self:Disable();
  719. self.TextBackground:SetDesaturated(isOffSpec);
  720. self.TextBackground2:SetDesaturated(isOffSpec);
  721. self.EmptySlot:SetDesaturated(isOffSpec);
  722. if self.SpellHighlightTexture then
  723. self.SpellHighlightTexture:Hide();
  724. end
  725. return;
  726. else
  727. self:Enable();
  728. end
  729. SpellButton_UpdateCooldown(self);
  730. local autoCastAllowed, autoCastEnabled = GetSpellAutocast(slot, SpellBookFrame.bookType);
  731. if ( autoCastAllowed ) then
  732. autoCastableTexture:Show();
  733. else
  734. autoCastableTexture:Hide();
  735. end
  736. if ( autoCastEnabled and not self.shine ) then
  737. self.shine = SpellBook_GetAutoCastShine();
  738. self.shine:Show();
  739. self.shine:SetParent(self);
  740. self.shine:SetPoint("CENTER", self, "CENTER");
  741. AutoCastShine_AutoCastStart(self.shine);
  742. elseif ( autoCastEnabled ) then
  743. self.shine:Show();
  744. self.shine:SetParent(self);
  745. self.shine:SetPoint("CENTER", self, "CENTER");
  746. AutoCastShine_AutoCastStart(self.shine);
  747. elseif ( not autoCastEnabled ) then
  748. SpellBook_ReleaseAutoCastShine(self.shine);
  749. self.shine = nil;
  750. end
  751. local spellName, _, spellID = GetSpellBookItemName(slot, SpellBookFrame.bookType);
  752. local isPassive = IsPassiveSpell(slot, SpellBookFrame.bookType);
  753. self.isPassive = isPassive;
  754. if (slotType == "FLYOUT") then
  755. SetClampedTextureRotation(self.FlyoutArrow, 90);
  756. self.FlyoutArrow:Show();
  757. else
  758. self.FlyoutArrow:Hide();
  759. end
  760. iconTexture:SetTexture(texture);
  761. spellString:SetText(spellName);
  762. self.SpellSubName:SetHeight(6);
  763. subSpellString:SetText("");
  764. if spellID then
  765. local spell = Spell:CreateFromSpellID(spellID);
  766. spell:ContinueOnSpellLoad(function()
  767. local subSpellName = spell:GetSpellSubtext();
  768. if ( subSpellName == "" ) then
  769. if ( IsTalentSpell(slot, SpellBookFrame.bookType, specID) ) then
  770. if ( isPassive ) then
  771. subSpellName = TALENT_PASSIVE;
  772. else
  773. subSpellName = TALENT;
  774. end
  775. elseif ( isPassive ) then
  776. subSpellName = SPELL_PASSIVE;
  777. end
  778. end
  779. -- If there is no spell sub-name, move the bottom row of text up
  780. if ( subSpellName ~= "" ) then
  781. self.SpellSubName:SetHeight(0);
  782. subSpellString:SetText(subSpellName);
  783. end
  784. end);
  785. end
  786. iconTexture:Show();
  787. spellString:Show();
  788. subSpellString:Show();
  789. local iconTextureAlpha;
  790. local iconTextureDesaturated;
  791. local isDisabled = spellID and C_SpellBook.IsSpellDisabled(spellID);
  792. if (not (slotType == "FUTURESPELL") and not isDisabled) then
  793. slotFrame:Show();
  794. self.UnlearnedFrame:Hide();
  795. self.TrainFrame:Hide();
  796. self.IconTextureBg:Hide();
  797. iconTextureAlpha = 1;
  798. iconTextureDesaturated = false;
  799. self.RequiredLevelString:Hide();
  800. self.SeeTrainerString:Hide();
  801. self.TrainTextBackground:Hide();
  802. self.TrainBook:Hide();
  803. self.SpellName:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
  804. self.SpellName:SetShadowOffset(self.SpellName.shadowX, self.SpellName.shadowY);
  805. self.SpellName:SetPoint("LEFT", self, "RIGHT", 8, 4);
  806. self.SpellSubName:SetTextColor(0, 0, 0);
  807. local _, actionID = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  808. if ( slotType == "SPELL" and not isOffSpec ) then
  809. if (IsSpellValidForPendingGlyph(actionID)) then
  810. self.AbilityHighlight:Show();
  811. self.AbilityHighlightAnim:Play();
  812. else
  813. self.AbilityHighlightAnim:Stop();
  814. self.AbilityHighlight:Hide();
  815. end
  816. if (HasAttachedGlyph(actionID) or SpellBookFrame.castingGlyphSlot == slot) then
  817. self.GlyphIcon:Show();
  818. else
  819. self.GlyphIcon:Hide();
  820. end
  821. else
  822. self.AbilityHighlightAnim:Stop();
  823. self.AbilityHighlight:Hide();
  824. self.GlyphIcon:Hide();
  825. end
  826. if self.SpellHighlightTexture then
  827. self.SpellHighlightTexture:Hide();
  828. if ( (SpellBookFrame.selectedSkillLine > 1 and not isOffSpec) or SpellBookFrame.bookType == BOOKTYPE_PET ) then
  829. if ( slotType == "SPELL" ) then
  830. -- If the spell is passive we never show the highlight. Otherwise, check if there are any action
  831. -- buttons with this spell.
  832. self.SpellHighlightTexture:SetShown(not isPassive and not C_ActionBar.IsOnBarOrSpecialBar(actionID));
  833. elseif ( slotType == "FLYOUT" ) then
  834. self.SpellHighlightTexture:SetShown(not C_ActionBar.HasFlyoutActionButtons(actionID));
  835. elseif ( slotType == "PETACTION" ) then
  836. if ( isPassive ) then
  837. self.SpellHighlightTexture:Hide();
  838. else
  839. local onBarSomewhere = C_ActionBar.HasPetActionButtons(actionID) or C_ActionBar.HasPetActionPetBarIndices(actionID);
  840. self.SpellHighlightTexture:SetShown(not onBarSomewhere);
  841. end
  842. end
  843. end
  844. end
  845. if ( slotType == "SPELL" and isOffSpec ) then
  846. local level = GetSpellLevelLearned(slotID);
  847. if ( level and level > 0 and level > UnitLevel("player") ) then
  848. self.RequiredLevelString:Show();
  849. self.RequiredLevelString:SetFormattedText(SPELLBOOK_AVAILABLE_AT, level);
  850. self.RequiredLevelString:SetTextColor(0.25, 0.12, 0);
  851. end
  852. end
  853. else
  854. local level = GetSpellAvailableLevel(slot, SpellBookFrame.bookType);
  855. slotFrame:Hide();
  856. self.AbilityHighlightAnim:Stop();
  857. self.AbilityHighlight:Hide();
  858. if self.SpellHighlightTexture then
  859. self.SpellHighlightTexture:Hide();
  860. end
  861. self.GlyphIcon:Hide();
  862. self.IconTextureBg:Show();
  863. iconTextureAlpha = .5;
  864. iconTextureDesaturated = true;
  865. if (IsCharacterNewlyBoosted()) then
  866. self.SeeTrainerString:Hide();
  867. self.UnlearnedFrame:Show();
  868. self.TrainFrame:Hide();
  869. self.TrainTextBackground:Hide();
  870. self.TrainBook:Hide();
  871. self.RequiredLevelString:Show();
  872. self.RequiredLevelString:SetText(BOOSTED_CHAR_SPELL_TEMPLOCK);
  873. self.RequiredLevelString:SetTextColor(0.25, 0.12, 0);
  874. self.SpellName:SetTextColor(0.25, 0.12, 0);
  875. self.SpellSubName:SetTextColor(0.25, 0.12, 0);
  876. self.SpellName:SetShadowOffset(0, 0);
  877. self.SpellName:SetPoint("LEFT", self, "RIGHT", 8, 6);
  878. elseif (level and level > UnitLevel("player") or isDisabled) then
  879. self.SeeTrainerString:Hide();
  880. local displayedLevel = isDisabled and GetSpellLevelLearned(slot, SpellBookFrame.bookType) or level;
  881. if displayedLevel > 0 then
  882. self.RequiredLevelString:SetFormattedText(SPELLBOOK_AVAILABLE_AT, displayedLevel);
  883. self.RequiredLevelString:SetTextColor(0.25, 0.12, 0);
  884. self.RequiredLevelString:Show();
  885. end
  886. self.UnlearnedFrame:Show();
  887. self.TrainFrame:Hide();
  888. self.TrainTextBackground:Hide();
  889. self.TrainBook:Hide();
  890. self.SpellName:SetTextColor(0.25, 0.12, 0);
  891. self.SpellSubName:SetTextColor(0.25, 0.12, 0);
  892. self.SpellName:SetShadowOffset(0, 0);
  893. self.SpellName:SetPoint("LEFT", self, "RIGHT", 8, 6);
  894. else
  895. self.SeeTrainerString:Show();
  896. self.RequiredLevelString:Hide();
  897. self.TrainFrame:Show();
  898. self.UnlearnedFrame:Hide();
  899. self.TrainTextBackground:Show();
  900. self.TrainBook:Show();
  901. self.SpellName:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  902. self.SpellName:SetShadowOffset(self.SpellName.shadowX, self.SpellName.shadowY);
  903. self.SpellName:SetPoint("LEFT", self, "RIGHT", 24, 8);
  904. self.SpellSubName:SetTextColor(0, 0, 0);
  905. end
  906. end
  907. local isLevelLinkLocked = spellID and C_LevelLink.IsSpellLocked(spellID) or false;
  908. levelLinkLockTexture:SetShown(isLevelLinkLocked);
  909. levelLinkLockBg:SetShown(isLevelLinkLocked);
  910. if isLevelLinkLocked then
  911. iconTexture:SetAlpha(1.0);
  912. iconTexture:SetDesaturated(true);
  913. else
  914. iconTexture:SetAlpha(iconTextureAlpha);
  915. iconTexture:SetDesaturated(iconTextureDesaturated);
  916. end
  917. if ( isPassive ) then
  918. highlightTexture:SetTexture("Interface\\Buttons\\UI-PassiveHighlight");
  919. slotFrame:Hide();
  920. self.UnlearnedFrame:Hide();
  921. else
  922. highlightTexture:SetTexture("Interface\\Buttons\\ButtonHilight-Square");
  923. end
  924. -- set all the desaturated offspec pages
  925. slotFrame:SetDesaturated(isOffSpec);
  926. self.TextBackground:SetDesaturated(isOffSpec);
  927. self.TextBackground2:SetDesaturated(isOffSpec);
  928. self.EmptySlot:SetDesaturated(isOffSpec);
  929. self.FlyoutArrow:SetDesaturated(isOffSpec);
  930. if (isOffSpec) then
  931. iconTexture:SetDesaturated(isOffSpec);
  932. self.SpellName:SetTextColor(0.75, 0.75, 0.75);
  933. self.RequiredLevelString:SetTextColor(0.1, 0.1, 0.1);
  934. autoCastableTexture:Hide();
  935. SpellBook_ReleaseAutoCastShine(self.shine);
  936. self.shine = nil;
  937. self:SetChecked(false);
  938. else
  939. SpellButton_UpdateSelection(self);
  940. end
  941. if GameTooltip:GetOwner() == self then
  942. SpellButton_OnEnter(self);
  943. end
  944. end
  945. function SpellBookPrevPageButton_OnClick()
  946. local pageNum = SpellBook_GetCurrentPage() - 1;
  947. if ( SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  948. PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN);
  949. SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] = pageNum;
  950. else
  951. -- Need to change to pet book pageturn sound
  952. PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN);
  953. SPELLBOOK_PAGENUMBERS[SpellBookFrame.bookType] = pageNum;
  954. end
  955. SpellBookFrame_Update();
  956. end
  957. function SpellBookNextPageButton_OnClick()
  958. local pageNum = SpellBook_GetCurrentPage() + 1;
  959. if ( SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  960. PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN);
  961. SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] = pageNum;
  962. else
  963. -- Need to change to pet book pageturn sound
  964. PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN);
  965. SPELLBOOK_PAGENUMBERS[SpellBookFrame.bookType] = pageNum;
  966. end
  967. SpellBookFrame_Update();
  968. end
  969. function SpellBookFrame_OnMouseWheel(self, value, scrollBar)
  970. --do nothing if not on an appropriate book type
  971. if not SpellBookInfo[SpellBookFrame.bookType].mousewheelNavigation then
  972. return;
  973. end
  974. local currentPage, maxPages = SpellBook_GetCurrentPage();
  975. if(value > 0) then
  976. if(currentPage > 1) then
  977. SpellBookPrevPageButton_OnClick()
  978. end
  979. else
  980. if(currentPage < maxPages) then
  981. SpellBookNextPageButton_OnClick()
  982. end
  983. end
  984. end
  985. function SpellBookSkillLineTab_OnClick(self)
  986. local id = self:GetID();
  987. if ( SpellBookFrame.selectedSkillLine ~= id ) then
  988. PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN);
  989. SpellBookFrame.selectedSkillLine = id;
  990. SpellBookFrame_Update();
  991. else
  992. self:SetChecked(true);
  993. end
  994. -- Stop tab flashing
  995. if ( self ) then
  996. local tabFlash = _G[self:GetName().."Flash"];
  997. if ( tabFlash ) then
  998. tabFlash:Hide();
  999. end
  1000. end
  1001. end
  1002. function SpellBookFrameTabButton_OnClick(self)
  1003. self:Disable();
  1004. if SpellBookFrame.currentTab then
  1005. SpellBookFrame.currentTab:Enable();
  1006. end
  1007. SpellBookFrame.currentTab = self;
  1008. ToggleSpellBook(self.bookType);
  1009. end
  1010. function SpellBook_GetSpellBookSlot(spellButton)
  1011. local id = spellButton:GetID()
  1012. if ( SpellBookFrame.bookType == BOOKTYPE_PROFESSION) then
  1013. return id + spellButton:GetParent().spellOffset;
  1014. elseif ( SpellBookFrame.bookType == BOOKTYPE_PET ) then
  1015. local slot = id + (SPELLS_PER_PAGE * (SPELLBOOK_PAGENUMBERS[BOOKTYPE_PET] - 1));
  1016. local slotType, slotID = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  1017. return slot, slotType, slotID;
  1018. else
  1019. local relativeSlot = id + ( SPELLS_PER_PAGE * (SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] - 1));
  1020. if ( SpellBookFrame.selectedSkillLineNumSlots and relativeSlot <= SpellBookFrame.selectedSkillLineNumSlots) then
  1021. local slot = SpellBookFrame.selectedSkillLineOffset + relativeSlot;
  1022. local slotType, slotID = GetSpellBookItemInfo(slot, SpellBookFrame.bookType);
  1023. return slot, slotType, slotID;
  1024. else
  1025. return nil, nil;
  1026. end
  1027. end
  1028. end
  1029. function SpellBook_GetButtonForID(id)
  1030. -- Currently the spell book is mapped such that odd numbered buttons from 1 - 11 match id 1 - 6, while even numbered buttons from 2 - 12 match 7 - 12
  1031. if (id > 6) then
  1032. return _G["SpellButton"..((id - 6) * 2)];
  1033. else
  1034. return _G["SpellButton"..(((id - 1) * 2) + 1)];
  1035. end
  1036. end
  1037. function SpellBookFrame_OpenToPageForGlyph(spellID, reason)
  1038. SpellBookFrame.bookType = BOOKTYPE_SPELL;
  1039. local toggleFlyout = true;
  1040. local button, flyoutButton = SpellBookFrame_OpenToSpell(spellID, toggleFlyout, reason);
  1041. if flyoutButton then
  1042. SpellFlyout:SetBorderColor(181/256, 162/256, 90/256);
  1043. elseif button then
  1044. if (reason == OPEN_REASON_PENDING_GLYPH) then
  1045. button.AbilityHighlight:Show();
  1046. button.AbilityHighlightAnim:Play();
  1047. elseif (reason == OPEN_REASON_ACTIVATED_GLYPH) then
  1048. button.AbilityHighlightAnim:Stop();
  1049. button.AbilityHighlight:Hide();
  1050. button.GlyphActivate:Show();
  1051. button.GlyphIcon:Show();
  1052. button.GlyphTranslation:Show();
  1053. button.GlyphActivateAnim:Play();
  1054. SpellBookFrame.castingGlyphSlot = slot;
  1055. end
  1056. end
  1057. end
  1058. function SpellBookFrame_ClearAbilityHighlights()
  1059. for i = 1, SPELLS_PER_PAGE do
  1060. local button = _G["SpellButton"..i];
  1061. button.AbilityHighlightAnim:Stop();
  1062. button.AbilityHighlight:Hide();
  1063. end
  1064. end
  1065. function SpellBook_GetCurrentPage()
  1066. local currentPage, maxPages;
  1067. local numPetSpells = HasPetSpells() or 0;
  1068. if ( SpellBookFrame.bookType == BOOKTYPE_PET ) then
  1069. currentPage = SPELLBOOK_PAGENUMBERS[BOOKTYPE_PET];
  1070. maxPages = ceil(numPetSpells/SPELLS_PER_PAGE);
  1071. elseif ( SpellBookFrame.bookType == BOOKTYPE_SPELL) then
  1072. currentPage = SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine];
  1073. local _, _, _, numSlots = GetSpellTabInfo(SpellBookFrame.selectedSkillLine);
  1074. maxPages = ceil(numSlots/SPELLS_PER_PAGE);
  1075. end
  1076. return currentPage, maxPages;
  1077. end
  1078. local maxShines = 1;
  1079. local shineGet = {}
  1080. function SpellBook_GetAutoCastShine ()
  1081. local shine = shineGet[1];
  1082. if ( shine ) then
  1083. tremove(shineGet, 1);
  1084. else
  1085. shine = CreateFrame("FRAME", "AutocastShine" .. maxShines, SpellBookFrame, "SpellBookShineTemplate");
  1086. maxShines = maxShines + 1;
  1087. end
  1088. return shine;
  1089. end
  1090. function SpellBook_ReleaseAutoCastShine (shine)
  1091. if ( not shine ) then
  1092. return;
  1093. end
  1094. shine:Hide();
  1095. AutoCastShine_AutoCastStop(shine);
  1096. tinsert(shineGet, shine);
  1097. end
  1098. -------------------------------------------------------------------
  1099. --------------------- Update functions for tabs --------------------
  1100. -------------------------------------------------------------------
  1101. function SpellBookFrame_UpdateSkillLineTabs()
  1102. local numSkillLineTabs = GetNumSpellTabs();
  1103. for i=1, MAX_SKILLLINE_TABS do
  1104. local skillLineTab = _G["SpellBookSkillLineTab"..i];
  1105. local prevTab = _G["SpellBookSkillLineTab"..i-1];
  1106. if ( i <= numSkillLineTabs and SpellBookFrame.bookType == BOOKTYPE_SPELL ) then
  1107. local name, texture, _, _, isGuild, offSpecID, shouldHide, specID = GetSpellTabInfo(i);
  1108. if ( shouldHide ) then
  1109. _G["SpellBookSkillLineTab"..i.."Flash"]:Hide();
  1110. skillLineTab:Hide();
  1111. else
  1112. local isOffSpec = (offSpecID ~= 0);
  1113. skillLineTab:SetNormalTexture(texture);
  1114. skillLineTab.tooltip = name;
  1115. skillLineTab:Show();
  1116. skillLineTab.isOffSpec = isOffSpec;
  1117. if(texture) then
  1118. skillLineTab:GetNormalTexture():SetDesaturated(isOffSpec);
  1119. end
  1120. -- Guild tab gets additional space
  1121. if (prevTab) then
  1122. if (isGuild) then
  1123. skillLineTab:SetPoint("TOPLEFT", prevTab, "BOTTOMLEFT", 0, -46);
  1124. elseif (isOffSpec and not prevTab.isOffSpec) then
  1125. skillLineTab:SetPoint("TOPLEFT", prevTab, "BOTTOMLEFT", 0, -40);
  1126. else
  1127. skillLineTab:SetPoint("TOPLEFT", prevTab, "BOTTOMLEFT", 0, -17);
  1128. end
  1129. end
  1130. -- Guild tab must show the Guild Banner
  1131. if (isGuild) then
  1132. skillLineTab:SetNormalTexture("Interface\\SpellBook\\GuildSpellbooktabBG");
  1133. skillLineTab.TabardEmblem:Show();
  1134. skillLineTab.TabardIconFrame:Show();
  1135. SetLargeGuildTabardTextures("player", skillLineTab.TabardEmblem, skillLineTab:GetNormalTexture(), skillLineTab.TabardIconFrame);
  1136. else
  1137. skillLineTab.TabardEmblem:Hide();
  1138. skillLineTab.TabardIconFrame:Hide();
  1139. end
  1140. -- Set the selected tab
  1141. if ( SpellBookFrame.selectedSkillLine == i ) then
  1142. skillLineTab:SetChecked(true);
  1143. --SpellBookSpellGroupText:SetText(name);
  1144. else
  1145. skillLineTab:SetChecked(false);
  1146. end
  1147. end
  1148. else
  1149. _G["SpellBookSkillLineTab"..i.."Flash"]:Hide();
  1150. skillLineTab:Hide();
  1151. end
  1152. end
  1153. end
  1154. function SpellBook_UpdatePlayerTab()
  1155. -- Setup skillline tabs
  1156. local _, _, offset, numSlots = GetSpellTabInfo(SpellBookFrame.selectedSkillLine);
  1157. SpellBookFrame.selectedSkillLineOffset = offset;
  1158. SpellBookFrame.selectedSkillLineNumSlots = numSlots;
  1159. SpellBookFrame_UpdatePages();
  1160. SpellBookFrame_UpdateSkillLineTabs();
  1161. SpellBookFrame_UpdateSpells();
  1162. end
  1163. function SpellBook_UpdatePetTab(showing)
  1164. SpellBookFrame_UpdatePages();
  1165. SpellBookFrame_UpdateSpells();
  1166. end
  1167. function UpdateProfessionButton(self)
  1168. local spellIndex = self:GetID() + self:GetParent().spellOffset;
  1169. local texture = GetSpellBookItemTexture(spellIndex, SpellBookFrame.bookType);
  1170. local spellName, _, spellID = GetSpellBookItemName(spellIndex, SpellBookFrame.bookType);
  1171. local isPassive = IsPassiveSpell(spellIndex, SpellBookFrame.bookType);
  1172. if ( isPassive ) then
  1173. self.highlightTexture:SetTexture("Interface\\Buttons\\UI-PassiveHighlight");
  1174. self.spellString:SetTextColor(PASSIVE_SPELL_FONT_COLOR.r, PASSIVE_SPELL_FONT_COLOR.g, PASSIVE_SPELL_FONT_COLOR.b);
  1175. else
  1176. self.highlightTexture:SetTexture("Interface\\Buttons\\ButtonHilight-Square");
  1177. self.spellString:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
  1178. end
  1179. self.iconTexture:SetTexture(texture);
  1180. local start, duration, enable = GetSpellCooldown(spellIndex, SpellBookFrame.bookType);
  1181. CooldownFrame_Set(self.cooldown, start, duration, enable);
  1182. if ( enable == 1 ) then
  1183. self.iconTexture:SetVertexColor(1.0, 1.0, 1.0);
  1184. else
  1185. self.iconTexture:SetVertexColor(0.4, 0.4, 0.4);
  1186. end
  1187. if ( self:GetParent().specializationIndex >= 0 and self:GetID() == self:GetParent().specializationOffset) then
  1188. self.unlearn:Show();
  1189. else
  1190. self.unlearn:Hide();
  1191. end
  1192. self.spellString:SetText(spellName);
  1193. self.subSpellString:SetText("");
  1194. if spellID then
  1195. local spell = Spell:CreateFromSpellID(spellID);
  1196. spell:ContinueOnSpellLoad(function()
  1197. self.subSpellString:SetText(spell:GetSpellSubtext());
  1198. end);
  1199. end
  1200. self.iconTexture:SetTexture(texture);
  1201. SpellButton_UpdateSelection(self);
  1202. end
  1203. function FormatProfession(frame, index)
  1204. if index then
  1205. frame.missingHeader:Hide();
  1206. frame.missingText:Hide();
  1207. local name, texture, rank, maxRank, numSpells, spelloffset, skillLine, rankModifier, specializationIndex, specializationOffset, skillLineName = GetProfessionInfo(index);
  1208. frame.skillName = name;
  1209. frame.spellOffset = spelloffset;
  1210. frame.skillLine = skillLine;
  1211. frame.specializationIndex = specializationIndex;
  1212. frame.specializationOffset = specializationOffset;
  1213. frame.statusBar:SetMinMaxValues(1,maxRank);
  1214. frame.statusBar:SetValue(rank);
  1215. local prof_title = "";
  1216. if (skillLineName) then
  1217. prof_title = skillLineName;
  1218. else
  1219. for i=1,#PROFESSION_RANKS do
  1220. local value,title = PROFESSION_RANKS[i][1], PROFESSION_RANKS[i][2];
  1221. if maxRank < value then break end
  1222. prof_title = title;
  1223. end
  1224. end
  1225. frame.rank:SetText(prof_title);
  1226. frame.statusBar:Show();
  1227. if rank == maxRank then
  1228. frame.statusBar.capRight:Show();
  1229. else
  1230. frame.statusBar.capRight:Hide();
  1231. end
  1232. frame.statusBar.capped:Hide();
  1233. frame.statusBar.rankText:SetTextColor(HIGHLIGHT_FONT_COLOR:GetRGB());
  1234. frame.statusBar.tooltip = nil;
  1235. -- trial cap
  1236. if ( GameLimitedMode_IsActive() ) then
  1237. local _, _, profCap = GetRestrictedAccountData();
  1238. if rank >= profCap and profCap > 0 then
  1239. frame.statusBar.capped:Show();
  1240. frame.statusBar.rankText:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
  1241. frame.statusBar.tooltip = RED_FONT_COLOR_CODE..CAP_REACHED_TRIAL..FONT_COLOR_CODE_CLOSE;
  1242. end
  1243. end
  1244. if frame.icon and texture then
  1245. SetPortraitToTexture(frame.icon, texture);
  1246. frame.unlearn:Show();
  1247. end
  1248. frame.professionName:SetText(name);
  1249. if ( rankModifier > 0 ) then
  1250. frame.statusBar.rankText:SetFormattedText(TRADESKILL_RANK_WITH_MODIFIER, rank, rankModifier, maxRank);
  1251. else
  1252. frame.statusBar.rankText:SetFormattedText(TRADESKILL_RANK, rank, maxRank);
  1253. end
  1254. if numSpells <= 0 then
  1255. frame.button1:Hide();
  1256. frame.button2:Hide();
  1257. elseif numSpells == 1 then
  1258. frame.button2:Hide();
  1259. frame.button1:Show();
  1260. UpdateProfessionButton(frame.button1);
  1261. else -- if numSpells >= 2 then
  1262. frame.button1:Show();
  1263. frame.button2:Show();
  1264. UpdateProfessionButton(frame.button1);
  1265. UpdateProfessionButton(frame.button2);
  1266. end
  1267. if numSpells > 2 then
  1268. local errorStr = "Found "..numSpells.." skills for "..name.." the max is 2:"
  1269. for i=1,numSpells do
  1270. errorStr = errorStr.." ("..GetSpellBookItemName(i + spelloffset, SpellBookFrame.bookType)..")";
  1271. end
  1272. assert(false, errorStr)
  1273. end
  1274. else
  1275. frame.missingHeader:Show();
  1276. frame.missingText:Show();
  1277. if frame.icon then
  1278. SetPortraitToTexture(frame.icon, "Interface\\Icons\\INV_Scroll_04");
  1279. frame.unlearn:Hide();
  1280. frame.specialization:SetText("");
  1281. end
  1282. frame.button1:Hide();
  1283. frame.button2:Hide();
  1284. frame.statusBar:Hide();
  1285. frame.rank:SetText("");
  1286. frame.professionName:SetText("");
  1287. end
  1288. end
  1289. function SpellBook_UpdateProfTab()
  1290. local prof1, prof2, arch, fish, cook = GetProfessions();
  1291. FormatProfession(PrimaryProfession1, prof1);
  1292. FormatProfession(PrimaryProfession2, prof2);
  1293. FormatProfession(SecondaryProfession1, cook);
  1294. FormatProfession(SecondaryProfession2, fish);
  1295. FormatProfession(SecondaryProfession3, arch);
  1296. SpellBookPage1:SetDesaturated(false);
  1297. SpellBookPage2:SetDesaturated(false);
  1298. end
  1299. -- *************************************************************************************
  1300. SpellBookFrame_HelpPlate = {
  1301. FramePos = { x = 5, y = -22 },
  1302. FrameSize = { width = 580, height = 500 },
  1303. [1] = { ButtonPos = { x = 250, y = -50}, HighLightBox = { x = 65, y = -25, width = 460, height = 462 }, ToolTipDir = "DOWN", ToolTipText = SPELLBOOK_HELP_1 },
  1304. [2] = { ButtonPos = { x = 520, y = -30 }, HighLightBox = { x = 540, y = -5, width = 46, height = 150 }, ToolTipDir = "LEFT", ToolTipText = SPELLBOOK_HELP_2 },
  1305. [3] = { ButtonPos = { x = 520, y = -150}, HighLightBox = { x = 540, y = -175, width = 46, height = 100 }, ToolTipDir = "LEFT", ToolTipText = SPELLBOOK_HELP_3, MinLevel = 10 },
  1306. }
  1307. ProfessionsFrame_HelpPlate = {
  1308. FramePos = { x = 5, y = -22 },
  1309. FrameSize = { width = 545, height = 500 },
  1310. [1] = { ButtonPos = { x = 150, y = -110 }, HighLightBox = { x = 60, y = -35, width = 460, height = 195 }, ToolTipDir = "UP", ToolTipText = PROFESSIONS_HELP_1 },
  1311. [2] = { ButtonPos = { x = 150, y = -325}, HighLightBox = { x = 60, y = -235, width = 460, height = 240 }, ToolTipDir = "UP", ToolTipText = PROFESSIONS_HELP_2 },
  1312. }
  1313. function SpellBook_ToggleTutorial()
  1314. SpellBookFrame_UpdateHelpPlate();
  1315. local tutorial, helpPlate = SpellBookFrame_GetTutorialEnum();
  1316. if ( helpPlate and not HelpPlate_IsShowing(helpPlate) and SpellBookFrame:IsShown()) then
  1317. HelpPlate_Show( helpPlate, SpellBookFrame, SpellBookFrame.MainHelpButton );
  1318. SetCVarBitfield( "closedInfoFrames", tutorial, true );
  1319. else
  1320. HelpPlate_Hide(true);
  1321. end
  1322. end