SpellBookFrame.lua

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