InterfaceOptionsFrame.lua

InterfaceOptionsFrame.lua (9.0.5.38134; unchanged since 9.0.1.36230)
  1. INTERFACEOPTIONS_ADDONCATEGORIES = {};
  2. local blizzardCategories = {};
  3. local securecall = securecall;
  4. local next = next;
  5. local function SecureNext(elements, key)
  6. return securecall(next, elements, key);
  7. end
  8. local tinsert = tinsert;
  9. local strlower = strlower;
  10. -- [[ InterfaceOptionsList functions ]] --
  11. function InterfaceOptionsList_DisplayPanel (frame)
  12. if ( InterfaceOptionsFramePanelContainer.displayedPanel ) then
  13. InterfaceOptionsFramePanelContainer.displayedPanel:Hide();
  14. end
  15. InterfaceOptionsFramePanelContainer.displayedPanel = frame;
  16. frame:SetParent(InterfaceOptionsFramePanelContainer);
  17. frame:ClearAllPoints();
  18. frame:SetPoint("TOPLEFT", InterfaceOptionsFramePanelContainer, "TOPLEFT");
  19. frame:SetPoint("BOTTOMRIGHT", InterfaceOptionsFramePanelContainer, "BOTTOMRIGHT");
  20. frame:Show();
  21. end
  22. function InterfaceOptionsListButton_OnClick (self, mouseButton)
  23. if ( mouseButton == "RightButton" ) then
  24. if ( self.element.hasChildren ) then
  25. OptionsListButtonToggle_OnClick(self.toggle);
  26. end
  27. return;
  28. end
  29. local parent = self:GetParent();
  30. local buttons = parent.buttons;
  31. OptionsList_ClearSelection(InterfaceOptionsFrameCategories, InterfaceOptionsFrameCategories.buttons);
  32. OptionsList_ClearSelection(InterfaceOptionsFrameAddOns, InterfaceOptionsFrameAddOns.buttons);
  33. OptionsList_SelectButton(parent, self);
  34. InterfaceOptionsList_DisplayPanel(self.element);
  35. end
  36. function InterfaceOptionsListButton_ToggleSubCategories (self)
  37. local element = self.element;
  38. element.collapsed = not element.collapsed;
  39. local collapsed = element.collapsed;
  40. for _, category in SecureNext, blizzardCategories do
  41. if ( category.parent == element.name ) then
  42. if ( collapsed ) then
  43. category.hidden = true;
  44. else
  45. category.hidden = false;
  46. end
  47. end
  48. end
  49. for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
  50. if ( category.parent == element.name ) then
  51. if ( collapsed ) then
  52. category.hidden = true;
  53. else
  54. category.hidden = false;
  55. end
  56. end
  57. end
  58. InterfaceCategoryList_Update();
  59. InterfaceAddOnsList_Update();
  60. end
  61. --Table to reuse! Yay reuse!
  62. local displayedElements = {}
  63. function InterfaceCategoryList_Update ()
  64. --Redraw the scroll lists
  65. local offset = FauxScrollFrame_GetOffset(InterfaceOptionsFrameCategoriesList);
  66. local buttons = InterfaceOptionsFrameCategories.buttons;
  67. local element;
  68. for i, element in SecureNext, displayedElements do
  69. displayedElements[i] = nil;
  70. end
  71. for i, element in SecureNext, blizzardCategories do
  72. if ( not element.hidden ) then
  73. tinsert(displayedElements, element);
  74. end
  75. end
  76. local numButtons = #buttons;
  77. local numCategories = #displayedElements;
  78. if ( numCategories > numButtons and ( not InterfaceOptionsFrameCategoriesList:IsShown() ) ) then
  79. OptionsList_DisplayScrollBar(InterfaceOptionsFrameCategories);
  80. elseif ( numCategories <= numButtons and ( InterfaceOptionsFrameCategoriesList:IsShown() ) ) then
  81. OptionsList_HideScrollBar(InterfaceOptionsFrameCategories);
  82. end
  83. FauxScrollFrame_Update(InterfaceOptionsFrameCategoriesList, numCategories, numButtons, buttons[1]:GetHeight());
  84. local selection = InterfaceOptionsFrameCategories.selection;
  85. if ( selection ) then
  86. -- Store the currently selected element and clear all the buttons, we're redrawing.
  87. OptionsList_ClearSelection(InterfaceOptionsFrameCategories, InterfaceOptionsFrameCategories.buttons);
  88. end
  89. for i = 1, numButtons do
  90. element = displayedElements[i + offset];
  91. if ( not element ) then
  92. OptionsList_HideButton(buttons[i]);
  93. else
  94. OptionsList_DisplayButton(buttons[i], element);
  95. if ( selection ) and ( selection == element ) and ( not InterfaceOptionsFrameCategories.selection ) then
  96. OptionsList_SelectButton(InterfaceOptionsFrameCategories, buttons[i]);
  97. end
  98. end
  99. end
  100. if ( selection ) then
  101. -- If there was a selected element before we cleared the button highlights, restore it, 'cause we're done.
  102. -- Note: This theoretically might already have been done by OptionsList_SelectButton, but in the event that the selected button hasn't been drawn, this is still necessary.
  103. InterfaceOptionsFrameCategories.selection = selection;
  104. end
  105. end
  106. function InterfaceAddOnsList_Update ()
  107. -- Might want to merge this into InterfaceCategoryList_Update depending on whether or not things get differentiated.
  108. local offset = FauxScrollFrame_GetOffset(InterfaceOptionsFrameAddOnsList);
  109. local buttons = InterfaceOptionsFrameAddOns.buttons;
  110. local element;
  111. for i, element in SecureNext, displayedElements do
  112. displayedElements[i] = nil;
  113. end
  114. for i, element in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
  115. if ( not element.hidden ) then
  116. tinsert(displayedElements, element);
  117. end
  118. end
  119. local numAddOnCategories = #displayedElements;
  120. local numButtons = #buttons;
  121. -- Show the AddOns tab if it's not empty.
  122. local showTabs = numAddOnCategories > 0;
  123. InterfaceOptionsFrameTab1:SetShown(showTabs);
  124. InterfaceOptionsFrameTab2:SetShown(showTabs);
  125. if ( numAddOnCategories > numButtons and ( not InterfaceOptionsFrameAddOnsList:IsShown() ) ) then
  126. -- We need to show the scroll bar, we have more elements than buttons.
  127. OptionsList_DisplayScrollBar(InterfaceOptionsFrameAddOns);
  128. elseif ( numAddOnCategories <= numButtons and ( InterfaceOptionsFrameAddOnsList:IsShown() ) ) then
  129. -- Hide the scrollbar, there's nothing to scroll.
  130. OptionsList_HideScrollBar(InterfaceOptionsFrameAddOns);
  131. end
  132. FauxScrollFrame_Update(InterfaceOptionsFrameAddOnsList, numAddOnCategories, numButtons, buttons[1]:GetHeight());
  133. local selection = InterfaceOptionsFrameAddOns.selection;
  134. if ( selection ) then
  135. OptionsList_ClearSelection(InterfaceOptionsFrameAddOns, InterfaceOptionsFrameAddOns.buttons);
  136. end
  137. for i = 1, #buttons do
  138. element = displayedElements[i + offset]
  139. if ( not element ) then
  140. OptionsList_HideButton(buttons[i]);
  141. else
  142. OptionsList_DisplayButton(buttons[i], element);
  143. if ( selection ) and ( selection == element ) and ( not InterfaceOptionsFrameAddOns.selection ) then
  144. OptionsList_SelectButton(InterfaceOptionsFrameAddOns, buttons[i]);
  145. end
  146. end
  147. end
  148. if ( selection ) then
  149. InterfaceOptionsFrameAddOns.selection = selection;
  150. end
  151. end
  152. -- [[ InterfaceOptionsFrame ]] --
  153. function InterfaceOptionsFrame_Show ()
  154. if ( InterfaceOptionsFrame:IsShown() ) then
  155. InterfaceOptionsFrame:Hide();
  156. else
  157. InterfaceOptionsFrame:Show();
  158. end
  159. end
  160. local function InterfaceOptionsFrame_RunOkayForCategory (category)
  161. pcall(category.okay, category);
  162. end
  163. local function InterfaceOptionsFrame_RunDefaultForCategory (category)
  164. pcall(category.default, category);
  165. end
  166. local function InterfaceOptionsFrame_RunCancelForCategory (category)
  167. pcall(category.cancel, category);
  168. end
  169. local function InterfaceOptionsFrame_RunRefreshForCategory (category)
  170. pcall(category.refresh, category);
  171. end
  172. function InterfaceOptionsFrameOkay_OnClick (self, button, apply)
  173. --Iterate through registered panels and run their okay methods in a taint-safe fashion
  174. for _, category in SecureNext, blizzardCategories do
  175. securecall(InterfaceOptionsFrame_RunOkayForCategory, category);
  176. end
  177. for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
  178. securecall(InterfaceOptionsFrame_RunOkayForCategory, category);
  179. end
  180. if ( InterfaceOptionsFrame.gameRestart ) then
  181. StaticPopup_Show("CLIENT_RESTART_ALERT");
  182. InterfaceOptionsFrame.gameRestart = nil;
  183. elseif ( InterfaceOptionsFrame.logout ) then
  184. StaticPopup_Show("CLIENT_LOGOUT_ALERT");
  185. InterfaceOptionsFrame.logout = nil;
  186. end
  187. if ( not apply ) then
  188. InterfaceOptionsFrame_Show();
  189. end
  190. end
  191. function InterfaceOptionsFrameCancel_OnClick (self, button)
  192. --Iterate through registered panels and run their cancel methods in a taint-safe fashion
  193. for _, category in SecureNext, blizzardCategories do
  194. securecall(InterfaceOptionsFrame_RunCancelForCategory, category);
  195. end
  196. for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
  197. securecall(InterfaceOptionsFrame_RunCancelForCategory, category);
  198. end
  199. InterfaceOptionsFrame.gameRestart = nil;
  200. InterfaceOptionsFrame.logout = nil;
  201. InterfaceOptionsFrame_Show();
  202. end
  203. function InterfaceOptionsFrameDefaults_OnClick (self, button)
  204. StaticPopup_Show("CONFIRM_RESET_INTERFACE_SETTINGS");
  205. end
  206. function InterfaceOptionsSocialPanelRedockChat_OnClick ()
  207. FCF_RedockAllWindows();
  208. end
  209. function InterfaceOptionsFrame_SetAllToDefaults ()
  210. --Iterate through registered panels and run their default methods in a taint-safe fashion
  211. for _, category in SecureNext, blizzardCategories do
  212. securecall(InterfaceOptionsFrame_RunDefaultForCategory, category);
  213. end
  214. for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
  215. securecall(InterfaceOptionsFrame_RunDefaultForCategory, category);
  216. end
  217. --Refresh the categories to pick up changes made.
  218. InterfaceOptionsOptionsFrame_RefreshCategories();
  219. InterfaceOptionsOptionsFrame_RefreshAddOns();
  220. end
  221. function InterfaceOptionsFrame_SetCurrentToDefaults ()
  222. local displayedPanel = InterfaceOptionsFramePanelContainer.displayedPanel;
  223. if ( not displayedPanel or not displayedPanel.default ) then
  224. return;
  225. end
  226. displayedPanel.default(displayedPanel);
  227. --Run the refresh method to refresh any values that were changed.
  228. displayedPanel.refresh(displayedPanel);
  229. end
  230. function InterfaceOptionsOptionsFrame_RefreshCategories ()
  231. for _, category in SecureNext, blizzardCategories do
  232. securecall(InterfaceOptionsFrame_RunRefreshForCategory, category);
  233. end
  234. end
  235. function InterfaceOptionsOptionsFrame_RefreshAddOns ()
  236. for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
  237. securecall(InterfaceOptionsFrame_RunRefreshForCategory, category);
  238. end
  239. end
  240. local UVARINFO = {
  241. ["REMOVE_CHAT_DELAY"] = { default = "0", cvar = "removeChatDelay", event = "REMOVE_CHAT_DELAY_TEXT" },
  242. ["LOCK_ACTIONBAR"] = { default = "0", cvar = "lockActionBars", event = "LOCK_ACTIONBAR_TEXT" },
  243. ["SHOW_BUFF_DURATIONS"] = { default = "1", cvar = "buffDurations", event = "SHOW_BUFF_DURATION_TEXT", func = function () SHOW_BUFF_DURATIONS = GetCVar("buffDurations"); BuffFrame_UpdatePositions(); end},
  244. ["ALWAYS_SHOW_MULTIBARS"] = { default = "0", cvar = "alwaysShowActionBars", event = "ALWAYS_SHOW_MULTIBARS_TEXT" },
  245. ["SHOW_PARTY_PETS"] = { default = "0", cvar = "showPartyPets", event = "SHOW_PARTY_PETS_TEXT" },
  246. ["SHOW_PARTY_BACKGROUND"] = { default = "0", cvar = "showPartyBackground", event = "SHOW_PARTY_BACKGROUND_TEXT" },
  247. ["SHOW_TARGET_OF_TARGET"] = { default = "0", cvar = "showTargetOfTarget", event = "SHOW_TARGET_OF_TARGET_TEXT" },
  248. ["AUTO_QUEST_WATCH"] = { default = "1", cvar = "autoQuestWatch", event = "AUTO_QUEST_WATCH_TEXT" },
  249. ["LOOT_UNDER_MOUSE"] = { default = "0", cvar = "lootUnderMouse", event = "LOOT_UNDER_MOUSE_TEXT" },
  250. ["AUTO_LOOT_DEFAULT"] = { default = "0", cvar = "autoLootDefault", event = "AUTO_LOOT_DEFAULT_TEXT" },
  251. ["SHOW_COMBAT_TEXT"] = { default = "1", cvar = "enableFloatingCombatText", event = "SHOW_COMBAT_TEXT_TEXT" },
  252. ["COMBAT_TEXT_SHOW_LOW_HEALTH_MANA"] = { default = "1", cvar = "floatingCombatTextLowManaHealth", event = "COMBAT_TEXT_SHOW_LOW_HEALTH_MANA_TEXT" },
  253. ["COMBAT_TEXT_SHOW_AURAS"] = { default = "0", cvar = "floatingCombatTextAuras", event = "COMBAT_TEXT_SHOW_AURAS_TEXT" },
  254. ["COMBAT_TEXT_SHOW_AURA_FADE"] = { default = "0", cvar = "floatingCombatTextAuras", event = "COMBAT_TEXT_SHOW_AURAS_TEXT" },
  255. ["COMBAT_TEXT_SHOW_COMBAT_STATE"] = { default = "0", cvar = "floatingCombatTextCombatState", event = "COMBAT_TEXT_SHOW_COMBAT_STATE_TEXT" },
  256. ["COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"] = { default = "0", cvar = "floatingCombatTextDodgeParryMiss", event = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS_TEXT" },
  257. ["COMBAT_TEXT_SHOW_RESISTANCES"] = { default = "0", cvar = "floatingCombatTextDamageReduction", event = "COMBAT_TEXT_SHOW_RESISTANCES_TEXT" },
  258. ["COMBAT_TEXT_SHOW_REPUTATION"] = { default = "1", cvar = "floatingCombatTextRepChanges", event = "COMBAT_TEXT_SHOW_REPUTATION_TEXT" },
  259. ["COMBAT_TEXT_SHOW_REACTIVES"] = { default = "0", cvar = "floatingCombatTextReactives", event = "COMBAT_TEXT_SHOW_REACTIVES_TEXT" },
  260. ["COMBAT_TEXT_SHOW_FRIENDLY_NAMES"] = { default = "0", cvar = "floatingCombatTextFriendlyHealers", event = "COMBAT_TEXT_SHOW_FRIENDLY_NAMES_TEXT" },
  261. ["COMBAT_TEXT_SHOW_COMBO_POINTS"] = { default = "0", cvar = "floatingCombatTextComboPoints", event = "COMBAT_TEXT_SHOW_COMBO_POINTS_TEXT" },
  262. ["COMBAT_TEXT_SHOW_ENERGIZE"] = { default = "0", cvar = "floatingCombatTextEnergyGains", event = "COMBAT_TEXT_SHOW_ENERGIZE_TEXT" },
  263. ["COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE"] = { default = "0", cvar = "floatingCombatTextPeriodicEnergyGains", event = "COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE_TEXT" },
  264. ["COMBAT_TEXT_FLOAT_MODE"] = { default = "1", cvar = "floatingCombatTextFloatMode", event = "COMBAT_TEXT_FLOAT_MODE" },
  265. ["COMBAT_TEXT_SHOW_HONOR_GAINED"] = { default = "0", cvar = "floatingCombatTextHonorGains", event = "COMBAT_TEXT_SHOW_HONOR_GAINED_TEXT" },
  266. ["ALWAYS_SHOW_MULTIBARS"] = { default = "0", cvar = "alwaysShowActionBars", },
  267. ["SHOW_CASTABLE_BUFFS"] = { default = "0", cvar = "showCastableBuffs", event = "SHOW_CASTABLE_BUFFS_TEXT" },
  268. ["SHOW_DISPELLABLE_DEBUFFS"] = { default = "1", cvar = "showDispelDebuffs", event = "SHOW_DISPELLABLE_DEBUFFS_TEXT" },
  269. ["SHOW_ARENA_ENEMY_FRAMES"] = { default = "1", cvar = "showArenaEnemyFrames", event = "SHOW_ARENA_ENEMY_FRAMES_TEXT" },
  270. ["SHOW_ARENA_ENEMY_CASTBAR"] = { default = "1", cvar = "showArenaEnemyCastbar", event = "SHOW_ARENA_ENEMY_CASTBAR_TEXT" },
  271. ["SHOW_ARENA_ENEMY_PETS"] = { default = "1", cvar = "showArenaEnemyPets", event = "SHOW_ARENA_ENEMY_PETS_TEXT" },
  272. }
  273. function InterfaceOptionsFrame_InitializeUVars ()
  274. -- Setup UVars that keep settings
  275. for uvar, setting in SecureNext, UVARINFO do
  276. _G[uvar] = setting.default;
  277. end
  278. end
  279. function InterfaceOptionsFrame_LoadUVars ()
  280. local variable, cvarValue
  281. for uvar, setting in SecureNext, UVARINFO do
  282. variable = _G[uvar];
  283. cvarValue = GetCVar(setting.cvar);
  284. if ( cvarValue == setting.default and variable ~= setting.default ) then
  285. SetCVar(setting.cvar, variable, setting.event)
  286. if ( setting.func ) then
  287. setting.func()
  288. end
  289. elseif ( cvarValue ~= setting.default or ( not ( _G[uvar] ) ) ) then
  290. _G[uvar] = cvarValue;
  291. if ( setting.func ) then
  292. setting.func()
  293. end
  294. end
  295. end
  296. end
  297. function InterfaceOptionsFrame_OnLoad (self)
  298. --Make sure all the UVars get their default values set, since systems that require them to be defined will be loaded before anything in UIOptionsPanels
  299. self:RegisterEvent("VARIABLES_LOADED");
  300. InterfaceOptionsFrame_InitializeUVars();
  301. PanelTemplates_SetNumTabs(self, 2);
  302. InterfaceOptionsFrame.selectedTab = 1;
  303. PanelTemplates_UpdateTabs(self);
  304. end
  305. function InterfaceOptionsFrame_OnEvent (self, event, ...)
  306. if ( event == "VARIABLES_LOADED" ) then
  307. InterfaceOptionsFrame_LoadUVars();
  308. end
  309. end
  310. function InterfaceOptionsFrame_OnShow (self)
  311. --Refresh the two category lists and display the "Controls" group of options if nothing is selected.
  312. InterfaceCategoryList_Update();
  313. InterfaceOptionsOptionsFrame_RefreshCategories();
  314. InterfaceAddOnsList_Update();
  315. if ( not InterfaceOptionsFramePanelContainer.displayedPanel ) then
  316. InterfaceOptionsFrame_OpenToCategory(CONTROLS_LABEL);
  317. end
  318. --Refresh the categories to pick up changes made while the options frame was hidden.
  319. InterfaceOptionsOptionsFrame_RefreshAddOns();
  320. end
  321. function InterfaceOptionsFrame_OnHide (self)
  322. OptionsFrame_OnHide(InterfaceOptionsFrame);
  323. if ( InterfaceOptionsFrame.gameRestart ) then
  324. StaticPopup_Show("CLIENT_RESTART_ALERT");
  325. InterfaceOptionsFrame.gameRestart = nil;
  326. elseif ( InterfaceOptionsFrame.logout ) then
  327. StaticPopup_Show("CLIENT_LOGOUT_ALERT");
  328. InterfaceOptionsFrame.logout = nil;
  329. end
  330. end
  331. function InterfaceOptionsFrame_TabOnClick ()
  332. if ( InterfaceOptionsFrame.selectedTab == 1 ) then
  333. InterfaceOptionsFrameCategories:Show();
  334. InterfaceOptionsFrameAddOns:Hide();
  335. else
  336. InterfaceOptionsFrameCategories:Hide();
  337. InterfaceOptionsFrameAddOns:Show();
  338. end
  339. end
  340. function InterfaceOptionsFrame_OpenToCategory (panel)
  341. local panelName;
  342. if ( type(panel) == "string" ) then
  343. panelName = panel;
  344. panel = nil;
  345. end
  346. assert(panelName or panel, 'Usage: InterfaceOptionsFrame_OpenToCategory("categoryName" or panel)');
  347. local blizzardElement, elementToDisplay
  348. for i, element in SecureNext, blizzardCategories do
  349. if ( element == panel or (panelName and element.name and element.name == panelName) ) then
  350. elementToDisplay = element;
  351. blizzardElement = true;
  352. break;
  353. end
  354. end
  355. if ( not elementToDisplay ) then
  356. for i, element in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
  357. if ( element == panel or (panelName and element.name and element.name == panelName) ) then
  358. elementToDisplay = element;
  359. break;
  360. end
  361. end
  362. end
  363. if ( not elementToDisplay ) then
  364. return;
  365. end
  366. if ( blizzardElement ) then
  367. InterfaceOptionsFrameTab1:Click();
  368. local buttons = InterfaceOptionsFrameCategories.buttons;
  369. for i, button in SecureNext, buttons do
  370. if ( button.element == elementToDisplay ) then
  371. InterfaceOptionsListButton_OnClick(button);
  372. elseif ( elementToDisplay.parent and button.element and (button.element.name == elementToDisplay.parent and button.element.collapsed) ) then
  373. OptionsListButtonToggle_OnClick(button.toggle);
  374. end
  375. end
  376. if ( not InterfaceOptionsFrame:IsShown() ) then
  377. InterfaceOptionsFrame_Show();
  378. end
  379. else
  380. InterfaceOptionsFrameTab2:Click();
  381. local buttons = InterfaceOptionsFrameAddOns.buttons;
  382. for i, button in SecureNext, buttons do
  383. if ( button.element == elementToDisplay ) then
  384. InterfaceOptionsListButton_OnClick(button);
  385. elseif ( elementToDisplay.parent and button.element and (button.element.name == elementToDisplay.parent and button.element.collapsed) ) then
  386. OptionsListButtonToggle_OnClick(button.toggle);
  387. end
  388. end
  389. if ( not InterfaceOptionsFrame:IsShown() ) then
  390. InterfaceOptionsFrame_Show();
  391. end
  392. end
  393. end
  394. ---------------------------------------------------------------------------------------------------
  395. -- HOWTO: Add new categories of options
  396. --
  397. -- The new Interface Options frame allows authors to place their configuration
  398. -- frames (aka "panels") alongside the panels for modifying the default UI.
  399. --
  400. -- Adding a new panel to the Interface Options frame is a fairly straightforward process.
  401. -- Any frame can be used as a panel as long as it implements the required values and methods.
  402. -- Once a frame is ready to be used as a panel, it must be registered using the function
  403. -- InterfaceOptions_AddCategory, i.e. InterfaceOptions_AddCategory(panel)
  404. --
  405. -- Panels can be designated as sub-categories of existing options. These panels are listed
  406. -- with smaller text, offset, and tied to parent categories. The parent categories can be expanded
  407. -- or collapsed to toggle display of their sub-categories.
  408. --
  409. -- When players select a category of options from the Interface Options frame, the panel associated
  410. -- with that category will be anchored to the right hand side of the Interface Options frame and shown.
  411. --
  412. -- The following members and methods are used by the Interface Options frame to display and organize panels.
  413. --
  414. -- panel.name - string (required)
  415. -- The name of the AddOn or group of configuration options.
  416. -- This is the text that will display in the AddOn options list.
  417. --
  418. -- panel.parent - string (optional)
  419. -- Name of the parent of the AddOn or group of configuration options.
  420. -- This identifies "panel" as the child of another category.
  421. -- If the parent category doesn't exist, "panel" will be displayed as a regular category.
  422. --
  423. -- panel.okay - function (optional)
  424. -- This method will run when the player clicks "okay" in the Interface Options.
  425. --
  426. -- panel.cancel - function (optional)
  427. -- This method will run when the player clicks "cancel" in the Interface Options.
  428. -- Use this to revert their changes.
  429. --
  430. -- panel.default - function (optional)
  431. -- This method will run when the player clicks "defaults".
  432. -- Use this to revert their changes to your defaults.
  433. --
  434. -- panel.refresh - function (optional)
  435. -- This method will run when the Interface Options frame calls its OnShow function and after defaults
  436. -- have been applied via the panel.default method described above.
  437. -- Use this to refresh your panel's UI in case settings were changed without player interaction.
  438. --
  439. -- EXAMPLE -- Use XML to create a frame, and through its OnLoad function, make the frame a panel.
  440. --
  441. -- MyAddOn.xml
  442. -- ≤Frame name="ExamplePanel">
  443. -- ≤Scripts>
  444. -- ≤OnLoad>
  445. -- ExamplePanel_OnLoad(self);
  446. -- ≤/OnLoad>
  447. -- ≤/Scripts>
  448. -- ≤/Frame>
  449. --
  450. -- MyAddOn.lua
  451. -- function ExamplePanel_OnLoad (panel)
  452. -- panel.name = "My AddOn"
  453. -- InterfaceOptions_AddCategory(panel);
  454. -- end
  455. --
  456. -- EXAMPLE -- Dynamically create a frame and use it as a subcategory for "My AddOn".
  457. --
  458. -- local panel = CreateFrame("FRAME", "ExampleSubCategory");
  459. -- panel.name = "My SubCategory";
  460. -- panel.parent = "My AddOn";
  461. --
  462. -- InterfaceOptions_AddCategory(panel);
  463. --
  464. -- EXAMPLE -- Create a frame with a control, an okay and a cancel method
  465. --
  466. -- --[[ Create a frame to use as the panel ]] --
  467. -- local panel = CreateFrame("FRAME", "ExamplePanel");
  468. -- panel.name = "My AddOn";
  469. --
  470. -- -- [[ When the player clicks okay, set the original value to the current setting ]] --
  471. -- panel.okay =
  472. -- function (self)
  473. -- self.originalValue = MY_VARIABLE;
  474. -- end
  475. --
  476. -- -- [[ When the player clicks cancel, set the current setting to the original value ]] --
  477. -- panel.cancel =
  478. -- function (self)
  479. -- MY_VARIABLE = self.originalValue;
  480. -- end
  481. --
  482. -- -- [[ Add the panel to the Interface Options ]] --
  483. -- InterfaceOptions_AddCategory(panel);
  484. -------------------------------------------------------------------------------------------------
  485. local function AddAddOnCategory(categories, index, frame)
  486. if index then
  487. tinsert(categories, index, frame);
  488. else
  489. tinsert(categories, frame);
  490. end
  491. InterfaceCategoryList_Update();
  492. end
  493. function InterfaceOptions_AddCategory (frame, addOn, position)
  494. if ( issecure() and ( not addOn ) ) then
  495. local parent = frame.parent;
  496. if ( parent ) then
  497. for i = 1, #blizzardCategories do
  498. if ( blizzardCategories[i].name == parent ) then
  499. if ( blizzardCategories[i].hasChildren ) then
  500. frame.hidden = ( blizzardCategories[i].collapsed );
  501. else
  502. frame.hidden = true;
  503. blizzardCategories[i].hasChildren = true;
  504. blizzardCategories[i].collapsed = true;
  505. end
  506. tinsert(blizzardCategories, i + 1, frame);
  507. InterfaceCategoryList_Update();
  508. return;
  509. end
  510. end
  511. end
  512. if ( position ) then
  513. tinsert(blizzardCategories, position, frame);
  514. else
  515. tinsert(blizzardCategories, frame);
  516. end
  517. InterfaceCategoryList_Update();
  518. elseif ( not type(frame) == "table" or not frame.name ) then
  519. --Check to make sure that AddOn interface panels have the necessary attributes to work with the system.
  520. return;
  521. else
  522. frame.okay = frame.okay or function () end;
  523. frame.cancel = frame.cancel or function () end;
  524. frame.default = frame.default or function () end;
  525. frame.refresh = frame.refresh or function () end;
  526. local categories = INTERFACEOPTIONS_ADDONCATEGORIES;
  527. local name = strlower(frame.name);
  528. local parent = frame.parent;
  529. if ( parent ) then
  530. for i = 1, #categories do
  531. if ( categories[i].name == parent ) then
  532. if ( not categories[i].hasChildren ) then
  533. frame.hidden = true;
  534. categories[i].hasChildren = true;
  535. categories[i].collapsed = true;
  536. AddAddOnCategory(categories, i + 1, frame);
  537. return;
  538. end
  539. frame.hidden = ( categories[i].collapsed );
  540. local j = i + 1;
  541. while ( categories[j] and categories[j].parent == parent ) do
  542. -- Skip to the end of the list of children, add this there.
  543. j = j + 1;
  544. end
  545. AddAddOnCategory(categories, j, frame);
  546. return;
  547. end
  548. end
  549. end
  550. for i = 1, #categories do
  551. if ( ( not categories[i].parent ) and ( name < strlower(categories[i].name) ) ) then
  552. AddAddOnCategory(categories, i, frame);
  553. return;
  554. end
  555. end
  556. AddAddOnCategory(categories, position, frame);
  557. end
  558. end