Blizzard_UIWidgets/Blizzard_UIWidgetManager.lua

Blizzard_UIWidgets/Blizzard_UIWidgetManager.lua (9.1.0.39617; unchanged since 9.1.0.39229)
  1. local TIMER_UPDATE_FREQUENCY_SECONDS = 1;
  2. local WIDGET_DEBUG_TEXTURE_SHOW = false;
  3. local WIDGET_DEBUG_TEXTURE_COLOR = CreateColor(0.1, 1.0, 0.1, 0.6);
  4. local WIDGET_CONTAINER_DEBUG_TEXTURE_SHOW = false;
  5. local WIDGET_CONTAINER_DEBUG_TEXTURE_COLOR = CreateColor(1.0, 0.1, 0.1, 0.6);
  6. local WIDGET_DEBUG_CUSTOM_TEXTURE_COLOR = CreateColor(1.0, 1.0, 0.0, 0.6);
  7. UIWidgetHorizontalWidgetContainerMixin = {};
  8. function UIWidgetHorizontalWidgetContainerMixin:OnLoad()
  9. self.parentWidgetContainer = self:GetParent();
  10. self.childWidgets = {};
  11. end
  12. function UIWidgetHorizontalWidgetContainerMixin:ResetChildWidgets()
  13. for _, widgetFrame in ipairs(self.childWidgets) do
  14. widgetFrame:SetParent(self.parentWidgetContainer);
  15. end
  16. self.childWidgets = {};
  17. end
  18. function UIWidgetHorizontalWidgetContainerMixin:AddChildWidget(widgetFrame)
  19. table.insert(self.childWidgets, widgetFrame);
  20. widgetFrame:SetParent(self);
  21. end
  22. UIWidgetContainerMixin = {};
  23. local function ResetHorizontalWidgetContainer(framePool, frame)
  24. frame:ResetChildWidgets();
  25. FramePool_HideAndClearAnchors(framePool, frame);
  26. end
  27. function UIWidgetContainerMixin:OnLoad()
  28. self.widgetPools = CreateFramePoolCollection();
  29. self.horizontalRowContainerPool = CreateFramePool("FRAME", self, "UIWidgetHorizontalWidgetContainerTemplate", ResetHorizontalWidgetContainer);
  30. if WIDGET_CONTAINER_DEBUG_TEXTURE_SHOW then
  31. self._debugBGTex = self:CreateTexture()
  32. self._debugBGTex:SetColorTexture(WIDGET_CONTAINER_DEBUG_TEXTURE_COLOR:GetRGBA());
  33. self._debugBGTex:SetAllPoints(self);
  34. end
  35. end
  36. function UIWidgetContainerMixin:OnEvent(event, ...)
  37. if event == "UPDATE_ALL_UI_WIDGETS" then
  38. self:ProcessAllWidgets();
  39. elseif event == "UPDATE_UI_WIDGET" then
  40. local widgetInfo = ...;
  41. if (widgetInfo.widgetSetID == self.widgetSetID) and (not widgetInfo.unit or (widgetInfo.unit == self.attachedToUnit)) then
  42. self:ProcessWidget(widgetInfo.widgetID, widgetInfo.widgetType);
  43. end
  44. end
  45. end
  46. function UIWidgetContainerMixin:OnUpdate(elapsed)
  47. -- Handle layout updates
  48. if self.dirtyLayout then
  49. self:UpdateWidgetLayout();
  50. end
  51. end
  52. function DefaultWidgetLayout(widgetContainerFrame, sortedWidgets)
  53. local horizontalRowContainer = nil;
  54. widgetContainerFrame.horizontalRowContainerPool:ReleaseAll();
  55. local widgetContainerFrameLevel = widgetContainerFrame:GetFrameLevel();
  56. local horizontalRowAnchorPoint = widgetContainerFrame.horizontalRowAnchorPoint or widgetContainerFrame.verticalAnchorPoint;
  57. local horizontalRowRelativePoint = widgetContainerFrame.horizontalRowRelativePoint or widgetContainerFrame.verticalRelativePoint;
  58. for index, widgetFrame in ipairs(sortedWidgets) do
  59. widgetFrame:ClearAllPoints();
  60. local widgetSetUsesVertical = widgetContainerFrame.widgetSetLayoutDirection == Enum.UIWidgetSetLayoutDirection.Vertical;
  61. local widgetUsesVertical = widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.Vertical;
  62. local useOverlapLayout = widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.Overlap;
  63. local useVerticalLayout = widgetUsesVertical or (widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.Default and widgetSetUsesVertical);
  64. if useOverlapLayout then
  65. -- This widget uses overlap layout
  66. if index == 1 then
  67. -- But this is the first widget in the set, so just anchor it to the widget container
  68. if widgetSetUsesVertical then
  69. widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, widgetContainerFrame);
  70. else
  71. widgetFrame:SetPoint(widgetContainerFrame.horizontalAnchorPoint, widgetContainerFrame);
  72. end
  73. else
  74. -- This is not the first widget in the set, so anchor it so it overlaps the previous widget
  75. local relative = sortedWidgets[index - 1];
  76. if widgetSetUsesVertical then
  77. -- Overlap it vertically
  78. widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, relative, widgetContainerFrame.verticalAnchorPoint, 0, 0);
  79. else
  80. -- Overlap it horizontally
  81. widgetFrame:SetPoint(widgetContainerFrame.horizontalAnchorPoint, relative, widgetContainerFrame.horizontalAnchorPoint, 0, 0);
  82. end
  83. end
  84. widgetFrame:SetParent(widgetContainerFrame);
  85. widgetFrame:SetFrameLevel(widgetContainerFrameLevel + index);
  86. elseif useVerticalLayout then
  87. -- This widget uses vertical layout
  88. if index == 1 then
  89. -- This is the first widget in the set, so just anchor it to the widget container
  90. widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, widgetContainerFrame);
  91. else
  92. -- This is not the first widget in the set, so anchor it to the previous widget (or the horizontalRowContainer if that exists)
  93. local relative = horizontalRowContainer or sortedWidgets[index - 1];
  94. widgetFrame:SetPoint(widgetContainerFrame.verticalAnchorPoint, relative, widgetContainerFrame.verticalRelativePoint, 0, widgetContainerFrame.verticalAnchorYOffset);
  95. if horizontalRowContainer then
  96. -- This widget is vertical, so horizontalRowContainer is done. Call layout on it and clear horizontalRowContainer
  97. horizontalRowContainer:Layout();
  98. horizontalRowContainer = nil;
  99. end
  100. end
  101. widgetFrame:SetParent(widgetContainerFrame);
  102. widgetFrame:SetFrameLevel(widgetContainerFrameLevel + index);
  103. else
  104. -- This widget uses horizontal layout
  105. local forceNewRow = widgetFrame.layoutDirection == Enum.UIWidgetLayoutDirection.HorizontalForceNewRow;
  106. local needNewRowContainer = not horizontalRowContainer or forceNewRow;
  107. if needNewRowContainer then
  108. -- We either don't have a horizontalRowContainer or this widget has requested a new row be started
  109. if horizontalRowContainer then
  110. horizontalRowContainer:Layout();
  111. end
  112. local newHorizontalRowContainer = widgetContainerFrame.horizontalRowContainerPool:Acquire();
  113. newHorizontalRowContainer:Show();
  114. if index == 1 then
  115. -- This is the first widget in the set, so just anchor it to the widget container
  116. newHorizontalRowContainer:SetPoint(widgetContainerFrame.verticalAnchorPoint, widgetContainerFrame, widgetContainerFrame.verticalAnchorPoint);
  117. else
  118. -- This is not the first widget in the set, so anchor it to the previous widget (or the horizontalRowContainer if that exists)
  119. local relative = horizontalRowContainer or sortedWidgets[index - 1];
  120. newHorizontalRowContainer:SetPoint(horizontalRowAnchorPoint, relative, horizontalRowRelativePoint, 0, widgetContainerFrame.verticalAnchorYOffset);
  121. end
  122. widgetFrame:SetPoint("TOPLEFT", newHorizontalRowContainer);
  123. newHorizontalRowContainer:AddChildWidget(widgetFrame);
  124. widgetFrame:SetFrameLevel(widgetContainerFrameLevel + index);
  125. -- The old horizontalRowContainer is no longer needed for anchoring, so set it to newHorizontalRowContainer
  126. horizontalRowContainer = newHorizontalRowContainer;
  127. else
  128. -- horizontalRowContainer already existed, so we just keep going in it, anchoring to the previous widget
  129. local relative = sortedWidgets[index - 1];
  130. horizontalRowContainer:AddChildWidget(widgetFrame);
  131. widgetFrame:SetFrameLevel(widgetContainerFrameLevel + index);
  132. widgetFrame:SetPoint(widgetContainerFrame.horizontalAnchorPoint, relative, widgetContainerFrame.horizontalRelativePoint, widgetContainerFrame.horizontalAnchorXOffset, 0);
  133. end
  134. end
  135. end
  136. if horizontalRowContainer then
  137. horizontalRowContainer:Layout();
  138. end
  139. widgetContainerFrame:Layout();
  140. end
  141. -- widgetLayoutFunction should take 2 arguments (this widget container and a sequence containing all widgetFrames belonging to that widgetSet, sorted by orderIndex). It can update the layout of the widgets & widgetContainer as it sees fit.
  142. -- IMPORTANT: widgetLayoutFunction is called every time any widget in this container is shown, hidden or re-ordered. If nil is passed DefaultWidgetLayout is used
  143. -- widgetInitFunction should take 1 argument (the widgetFrame). It should do anything needed for initialization of widgets by the registering system. It is called only once, when a widget is initialized (when entering a new map/area/subarea/phase)
  144. -- Either can be nil if your system doesn't need that functionaility
  145. --
  146. -- Calling RegisterForWidgetSet on a container that is already registered to a different WidgetSet will cause the old WidgetSet to get unregistered and the new one to take its place
  147. -- Calling RegisterForWidgetSet with a nil widgetSetID is the same as just calling UnregisterForWidgetSet
  148. function UIWidgetContainerMixin:RegisterForWidgetSet(widgetSetID, widgetLayoutFunction, widgetInitFunction, attachedToUnit)
  149. if self.widgetSetID then
  150. -- We are already registered to a WidgetSet
  151. if self.widgetSetID == widgetSetID then
  152. -- And it's the same WidgetSet we are trying to register again...nothing to do
  153. return;
  154. else
  155. -- We are already registered for a different WidgetSet...unregister it
  156. self:UnregisterForWidgetSet();
  157. end
  158. end
  159. if not widgetSetID then
  160. return;
  161. end
  162. self.widgetSetID = widgetSetID;
  163. self.layoutFunc = widgetLayoutFunction or DefaultWidgetLayout;
  164. self.initFunc = widgetInitFunction;
  165. self.attachedToUnit = attachedToUnit;
  166. self.widgetFrames = {};
  167. self.timerWidgets = {};
  168. self.numTimers = 0;
  169. self.numWidgetsShowing = 0;
  170. local widgetSetInfo = C_UIWidgetManager.GetWidgetSetInfo(widgetSetID);
  171. self.widgetSetLayoutDirection = widgetSetInfo.layoutDirection;
  172. self.verticalAnchorYOffset = -widgetSetInfo.verticalPadding;
  173. if self.attachedToUnit then
  174. C_UIWidgetManager.RegisterUnitForWidgetUpdates(self.attachedToUnit);
  175. end
  176. self:ProcessAllWidgets();
  177. if self.showAndHideOnWidgetSetRegistration then
  178. self:Show();
  179. end
  180. self:RegisterEvent("UPDATE_ALL_UI_WIDGETS");
  181. self:RegisterEvent("UPDATE_UI_WIDGET");
  182. UIWidgetManager:OnWidgetContainerRegistered(self);
  183. end
  184. function UIWidgetContainerMixin:UnregisterForWidgetSet()
  185. if not self.widgetSetID then
  186. -- We are not registered to a WidgetSet...nothing to do
  187. return;
  188. end
  189. -- Remove all widgets from this widget container
  190. self:RemoveAllWidgets();
  191. self:UpdateWidgetLayout();
  192. -- And clear everything else
  193. self.widgetSetID = nil;
  194. self.layoutFunc = nil;
  195. self.initFunc = nil;
  196. self.dirtyLayout = nil;
  197. if self.showAndHideOnWidgetSetRegistration then
  198. self:Hide();
  199. end
  200. if self.attachedToUnit then
  201. if UIWidgetManager.processingUnit == self.attachedToUnit then
  202. UIWidgetManager.processingUnit = nil;
  203. end
  204. C_UIWidgetManager.UnregisterUnitForWidgetUpdates(self.attachedToUnit);
  205. self.attachedToUnit = nil;
  206. end
  207. self:UnregisterEvent("UPDATE_ALL_UI_WIDGETS");
  208. self:UnregisterEvent("UPDATE_UI_WIDGET");
  209. UIWidgetManager:OnWidgetContainerUnregistered(self);
  210. end
  211. function UIWidgetContainerMixin:RegisterTimerWidget(widgetID, widgetFrame)
  212. if not self.timerWidgets[widgetID] then
  213. -- New timer added
  214. self.timerWidgets[widgetID] = widgetFrame;
  215. if not self.ticker then
  216. self.ticker = C_Timer.NewTicker(TIMER_UPDATE_FREQUENCY_SECONDS,
  217. function()
  218. for id, widget in pairs(self.timerWidgets) do
  219. self:ProcessWidget(id, widget.widgetType);
  220. end
  221. end);
  222. end
  223. self.numTimers = self.numTimers + 1;
  224. end
  225. end
  226. function UIWidgetContainerMixin:UnregisterTimerWidget(widgetID)
  227. if self.timerWidgets[widgetID] then
  228. -- Existing timer removed
  229. self.timerWidgets[widgetID] = nil;
  230. self.numTimers = self.numTimers - 1;
  231. if self.numTimers == 0 and self.ticker then
  232. self.ticker:Cancel();
  233. self.ticker = nil;
  234. end
  235. end
  236. end
  237. function UIWidgetContainerMixin:GatherWidgetsByWidgetTag(widgetArray, widgetTag)
  238. for _, widgetFrame in pairs(self.widgetFrames) do
  239. if widgetTag == widgetFrame.widgetTag then
  240. table.insert(widgetArray, widgetFrame);
  241. end
  242. end
  243. end
  244. -- Mark all currently shown widgets to be removed
  245. function UIWidgetContainerMixin:MarkAllWidgetsForRemoval()
  246. for _, widgetFrame in pairs(self.widgetFrames) do
  247. widgetFrame.markedForRemove = true;
  248. end
  249. end
  250. -- Go through all widgets in this container and call AnimOut on any that are marked for removal. This will cause them to animate out and RemoveWidget will be called once that is done.
  251. function UIWidgetContainerMixin:AnimateOutAllMarkedWidgets()
  252. for _, widgetFrame in pairs(self.widgetFrames) do
  253. if widgetFrame.markedForRemove then
  254. widgetFrame:AnimOut();
  255. end
  256. end
  257. end
  258. -- Removes all widgets from this container immediately (don't animate them out)
  259. function UIWidgetContainerMixin:RemoveAllWidgets()
  260. self.widgetFrames = {};
  261. self.timerWidgets = {};
  262. self.numTimers = 0;
  263. self.numWidgetsShowing = 0;
  264. if self.ticker then
  265. self.ticker:Cancel();
  266. self.ticker = nil;
  267. end
  268. self.widgetPools:ReleaseAll();
  269. end
  270. -- This is called AFTER the widget is done animating out. The widgetFrame is actually released back to the pool and hidden.
  271. function UIWidgetContainerMixin:RemoveWidget(widgetID)
  272. local widgetFrame = self.widgetFrames[widgetID];
  273. if not widgetFrame then
  274. -- This widget was never created. Nothing to do
  275. return;
  276. end
  277. -- If this is a widget with a timer, remove it from the timer list
  278. if widgetFrame.hasTimer then
  279. self:UnregisterTimerWidget(widgetID);
  280. end
  281. self.widgetPools:Release(widgetFrame);
  282. self.widgetFrames[widgetID] = nil;
  283. -- The layout is dirty
  284. self.dirtyLayout = true;
  285. end
  286. local function ResetWidget(pool, widgetFrame)
  287. widgetFrame:OnReset();
  288. end
  289. function UIWidgetContainerMixin:GetWidgetFromPools(templateInfo)
  290. if templateInfo then
  291. self.widgetPools:CreatePoolIfNeeded(templateInfo.frameType, self, templateInfo.frameTemplate, ResetWidget);
  292. local widgetFrame = self.widgetPools:Acquire(templateInfo.frameTemplate);
  293. widgetFrame:SetParent(self);
  294. return widgetFrame;
  295. end
  296. end
  297. function UIWidgetContainerMixin:CreateWidget(widgetID, widgetType, widgetTypeInfo, widgetInfo)
  298. local widgetFrame = self:GetWidgetFromPools(widgetTypeInfo.templateInfo);
  299. widgetFrame.widgetID = widgetID;
  300. widgetFrame.widgetSetID = self.widgetSetID;
  301. widgetFrame.widgetType = widgetType;
  302. widgetFrame.hasTimer = widgetInfo.hasTimer;
  303. widgetFrame.orderIndex = widgetInfo.orderIndex;
  304. widgetFrame.widgetTag = widgetInfo.widgetTag;
  305. widgetFrame.inAnimType = widgetInfo.inAnimType;
  306. widgetFrame.outAnimType = widgetInfo.outAnimType;
  307. widgetFrame.layoutDirection = widgetInfo.layoutDirection;
  308. widgetFrame.modelSceneLayer = widgetInfo.modelSceneLayer;
  309. widgetFrame.scriptedAnimationEffectID = widgetInfo.scriptedAnimationEffectID;
  310. widgetFrame.markedForRemove = nil;
  311. -- If this is a widget with a timer, add it from the timer list
  312. if widgetFrame.hasTimer then
  313. self:RegisterTimerWidget(widgetID, widgetFrame);
  314. end
  315. -- If there is an init function, run it
  316. if self.initFunc then
  317. self.initFunc(widgetFrame);
  318. end
  319. self.widgetFrames[widgetID] = widgetFrame;
  320. return widgetFrame;
  321. end
  322. function UIWidgetContainerMixin:ProcessWidget(widgetID, widgetType)
  323. local widgetTypeInfo = UIWidgetManager:GetWidgetTypeInfo(widgetType);
  324. if not widgetTypeInfo then
  325. -- This WidgetType is not supported (nothing called RegisterWidgetVisTypeTemplate for it)
  326. return;
  327. end
  328. if UIWidgetManager.processingUnit ~= self.attachedToUnit then
  329. C_UIWidgetManager.SetProcessingUnit(self.attachedToUnit);
  330. UIWidgetManager.processingUnit = self.attachedToUnit;
  331. end
  332. local widgetInfo = widgetTypeInfo.visInfoDataFunction(widgetID);
  333. local widgetFrame = self.widgetFrames[widgetID];
  334. local widgetAlreadyExisted = (widgetFrame ~= nil);
  335. local oldOrderIndex;
  336. local oldLayoutDirection;
  337. local isNewWidget = false;
  338. if widgetAlreadyExisted then
  339. -- Widget already existed
  340. if not widgetInfo then
  341. -- widgetInfo is nil, indicating it should no longer be shown...animate it out (RemoveWidget will be called once that is done)
  342. widgetFrame:AnimOut();
  343. widgetFrame.markedForRemove = nil;
  344. return;
  345. end
  346. -- Otherwise the widget should still show...save the current orderIndex and layoutDirection so we can determine if they change after Setup is run
  347. oldOrderIndex = widgetFrame.orderIndex;
  348. oldLayoutDirection = widgetFrame.layoutDirection;
  349. -- Remove markedForRemove because it is still showing
  350. widgetFrame.markedForRemove = nil;
  351. else
  352. -- Widget did not already exist
  353. if widgetInfo then
  354. -- And it should be shown...create it
  355. widgetFrame = self:CreateWidget(widgetID, widgetType, widgetTypeInfo, widgetInfo);
  356. isNewWidget = true;
  357. else
  358. -- Widget should not be shown. It didn't already exist so there is nothing to do
  359. return;
  360. end
  361. end
  362. -- Ok we are now SURE that this widget should be shown and we have a frame for it
  363. -- Run the Setup function on the widget (could change the orderIndex and/or layoutDirection)
  364. widgetFrame:Setup(widgetInfo, self);
  365. if(isNewWidget) then
  366. --Only Apply the effects when the widget is first added.
  367. widgetFrame:ApplyEffects(widgetInfo);
  368. end
  369. if WIDGET_DEBUG_TEXTURE_SHOW then
  370. if not widgetFrame._debugBGTex then
  371. widgetFrame._debugBGTex = widgetFrame:CreateTexture()
  372. widgetFrame._debugBGTex:SetColorTexture(WIDGET_DEBUG_TEXTURE_COLOR:GetRGBA());
  373. widgetFrame._debugBGTex:SetAllPoints(widgetFrame);
  374. end
  375. if widgetFrame.CustomDebugSetup then
  376. widgetFrame:CustomDebugSetup(WIDGET_DEBUG_CUSTOM_TEXTURE_COLOR);
  377. end
  378. end
  379. if isNewWidget and widgetFrame.OnAcquired then
  380. widgetFrame:OnAcquired(widgetInfo)
  381. end
  382. -- Determine if we need to run layout again
  383. local needsLayout = (oldOrderIndex ~= widgetFrame.orderIndex) or (oldLayoutDirection ~= widgetFrame.layoutDirection);
  384. if needsLayout then
  385. -- Either this is a new widget or either orderIndex or layoutDirection changed. In either case layout needs to be run
  386. self.dirtyLayout = true;
  387. end
  388. end
  389. function UIWidgetContainerMixin:ProcessAllWidgets()
  390. -- First mark all widgets for removal
  391. self:MarkAllWidgetsForRemoval();
  392. -- Add any new widgets and unmark any existing widgets that are still shown
  393. local setWidgets = C_UIWidgetManager.GetAllWidgetsBySetID(self.widgetSetID);
  394. for _, widgetInfo in ipairs(setWidgets) do
  395. self:ProcessWidget(widgetInfo.widgetID, widgetInfo.widgetType);
  396. end
  397. -- Animate out any widgets that are still marked for removal
  398. self:AnimateOutAllMarkedWidgets();
  399. -- Force call UpdateWidgetLayout because some containers rely on it being called right away
  400. self:UpdateWidgetLayout();
  401. end
  402. local function SortWidgets(a, b)
  403. if a.orderIndex == b.orderIndex then
  404. return a.widgetID < b.widgetID;
  405. else
  406. return a.orderIndex < b.orderIndex;
  407. end
  408. end
  409. function UIWidgetContainerMixin:GetNumWidgetsShowing()
  410. return self.numWidgetsShowing or 0;
  411. end
  412. function UIWidgetContainerMixin:HasAnyWidgetsShowing()
  413. return (self:GetNumWidgetsShowing() > 0);
  414. end
  415. function UIWidgetContainerMixin:UpdateWidgetLayout()
  416. local sortedWidgets = {};
  417. for _, widget in pairs(self.widgetFrames) do
  418. table.insert(sortedWidgets, widget);
  419. end
  420. table.sort(sortedWidgets, SortWidgets);
  421. self.numWidgetsShowing = #sortedWidgets;
  422. self:layoutFunc(sortedWidgets);
  423. self.dirtyLayout = false;
  424. end
  425. UIWidgetManagerMixin = {};
  426. function UIWidgetManagerMixin:OnLoad()
  427. self.widgetVisTypeInfo = {};
  428. self.registeredWidgetContainers = {};
  429. end
  430. function UIWidgetManagerMixin:OnWidgetContainerRegistered(widgetContainer)
  431. self.registeredWidgetContainers[widgetContainer] = true;
  432. end
  433. function UIWidgetManagerMixin:OnWidgetContainerUnregistered(widgetContainer)
  434. self.registeredWidgetContainers[widgetContainer] = nil;
  435. end
  436. function UIWidgetManagerMixin:GetWidgetTypeInfo(widgetType)
  437. return self.widgetVisTypeInfo[widgetType];
  438. end
  439. -- templateInfo should be a table that contains 2 entries (frameType and frameTemplate)
  440. -- visInfoDataFunction should be a function that gets the widget visInfo object. It should return this visInfo object. If something in the data indicates the widget should not show it should return nil.
  441. function UIWidgetManagerMixin:RegisterWidgetVisTypeTemplate(visType, templateInfo, visInfoDataFunction)
  442. if not visType or not templateInfo or not templateInfo.frameType or not templateInfo.frameTemplate or not visInfoDataFunction then
  443. -- All these things are required
  444. return;
  445. end
  446. if self.widgetVisTypeInfo[visType] then
  447. -- Someone already registered for this visType, so do nothing
  448. return;
  449. end
  450. self.widgetVisTypeInfo[visType] = { templateInfo = templateInfo, visInfoDataFunction = visInfoDataFunction };
  451. end
  452. -- This function will return an enumerator for all currently-visible widgets that are flagged with the passed widgetTag.
  453. -- Example use:
  454. -- for index, widgetFrame in UIWidgetManager:EnumerateWidgetsByWidgetTag("myTag") do
  455. -- -- YOUR CODE
  456. -- end
  457. function UIWidgetManagerMixin:EnumerateWidgetsByWidgetTag(widgetTag)
  458. local widgetFrames = {};
  459. for widgetContainer in pairs(self.registeredWidgetContainers) do
  460. widgetContainer:GatherWidgetsByWidgetTag(widgetFrames, widgetTag);
  461. end
  462. return pairs(widgetFrames);
  463. end