Blizzard_MapCanvas/Blizzard_MapCanvas.lua

Blizzard_MapCanvas/Blizzard_MapCanvas.lua (8.3.7.35662; unchanged since 8.3.0.33062)
  1. MapCanvasMixin = CreateFromMixins(CallbackRegistryBaseMixin);
  2. function MapCanvasMixin:OnLoad()
  3. CallbackRegistryBaseMixin.OnLoad(self);
  4. self.detailLayerPool = CreateFramePool("FRAME", self:GetCanvas(), "MapCanvasDetailLayerTemplate");
  5. self.dataProviders = {};
  6. self.dataProviderEventsCount = {};
  7. self.pinPools = {};
  8. self.pinTemplateTypes = {};
  9. self.activeAreaTriggers = {};
  10. self.lockReasons = {};
  11. self.pinsToNudge = {};
  12. self.pinFrameLevelsManager = CreateFromMixins(MapCanvasPinFrameLevelsManagerMixin);
  13. self.pinFrameLevelsManager:Initialize();
  14. self.mouseClickHandlers = {};
  15. self:EvaluateLockReasons();
  16. self.debugAreaTriggers = false;
  17. end
  18. function MapCanvasMixin:OnUpdate()
  19. self:UpdatePinNudging();
  20. end
  21. function MapCanvasMixin:SetMapID(mapID)
  22. local mapArtID = C_Map.GetMapArtID(mapID) -- phased map art may be different for the same mapID
  23. if self.mapID ~= mapID or self.mapArtID ~= mapArtID then
  24. self.areDetailLayersDirty = true;
  25. self.mapID = mapID;
  26. self.mapArtID = mapArtID;
  27. self.expandedMapInsetsByMapID = {};
  28. self.ScrollContainer:SetMapID(mapID);
  29. if self:IsShown() then
  30. self:RefreshDetailLayers();
  31. end
  32. self:OnMapChanged();
  33. end
  34. end
  35. function MapCanvasMixin:OnFrameSizeChanged()
  36. self.ScrollContainer:OnCanvasSizeChanged();
  37. end
  38. function MapCanvasMixin:GetMapID()
  39. -- normally the mapID is set in OnShow, however if the player has never opened the quest log or the map, and then
  40. -- hides the UI, and while the UI is hidden opens the quest log, mapID will be nil and we get a lua error.
  41. -- under these very rare circumstances, dig out the diplayable mapID.
  42. return self.mapID or MapUtil.GetDisplayableMapForPlayer();
  43. end
  44. function MapCanvasMixin:SetMapInsetPool(mapInsetPool)
  45. self.mapInsetPool = mapInsetPool;
  46. end
  47. function MapCanvasMixin:GetMapInsetPool()
  48. return self.mapInsetPool;
  49. end
  50. function MapCanvasMixin:OnShow()
  51. local FROM_ON_SHOW = true;
  52. self:RefreshAll(FROM_ON_SHOW);
  53. for dataProvider in pairs(self.dataProviders) do
  54. dataProvider:OnShow();
  55. end
  56. end
  57. function MapCanvasMixin:OnHide()
  58. for dataProvider in pairs(self.dataProviders) do
  59. dataProvider:OnHide();
  60. end
  61. end
  62. function MapCanvasMixin:OnEvent(event, ...)
  63. -- Data provider event
  64. for dataProvider in pairs(self.dataProviders) do
  65. dataProvider:SignalEvent(event, ...);
  66. end
  67. end
  68. function MapCanvasMixin:AddDataProvider(dataProvider)
  69. self.dataProviders[dataProvider] = true;
  70. dataProvider:OnAdded(self);
  71. end
  72. function MapCanvasMixin:RemoveDataProvider(dataProvider)
  73. dataProvider:RemoveAllData();
  74. self.dataProviders[dataProvider] = nil;
  75. dataProvider:OnRemoved(self);
  76. end
  77. function MapCanvasMixin:AddDataProviderEvent(event)
  78. self.dataProviderEventsCount[event] = (self.dataProviderEventsCount[event] or 0) + 1;
  79. self:RegisterEvent(event);
  80. end
  81. function MapCanvasMixin:RemoveDataProviderEvent(event)
  82. if self.dataProviderEventsCount[event] then
  83. self.dataProviderEventsCount[event] = self.dataProviderEventsCount[event] - 1;
  84. if self.dataProviderEventsCount[event] == 0 then
  85. self.dataProviderEventsCount[event] = nil;
  86. self:UnregisterEvent(event);
  87. end
  88. end
  89. end
  90. function MapCanvasMixin:SetPinNudgingDirty(dirty)
  91. self.pinNudgingDirty = dirty;
  92. end
  93. do
  94. local function OnPinReleased(pinPool, pin)
  95. FramePool_HideAndClearAnchors(pinPool, pin);
  96. pin:OnReleased();
  97. pin.pinTemplate = nil;
  98. pin.owningMap = nil;
  99. end
  100. local function OnPinMouseUp(pin, button, upInside)
  101. pin:OnMouseUp(button);
  102. if upInside then
  103. pin:OnClick(button);
  104. end
  105. end
  106. function MapCanvasMixin:AcquirePin(pinTemplate, ...)
  107. if not self.pinPools[pinTemplate] then
  108. local pinTemplateType = self.pinTemplateTypes[pinTemplate] or "FRAME";
  109. self.pinPools[pinTemplate] = CreateFramePool(pinTemplateType, self:GetCanvas(), pinTemplate, OnPinReleased);
  110. end
  111. local pin, newPin = self.pinPools[pinTemplate]:Acquire();
  112. if newPin then
  113. local isMouseClickEnabled = pin:IsMouseClickEnabled();
  114. local isMouseMotionEnabled = pin:IsMouseMotionEnabled();
  115. if isMouseClickEnabled then
  116. pin:SetScript("OnMouseUp", OnPinMouseUp);
  117. pin:SetScript("OnMouseDown", pin.OnMouseDown);
  118. end
  119. if isMouseMotionEnabled then
  120. if newPin then
  121. -- These will never be called, just define a OnMouseEnter and OnMouseLeave on the pin mixin and it'll be called when appropriate
  122. assert(pin:GetScript("OnEnter") == nil);
  123. assert(pin:GetScript("OnLeave") == nil);
  124. end
  125. pin:SetScript("OnEnter", pin.OnMouseEnter);
  126. pin:SetScript("OnLeave", pin.OnMouseLeave);
  127. end
  128. pin:SetMouseClickEnabled(isMouseClickEnabled);
  129. pin:SetMouseMotionEnabled(isMouseMotionEnabled);
  130. end
  131. pin.pinTemplate = pinTemplate;
  132. pin.owningMap = self;
  133. if newPin then
  134. pin:OnLoad();
  135. end
  136. self.ScrollContainer:MarkCanvasDirty();
  137. pin:Show();
  138. pin:OnAcquired(...);
  139. return pin;
  140. end
  141. end
  142. function MapCanvasMixin:SetPinTemplateType(pinTemplate, pinTemplateType)
  143. self.pinTemplateTypes[pinTemplate] = pinTemplateType;
  144. end
  145. function MapCanvasMixin:RemoveAllPinsByTemplate(pinTemplate)
  146. if self.pinPools[pinTemplate] then
  147. self.pinPools[pinTemplate]:ReleaseAll();
  148. self.ScrollContainer:MarkCanvasDirty();
  149. end
  150. end
  151. function MapCanvasMixin:RemovePin(pin)
  152. if pin:GetNudgeSourceRadius() > 0 then
  153. self.pinNudgingDirty = true;
  154. end
  155. self.pinPools[pin.pinTemplate]:Release(pin);
  156. self.ScrollContainer:MarkCanvasDirty();
  157. end
  158. function MapCanvasMixin:EnumeratePinsByTemplate(pinTemplate)
  159. if self.pinPools[pinTemplate] then
  160. return self.pinPools[pinTemplate]:EnumerateActive();
  161. end
  162. return nop;
  163. end
  164. function MapCanvasMixin:GetNumActivePinsByTemplate(pinTemplate)
  165. if self.pinPools[pinTemplate] then
  166. return self.pinPools[pinTemplate]:GetNumActive();
  167. end
  168. return 0;
  169. end
  170. function MapCanvasMixin:EnumerateAllPins()
  171. local currentPoolKey, currentPool = next(self.pinPools, nil);
  172. local currentPin = nil;
  173. return function()
  174. if currentPool then
  175. currentPin = currentPool:GetNextActive(currentPin);
  176. while not currentPin do
  177. currentPoolKey, currentPool = next(self.pinPools, currentPoolKey);
  178. if currentPool then
  179. currentPin = currentPool:GetNextActive();
  180. else
  181. break;
  182. end
  183. end
  184. end
  185. return currentPin;
  186. end, nil;
  187. end
  188. function MapCanvasMixin:AcquireAreaTrigger(namespace)
  189. if not self.activeAreaTriggers[namespace] then
  190. self.activeAreaTriggers[namespace] = {};
  191. end
  192. local areaTrigger = CreateRectangle();
  193. areaTrigger.enclosed = false;
  194. areaTrigger.intersects = false;
  195. areaTrigger.intersectCallback = nil;
  196. areaTrigger.enclosedCallback = nil;
  197. areaTrigger.triggerPredicate = nil;
  198. self.activeAreaTriggers[namespace][areaTrigger] = true;
  199. self.ScrollContainer:MarkAreaTriggersDirty();
  200. return areaTrigger;
  201. end
  202. function MapCanvasMixin:SetAreaTriggerEnclosedCallback(areaTrigger, enclosedCallback)
  203. areaTrigger.enclosedCallback = enclosedCallback;
  204. self.ScrollContainer:MarkAreaTriggersDirty();
  205. end
  206. function MapCanvasMixin:SetAreaTriggerIntersectsCallback(areaTrigger, intersectCallback)
  207. areaTrigger.intersectCallback = intersectCallback;
  208. self.ScrollContainer:MarkAreaTriggersDirty();
  209. end
  210. function MapCanvasMixin:SetAreaTriggerPredicate(areaTrigger, triggerPredicate)
  211. areaTrigger.triggerPredicate = triggerPredicate;
  212. self.ScrollContainer:MarkAreaTriggersDirty();
  213. end
  214. function MapCanvasMixin:ReleaseAreaTriggers(namespace)
  215. self.activeAreaTriggers[namespace] = nil;
  216. self:TryRefreshingDebugAreaTriggers();
  217. end
  218. function MapCanvasMixin:ReleaseAreaTrigger(namespace, areaTrigger)
  219. if self.activeAreaTriggers[namespace] then
  220. self.activeAreaTriggers[namespace][areaTrigger] = nil;
  221. self:TryRefreshingDebugAreaTriggers();
  222. end
  223. end
  224. function MapCanvasMixin:UpdateAreaTriggers(scrollRect)
  225. for namespace, areaTriggers in pairs(self.activeAreaTriggers) do
  226. for areaTrigger in pairs(areaTriggers) do
  227. if areaTrigger.intersectCallback then
  228. local intersects = (not areaTrigger.triggerPredicate or areaTrigger.triggerPredicate(areaTrigger)) and scrollRect:IntersectsRect(areaTrigger);
  229. if areaTrigger.intersects ~= intersects then
  230. areaTrigger.intersects = intersects;
  231. areaTrigger.intersectCallback(areaTrigger, intersects);
  232. end
  233. end
  234. if areaTrigger.enclosedCallback then
  235. local enclosed = (not areaTrigger.triggerPredicate or areaTrigger.triggerPredicate(areaTrigger)) and scrollRect:EnclosesRect(areaTrigger);
  236. if areaTrigger.enclosed ~= enclosed then
  237. areaTrigger.enclosed = enclosed;
  238. areaTrigger.enclosedCallback(areaTrigger, enclosed);
  239. end
  240. end
  241. end
  242. end
  243. self:TryRefreshingDebugAreaTriggers();
  244. end
  245. function SquaredDistanceBetweenPoints(firstX, firstY, secondX, secondY)
  246. local xDiff = firstX - secondX;
  247. local yDiff = firstY - secondY;
  248. return xDiff * xDiff + yDiff * yDiff;
  249. end
  250. function MapCanvasMixin:CalculatePinNudging(targetPin)
  251. targetPin:SetNudgeVector(nil, nil, nil, nil);
  252. if not targetPin:IgnoresNudging() and targetPin:GetNudgeTargetFactor() > 0 then
  253. local normalizedX, normalizedY = targetPin:GetPosition();
  254. for sourcePin in self:EnumerateAllPins() do
  255. if targetPin ~= sourcePin and not sourcePin:IgnoresNudging() and sourcePin:GetNudgeSourceRadius() > 0 then
  256. local otherNormalizedX, otherNormalizedY = sourcePin:GetPosition();
  257. local distanceSquared = SquaredDistanceBetweenPoints(normalizedX, normalizedY, otherNormalizedX, otherNormalizedY);
  258. local nudgeFactor = targetPin:GetNudgeTargetFactor() * sourcePin:GetNudgeSourceRadius();
  259. if distanceSquared < nudgeFactor * nudgeFactor then
  260. local distance = math.sqrt(distanceSquared);
  261. -- Avoid divide by zero: just push it right.
  262. if distanceSquared == 0 then
  263. targetPin:SetNudgeVector(sourcePin:GetNudgeSourceZoomedOutMagnitude(), sourcePin:GetNudgeSourceZoomedInMagnitude(), 1, 0);
  264. else
  265. targetPin:SetNudgeVector(sourcePin:GetNudgeSourceZoomedOutMagnitude(), sourcePin:GetNudgeSourceZoomedInMagnitude(), (normalizedX - otherNormalizedX) / distance, (normalizedY - otherNormalizedY) / distance);
  266. end
  267. targetPin:SetNudgeFactor(1 - (distance / nudgeFactor));
  268. break; -- This is non-exact: each target pin only gets pushed by one source pin.
  269. end
  270. end
  271. end
  272. end
  273. end
  274. function MapCanvasMixin:UpdatePinNudging()
  275. if not self.pinNudgingDirty and #self.pinsToNudge == 0 then
  276. return;
  277. end
  278. if self.pinNudgingDirty then
  279. for targetPin in self:EnumerateAllPins() do
  280. self:CalculatePinNudging(targetPin);
  281. end
  282. else
  283. for _, targetPin in ipairs(self.pinsToNudge) do
  284. self:CalculatePinNudging(targetPin);
  285. end
  286. end
  287. self.pinNudgingDirty = false;
  288. self.pinsToNudge = {};
  289. end
  290. function MapCanvasMixin:TryRefreshingDebugAreaTriggers()
  291. if self.debugAreaTriggers then
  292. self:RefreshDebugAreaTriggers();
  293. elseif self.debugAreaTriggerPool then
  294. self.debugAreaTriggerPool:ReleaseAll();
  295. end
  296. end
  297. function MapCanvasMixin:RefreshDebugAreaTriggers()
  298. if not self.debugAreaTriggerPool then
  299. self.debugAreaTriggerPool = CreateTexturePool(self:GetCanvas(), "OVERLAY", 7, "MapCanvasDebugTriggerAreaTemplate");
  300. self.debugAreaTriggerColors = {};
  301. end
  302. self.debugAreaTriggerPool:ReleaseAll();
  303. local canvas = self:GetCanvas();
  304. for namespace, areaTriggers in pairs(self.activeAreaTriggers) do
  305. if not self.debugAreaTriggerColors[namespace] then
  306. self.debugAreaTriggerColors[namespace] = { math.random(), math.random(), math.random(), 0.45 };
  307. end
  308. for areaTrigger in pairs(areaTriggers) do
  309. local debugAreaTexture = self.debugAreaTriggerPool:Acquire();
  310. debugAreaTexture:SetPoint("TOPLEFT", canvas, "TOPLEFT", canvas:GetWidth() * areaTrigger:GetLeft(), -canvas:GetHeight() * areaTrigger:GetTop());
  311. debugAreaTexture:SetPoint("BOTTOMRIGHT", canvas, "TOPLEFT", canvas:GetWidth() * areaTrigger:GetRight(), -canvas:GetHeight() * areaTrigger:GetBottom());
  312. debugAreaTexture:SetColorTexture(unpack(self.debugAreaTriggerColors[namespace]));
  313. debugAreaTexture:Show();
  314. end
  315. end
  316. end
  317. function MapCanvasMixin:SetDebugAreaTriggersEnabled(enabled)
  318. self.debugAreaTriggers = enabled;
  319. self.ScrollContainer:MarkAreaTriggersDirty();
  320. end
  321. function MapCanvasMixin:ForceRefreshDetailLayers()
  322. self.areDetailLayersDirty = true;
  323. self:RefreshDetailLayers();
  324. end
  325. function MapCanvasMixin:RefreshDetailLayers()
  326. if not self.areDetailLayersDirty then return end;
  327. self.detailLayerPool:ReleaseAll();
  328. local layers = C_Map.GetMapArtLayers(self.mapID);
  329. for layerIndex, layerInfo in ipairs(layers) do
  330. local detailLayer = self.detailLayerPool:Acquire();
  331. detailLayer:SetAllPoints(self:GetCanvas());
  332. detailLayer:SetMapAndLayer(self.mapID, layerIndex);
  333. detailLayer:SetGlobalAlpha(self:GetGlobalAlpha());
  334. detailLayer:Show();
  335. end
  336. self:AdjustDetailLayerAlpha();
  337. self.areDetailLayersDirty = false;
  338. end
  339. function MapCanvasMixin:AreDetailLayersLoaded()
  340. for detailLayer in self.detailLayerPool:EnumerateActive() do
  341. if not detailLayer:IsFullyLoaded() then
  342. return false;
  343. end
  344. end
  345. return true;
  346. end
  347. function MapCanvasMixin:AdjustDetailLayerAlpha()
  348. self.ScrollContainer:AdjustDetailLayerAlpha(self.detailLayerPool);
  349. end
  350. function MapCanvasMixin:RefreshAllDataProviders(fromOnShow)
  351. for dataProvider in pairs(self.dataProviders) do
  352. dataProvider:RefreshAllData(fromOnShow);
  353. end
  354. end
  355. function MapCanvasMixin:ResetInsets()
  356. if self.mapInsetPool then
  357. self.mapInsetPool:ReleaseAll();
  358. self.mapInsetsByIndex = {};
  359. end
  360. end
  361. function MapCanvasMixin:RefreshInsets()
  362. self:ResetInsets();
  363. end
  364. function MapCanvasMixin:AddInset(insetIndex, mapID, title, description, collapsedIcon, numDetailTiles, normalizedX, normalizedY)
  365. if self.mapInsetPool then
  366. local mapInset = self.mapInsetPool:Acquire();
  367. local expanded = self.expandedMapInsetsByMapID[mapID];
  368. mapInset:Initialize(self, not expanded, insetIndex, mapID, title, description, collapsedIcon, numDetailTiles, normalizedX, normalizedY);
  369. self.mapInsetsByIndex[insetIndex] = mapInset;
  370. end
  371. end
  372. function MapCanvasMixin:RefreshAll(fromOnShow)
  373. self:RefreshDetailLayers();
  374. self:RefreshInsets();
  375. self:RefreshAllDataProviders(fromOnShow);
  376. end
  377. function MapCanvasMixin:SetPinPosition(pin, normalizedX, normalizedY, insetIndex)
  378. self:ApplyPinPosition(pin, normalizedX, normalizedY, insetIndex);
  379. if not pin:IgnoresNudging() then
  380. if pin:GetNudgeSourceRadius() > 0 then
  381. -- If we nudge other things we need to recalculate all nudging.
  382. self.pinNudgingDirty = true;
  383. else
  384. self.pinsToNudge[#self.pinsToNudge + 1] = pin;
  385. end
  386. end
  387. end
  388. function MapCanvasMixin:ApplyPinPosition(pin, normalizedX, normalizedY, insetIndex)
  389. if insetIndex then
  390. if self.mapInsetsByIndex and self.mapInsetsByIndex[insetIndex] then
  391. self.mapInsetsByIndex[insetIndex]:SetLocalPinPosition(pin, normalizedX, normalizedY);
  392. pin:ApplyFrameLevel();
  393. end
  394. else
  395. pin:ClearAllPoints();
  396. if normalizedX and normalizedY then
  397. local x = normalizedX;
  398. local y = normalizedY;
  399. local nudgeVectorX, nudgeVectorY = pin:GetNudgeVector();
  400. if nudgeVectorX and nudgeVectorY then
  401. local finalNudgeFactor = pin:GetNudgeFactor() * pin:GetNudgeTargetFactor() * pin:GetNudgeZoomFactor();
  402. x = normalizedX + nudgeVectorX * finalNudgeFactor;
  403. y = normalizedY + nudgeVectorY * finalNudgeFactor;
  404. end
  405. local canvas = self:GetCanvas();
  406. local scale = pin:GetScale();
  407. pin:SetParent(canvas);
  408. pin:ApplyFrameLevel();
  409. pin:SetPoint("CENTER", canvas, "TOPLEFT", (canvas:GetWidth() * x) / scale, -(canvas:GetHeight() * y) / scale);
  410. end
  411. end
  412. end
  413. function MapCanvasMixin:GetGlobalPosition(normalizedX, normalizedY, insetIndex)
  414. if self.mapInsetsByIndex and self.mapInsetsByIndex[insetIndex] then
  415. return self.mapInsetsByIndex[insetIndex]:GetGlobalPosition(normalizedX, normalizedY);
  416. end
  417. return normalizedX, normalizedY;
  418. end
  419. function MapCanvasMixin:GetCanvas()
  420. return self.ScrollContainer.Child;
  421. end
  422. function MapCanvasMixin:GetCanvasContainer()
  423. return self.ScrollContainer;
  424. end
  425. function MapCanvasMixin:CallMethodOnPinsAndDataProviders(methodName, ...)
  426. for dataProvider in pairs(self.dataProviders) do
  427. dataProvider[methodName](dataProvider, ...);
  428. end
  429. for pin in self:EnumerateAllPins() do
  430. pin[methodName](pin, ...);
  431. end
  432. end
  433. function MapCanvasMixin:OnMapInsetSizeChanged(mapID, mapInsetIndex, expanded)
  434. self.expandedMapInsetsByMapID[mapID] = expanded;
  435. self:CallMethodOnPinsAndDataProviders("OnMapInsetSizeChanged", mapInsetIndex, expanded);
  436. end
  437. function MapCanvasMixin:OnMapInsetMouseEnter(mapInsetIndex)
  438. self:CallMethodOnPinsAndDataProviders("OnMapInsetMouseEnter", mapInsetIndex);
  439. end
  440. function MapCanvasMixin:OnMapInsetMouseLeave(mapInsetIndex)
  441. self:CallMethodOnPinsAndDataProviders("OnMapInsetMouseLeave", mapInsetIndex);
  442. end
  443. function MapCanvasMixin:OnMapChanged()
  444. for dataProvider in pairs(self.dataProviders) do
  445. dataProvider:OnMapChanged();
  446. end
  447. end
  448. function MapCanvasMixin:OnCanvasScaleChanged()
  449. self:AdjustDetailLayerAlpha();
  450. if self.mapInsetsByIndex then
  451. for insetIndex, mapInset in pairs(self.mapInsetsByIndex) do
  452. mapInset:OnCanvasScaleChanged();
  453. end
  454. end
  455. self:CallMethodOnPinsAndDataProviders("OnCanvasScaleChanged");
  456. end
  457. function MapCanvasMixin:OnCanvasPanChanged()
  458. self:CallMethodOnPinsAndDataProviders("OnCanvasPanChanged");
  459. end
  460. function MapCanvasMixin:OnCanvasSizeChanged()
  461. self:CallMethodOnPinsAndDataProviders("OnCanvasSizeChanged");
  462. end
  463. function MapCanvasMixin:GetCanvasScale()
  464. return self.ScrollContainer:GetCanvasScale();
  465. end
  466. function MapCanvasMixin:GetCanvasZoomPercent()
  467. return self.ScrollContainer:GetCanvasZoomPercent();
  468. end
  469. function MapCanvasMixin:IsZoomingIn()
  470. return self.ScrollContainer:IsZoomingIn();
  471. end
  472. function MapCanvasMixin:IsZoomingOut()
  473. return self.ScrollContainer:IsZoomingOut();
  474. end
  475. function MapCanvasMixin:ZoomIn()
  476. self.ScrollContainer:ZoomIn();
  477. end
  478. function MapCanvasMixin:ZoomOut()
  479. self.ScrollContainer:ZoomOut();
  480. end
  481. function MapCanvasMixin:ResetZoom()
  482. self.ScrollContainer:ResetZoom();
  483. end
  484. function MapCanvasMixin:IsAtMaxZoom()
  485. return self.ScrollContainer:IsAtMaxZoom();
  486. end
  487. function MapCanvasMixin:IsAtMinZoom()
  488. return self.ScrollContainer:IsAtMinZoom();
  489. end
  490. function MapCanvasMixin:PanTo(normalizedX, normalizedY)
  491. self.ScrollContainer:SetPanTarget(normalizedX, normalizedY);
  492. end
  493. function MapCanvasMixin:PanAndZoomTo(normalizedX, normalizedY)
  494. self.ScrollContainer:SetPanTarget(normalizedX, normalizedY);
  495. self.ScrollContainer:ZoomIn();
  496. end
  497. function MapCanvasMixin:SetMouseWheelZoomMode(zoomMode)
  498. self.ScrollContainer:SetMouseWheelZoomMode(zoomMode);
  499. end
  500. function MapCanvasMixin:SetShouldZoomInOnClick(shouldZoomInOnClick)
  501. self.ScrollContainer:SetShouldZoomInOnClick(shouldZoomInOnClick);
  502. end
  503. function MapCanvasMixin:ShouldZoomInOnClick()
  504. return self.ScrollContainer:ShouldZoomInOnClick();
  505. end
  506. function MapCanvasMixin:SetShouldNavigateOnClick(shouldNavigateOnClick)
  507. self.ScrollContainer:SetShouldNavigateOnClick(shouldNavigateOnClick);
  508. end
  509. function MapCanvasMixin:ShouldNavigateOnClick()
  510. return self.ScrollContainer:ShouldNavigateOnClick();
  511. end
  512. function MapCanvasMixin:SetShouldPanOnClick(shouldPanOnClick)
  513. self.ScrollContainer:SetShouldPanOnClick(shouldPanOnClick);
  514. end
  515. function MapCanvasMixin:ShouldPanOnClick()
  516. return self.ScrollContainer:ShouldPanOnClick();
  517. end
  518. function MapCanvasMixin:SetShouldZoomInstantly(shouldZoomInstantly)
  519. self.ScrollContainer:SetShouldZoomInstantly(shouldZoomInstantly);
  520. end
  521. function MapCanvasMixin:ShouldZoomInstantly()
  522. return self.ScrollContainer:ShouldZoomInstantly();
  523. end
  524. function MapCanvasMixin:GetViewRect()
  525. return self.ScrollContainer:GetViewRect();
  526. end
  527. function MapCanvasMixin:GetMaxZoomViewRect()
  528. return self.ScrollContainer:GetMaxZoomViewRect();
  529. end
  530. function MapCanvasMixin:GetMinZoomViewRect()
  531. return self.ScrollContainer:GetMinZoomViewRect();
  532. end
  533. function MapCanvasMixin:GetScaleForMaxZoom()
  534. return self.ScrollContainer:GetScaleForMaxZoom();
  535. end
  536. function MapCanvasMixin:GetScaleForMinZoom()
  537. return self.ScrollContainer:GetScaleForMinZoom();
  538. end
  539. function MapCanvasMixin:CalculateZoomScaleAndPositionForAreaInViewRect(...)
  540. return self.ScrollContainer:CalculateZoomScaleAndPositionForAreaInViewRect(...);
  541. end
  542. function MapCanvasMixin:NormalizeHorizontalSize(size)
  543. return self.ScrollContainer:NormalizeHorizontalSize(size);
  544. end
  545. function MapCanvasMixin:DenormalizeHorizontalSize(size)
  546. return self.ScrollContainer:DenormalizeHorizontalSize(size);
  547. end
  548. function MapCanvasMixin:NormalizeVerticalSize(size)
  549. return self.ScrollContainer:NormalizeVerticalSize(size);
  550. end
  551. function MapCanvasMixin:DenormalizeVerticalSize(size)
  552. return self.ScrollContainer:DenormalizeVerticalSize(size);
  553. end
  554. function MapCanvasMixin:GetNormalizedCursorPosition()
  555. return self.ScrollContainer:GetNormalizedCursorPosition()
  556. end
  557. function MapCanvasMixin:IsCanvasMouseFocus()
  558. return self.ScrollContainer == GetMouseFocus();
  559. end
  560. function MapCanvasMixin:AddLockReason(reason)
  561. self.lockReasons[reason] = true;
  562. self:EvaluateLockReasons();
  563. end
  564. function MapCanvasMixin:RemoveLockReason(reason)
  565. self.lockReasons[reason] = nil;
  566. self:EvaluateLockReasons();
  567. end
  568. function MapCanvasMixin:EvaluateLockReasons()
  569. if next(self.lockReasons) then
  570. self.BorderFrame:EnableMouse(true);
  571. self.BorderFrame:EnableMouseWheel(true);
  572. if self.BorderFrame.Underlay then
  573. self.BorderFrame.Underlay:Show();
  574. end
  575. else
  576. self.BorderFrame:EnableMouse(false);
  577. self.BorderFrame:EnableMouseWheel(false);
  578. if self.BorderFrame.Underlay then
  579. self.BorderFrame.Underlay:Hide();
  580. end
  581. end
  582. end
  583. function MapCanvasMixin:GetPinFrameLevelsManager()
  584. return self.pinFrameLevelsManager;
  585. end
  586. function MapCanvasMixin:ReapplyPinFrameLevels(pinFrameLevelType)
  587. for pin in self:EnumerateAllPins() do
  588. if pin:GetFrameLevelType() == pinFrameLevelType then
  589. pin:ApplyFrameLevel();
  590. end
  591. end
  592. end
  593. function MapCanvasMixin:NavigateToParentMap()
  594. local mapInfo = C_Map.GetMapInfo(self:GetMapID());
  595. if mapInfo.parentMapID > 0 then
  596. self:SetMapID(mapInfo.parentMapID);
  597. end
  598. end
  599. function MapCanvasMixin:NavigateToCursor()
  600. local normalizedCursorX, normalizedCursorY = self:GetNormalizedCursorPosition();
  601. local mapInfo = C_Map.GetMapInfoAtPosition(self:GetMapID(), normalizedCursorX, normalizedCursorY);
  602. if mapInfo then
  603. self:SetMapID(mapInfo.mapID);
  604. end
  605. end
  606. -- Add a function that will be checked when the canvas is clicked
  607. -- If the function returns true then handling will stop
  608. -- A priority can optionally be specified, higher priority values will be called first
  609. do
  610. local function PrioritySorter(left, right)
  611. return left.priority > right.priority;
  612. end
  613. function MapCanvasMixin:AddCanvasClickHandler(handler, priority)
  614. table.insert(self.mouseClickHandlers, { handler = handler, priority = priority or 0 });
  615. table.sort(self.mouseClickHandlers, PrioritySorter);
  616. end
  617. end
  618. function MapCanvasMixin:RemoveCanvasClickHandler(handler, priority)
  619. for i, handlerInfo in ipairs(self.mouseClickHandlers) do
  620. if handlerInfo.handler == handler and (not priority or handlerInfo.priority == priority) then
  621. table.remove(i);
  622. break;
  623. end
  624. end
  625. end
  626. function MapCanvasMixin:ProcessCanvasClickHandlers(button, cursorX, cursorY)
  627. for i, handlerInfo in ipairs(self.mouseClickHandlers) do
  628. local success, stopChecking = xpcall(handlerInfo.handler, CallErrorHandler, self, button, cursorX, cursorY);
  629. if success and stopChecking then
  630. return true;
  631. end
  632. end
  633. return false;
  634. end
  635. function MapCanvasMixin:GetGlobalPinScale()
  636. return self.globalPinScale or 1;
  637. end
  638. function MapCanvasMixin:SetGlobalPinScale(scale)
  639. if self.globalPinScale ~= scale then
  640. self.globalPinScale = scale;
  641. for pin in self:EnumerateAllPins() do
  642. pin:ApplyCurrentScale();
  643. end
  644. end
  645. end
  646. function MapCanvasMixin:GetGlobalAlpha()
  647. return self.globalAlpha or 1;
  648. end
  649. function MapCanvasMixin:SetGlobalAlpha(globalAlpha)
  650. if self.globalAlpha ~= globalAlpha then
  651. self.globalAlpha = globalAlpha;
  652. for detailLayer in self.detailLayerPool:EnumerateActive() do
  653. detailLayer:SetGlobalAlpha(globalAlpha);
  654. end
  655. for dataProvider in pairs(self.dataProviders) do
  656. dataProvider:OnGlobalAlphaChanged();
  657. end
  658. end
  659. end