changeset 35:26dfa661daa7

WorldPlan: - Quest pins will appear in the flight map. They follow the filter settings applied from the world map. - Reward filter toggle changed to clear out other reward filters. The assumption being that one is most often looking only for that particular type of quest when they go to use it. - Fixed filter bar info falling out of sync after player-triggered world map updates. - Code stuff: -- Quest pin shown-state management makes better use of OnShow OnHide handlers, SetShown is toggled and it all goes from there -- WorldQuests module re-factored outside of the top level frame script. ClassPlan: - Available missions are now recorded; the mission list can be toggled between in-progress and available by clicking the heading.
author Nenue
date Thu, 03 Nov 2016 17:29:15 -0400
parents 0100d923d8c3
children 21bcff08b0f4
files ClassPlan.lua ClassPlan.xml ClassPlanFollowers.lua ClassPlanFollowers.xml ClassPlanMissions.lua ClassPlanMissions.xml ClassPlanShipments.lua ClassPlanShipments.xml FollowerList.lua FollowerList.xml QuestPOI.lua WorldPlan.lua WorldPlan.toc WorldPlan.xml WorldQuests.lua
diffstat 13 files changed, 632 insertions(+), 400 deletions(-) [+]
line wrap: on
line diff
--- a/ClassPlan.lua	Wed Nov 02 19:04:47 2016 -0400
+++ b/ClassPlan.lua	Thu Nov 03 17:29:15 2016 -0400
@@ -38,6 +38,7 @@
 ClassOrderPlanCore = {
   events = {},
   freeBlocks = {},
+  characterButtons = {},
   blocks = {},
   sortedItems = {},
   timers = {},
@@ -73,6 +74,7 @@
 local SharedHandlers = {
   numBlocks = 0,
   isStale = true,
+  maxItems = 10
 }
 local SharedEntry = {}
 local ShipmentEntry = {}
@@ -122,6 +124,8 @@
   self.Background:SetColorTexture(classColor.r, classColor.g, classColor.b, 0.5)
   self.profile.classColor = classColor
   self.profile.className = className
+  self.profile.characterName = name
+  self.profile.characterRealm = realm
   return self.profile
 end
 
@@ -189,22 +193,23 @@
         print('  |cFF00FF00'..index..' '..handler:GetName()..'|r')
         local sortedItems = handler.sortedItems
         local activeKey = handler.activeKey
+
         handler.profile = self.profile[handler.activeKey]
-
+        handler.currentTime = GI_currentTime
+        handler:GetPlayerData(self.profile)
         wipe(sortedItems)
-        handler:GetPlayerData(self.profile)
         for key, profile in pairs(self.data.characters) do
           print('profile', key, activeKey)
           local profileList = profile[activeKey]
           if profileList and #profileList >= 1 then
-            local classColor = profile.classColor or defaultClassColor
+            local classColor = profile.classColor or RAID_CLASS_COLORS['HUNTER']
             local isMine = (profile == self.profile)
             for index, data in ipairs(profileList) do
               data.classColor = classColor
               data.profileKey = key
               data.isMine = isMine
               if handler.OnGetItem then
-                handler.OnGetItem(data)
+                handler:OnGetItem(data)
               end
               tinsert(sortedItems, data)
             end
@@ -222,6 +227,37 @@
 
     end
 
+    local index = 1
+    for id, profile in pairs(self.data.characters) do
+      local button = self.characterButtons[index]
+      if not button then
+        button = CreateFrame('Button', nil, self, 'ClassOrderPlanCharacterButton')
+        button:SetID(index)
+        self.characterButtons[index] = button
+
+        if not self.lastButton then
+          button:SetPoint('BOTTOMLEFT', self, 'TOPLEFT', 0, 0)
+        else
+          button:SetPoint('BOTTOMLEFT', self.lastButton, 'BOTTOMRIGHT', 2, 0)
+        end
+        self.lastButton = button
+      end
+      if not profile.characterName then
+        profile.characterName, profile.characterRealm = id:match("%(.+)%-(.+)^")
+      end
+
+      button.className = profile.className
+      button.classColor = profile.classColor
+      button.characterName = profile.characterName
+      button.characterRealm = profile.characterRealm
+      button.hideItems = (profile.showItems == false) and (profile ~= self.profile)
+      button.isMine = (profile == self.profile)
+      button:Update()
+      button:Show()
+      index = index + 1
+    end
+
+
     self.isStale = nil
     self:Reanchor()
     self:SetHeight(self.currentHeight + CP_HEADER_SIZE)
@@ -265,6 +301,17 @@
 
   for index, frame in ipairs(self.Handlers) do
     frame:Reanchor()
+
+    local ListTab = frame.ListTab
+    if ListTab then
+      ListTab:ClearAllPoints()
+      ListTab:SetPoint('TOPLEFT', frame, 'TOPLEFT', 0, CP_HEADER_SIZE)
+      ListTab:SetPoint('BOTTOMRIGHT', frame, 'TOPRIGHT', 0, 0)
+      ListTab.Label:SetText(frame.listTitle[frame.currentListIndex])
+      ListTab:Show()
+      print(ListTab:GetSize())
+    end
+
   end
 end
 
@@ -300,6 +347,11 @@
   self.isStale = true
 end
 
+function SharedHandlers:OnMouseWheel(delta)
+  self.scrollOffset = (self.scrollOffset or 0) - ((delta > 0) and 1 or -1)
+  self:UpdateItems()
+end
+
 function SharedHandlers:RequestData()
   print('|cFF0088FF'..self:GetName()..':RequestData()')
   self.isStale = true
@@ -345,34 +397,57 @@
   self.Name:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b)
 end
 
+function SharedHandlers:Acquire(id)
+end
+function SharedHandlers:FreeBlock (block)
+end
+
 function SharedHandlers:UpdateItems()
+
+  self.MoreItemsUp:Hide()
+  self.MoreItemsDown:Hide()
+
   local sortedItems = self.sortedItems
+  local scrollOffset = self.scrollOffset or 0
+  local numItems = #sortedItems
+  if (not sortedItems[scrollOffset+1]) or (numItems <= self.maxItems) then
+    scrollOffset = 0
+  elseif (numItems > self.maxItems) and (scrollOffset > (numItems - self.maxItems)) then
+    scrollOffset = (numItems - self.maxItems)
+  end
+
 
   self.blocks = self.blocks or  {}
   local blocks = self.blocks
 
   local lastProfile
-  local numItems = #sortedItems
   local totalHeight = 0
   self.lastBlock = nil
   self.numActive = 0
-  for i, data in ipairs(sortedItems) do
+  for i = 1, self.maxItems do
+    local index = scrollOffset + i
+    local data = sortedItems[index]
+    if not data then
+      break
+    end
+
+
     local block = blocks[i]
     if not block then
       block = CreateFrame('Button', nil, self, self.templateName)
-      block:SetID(i)
       block.listType = self.activeKey
       block.handler = self
       self.numBlocks = self.numBlocks + 1
       blocks[i] = block
     end
+    block:SetID(index)
 
     print('RefreshItem', block)
     self.numActive = self.numActive + 1
 
     if self.lastBlock then
       block:SetPoint('TOPLEFT', self.lastBlock, 'BOTTOMLEFT', 0, 0)
-      print('--', i, data.isComplete, data.missionEndTime, data.name)
+      print('--', index, data.isComplete, data.missionEndTime, data.name)
     else
       block:SetPoint('TOPLEFT', 0, 0)
       print('--top')
@@ -401,12 +476,22 @@
     lastProfile = data.profileKey
   end
 
-  for i = numItems + 1, self.numBlocks do
+  if self.numActive < numItems then
+    if scrollOffset < (numItems - self.maxItems) then
+      self.MoreItemsDown:Show()
+    end
+    if scrollOffset > 0 then
+      self.MoreItemsUp:Show()
+    end
+  end
+
+  for i = self.numActive + 1, self.numBlocks do
     if blocks[i] then
       blocks[i]:Hide()
     end
   end
 
+  self.scrollOffset = scrollOffset
   self:Reanchor()
 
   return totalHeight
@@ -419,38 +504,7 @@
   self:SetPoint('BOTTOMRIGHT', -ClassOrderPlan:GetWidth()/2, 0)
 end
 
-function MissionList:Reanchor()
-  self:SetPoint('TOPRIGHT', 0, -24)
-  self:SetPoint('BOTTOMLEFT', ClassOrderPlan:GetWidth()/2, 0)
 
-  self.ListTab:ClearAllPoints()
-  self.ListTab:SetPoint('TOPLEFT', self, 'TOPLEFT', 0, CP_HEADER_SIZE)
-  self.ListTab:SetPoint('BOTTOMRIGHT', self, 'TOPRIGHT', 0, 0)
-  self.ListTab.Label:SetText(self.listTitle[self.currentListIndex])
-  self.ListTab:Show()
-  print(self.ListTab:GetSize())
-end
-
-function MissionList:GetPlayerData (profile)
-  wipe(profile.missions)
-  wipe(profile.available)
-
-  local items = C_Garrison.GetAvailableMissions(GetPrimaryGarrisonFollowerType(LE_GARRISON_TYPE_7_0));
-  for i = 1, #items do
-    if (not items[i].isBuilding and items[i].isZoneSupport) then
-    else
-
-      tinsert(profile.available, items[i])
-    end
-  end
-
-  local items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0)
-  for index, data in ipairs(items) do
-    print(' -',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime))
-    tinsert(profile.missions, data)
-  end
-  return true
-end
 
 do
   local ShipmentsInfo = {}
@@ -532,63 +586,47 @@
     return true
   end
 end
-MissionList.OnGetItem = function(data)
-  if data.missionEndTime and (data.missionEndTime < GI_currentTime) then
-    data.isComplete = true
+
+
+function SharedEntry:SetTimeLeft(expires, duration)
+  self.ProgressBG:Hide()
+  self.ProgressBar:Hide()
+  if not expires then
+    return
   end
-end
 
-MissionList.FreeBlock = function(self, block)
-end
+  -- calculate here since time isn't available
+  local timeLeft = expires - GI_currentTime
+  if timeLeft < 0 then
+    -- handle being complete
 
-MissionList.SortHandler = function (a,b)
-  local result = false
-  --if not a or not b then
-  --  return true
-  --else
-    --if (a.isMine ~= b.isMine) then
-    --  result = a.isMine
-    --else
-      --if (not b.missionEndTime) or (not a.missionEndTime) then
-      --  print('missing article', b.missionEndTime, a.missionEndTime)
-      --end
-      if b.isComplete ~= a.isComplete then
-        return a.isComplete
-      elseif b.isMine ~= a.isMine then
-        return a.isMine
-      elseif b.missionEndTime then
-        return ( b.missionEndTime > a.missionEndTime)
-      else
-        return ( b.offerEndTime > a.offerEndTime)
-      end
+  else
+    self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
+  end
 
-    --end
-  --end
-end
+  if (timeLeft > 0) and duration then
+    local progress = (duration - timeLeft) / duration
+    local r = ((progress >= .5) and (progress/2)) or 1
+    local g = ((progress <= .5) and (progress*2)) or 1
+    self.ProgressBG:Show()
+    self.ProgressBar:Show()
 
-
-function MissionList:OnShow()
-  print('|cFF00FF88'..self:GetName()..':OnShow()|r')
-end
-
-function ShipmentList:OnLoad()
-  C_Garrison.RequestLandingPageShipmentInfo();
-end
-function  ShipmentList:OnShow()
-  print('|cFF00FF88'..self:GetName()..':OnShow()|r')
-  C_Garrison.RequestLandingPageShipmentInfo()
+    self.ProgressBG:SetColorTexture(r,g,0,0.25)
+    self.ProgressBar:SetColorTexture(r,g,0,0.5)
+    self.ProgressBar:SetWidth(self:GetWidth() * progress)
+  end
 end
 
 -- Update shipment flags data
 local SetActualShipmentTime = function(self)
 
   if self.isComplete then
-    print('|cFF00FF88isComplete '..self.name..'|r')
-    return true
+    return nil, nil
   end
 
   local timestamp = time()
   local timeLeft = self.creationTime + self.duration - timestamp
+  local duration = self.duration * self.shipmentsTotal
   local justFinished = false
   while (self.shipmentsReady < self.shipmentsTotal) and (timeLeft <= 0) do
     if not self.originalReady then
@@ -608,10 +646,13 @@
     self.isStale = true
   end
 
-  return timeLeft
+
+  local expires = (self.originalCreationTime or self.creationTime) + duration
+
+  return expires, duration
 end
 
-ShipmentList.OnGetItem = function(data)
+function ShipmentList:OnGetItem (data)
   print('OnGetItem()')
   if data.shipmentsTotal then
     SetActualShipmentTime(data)
@@ -628,118 +669,12 @@
   end
 end
 
-
-function MissionEntry:OnComplete()
-  print('flagging complete', self.name)
-  self:Update()
+function ShipmentList:OnLoad()
+  C_Garrison.RequestLandingPageShipmentInfo();
 end
-
-function MissionEntry:OnUpdate(sinceLast)
-  self.throttle = (self.throttle or .5) + sinceLast
-  if self.throttle < .5 then
-    return
-  else
-    self.throttle = self.throttle - .5
-  end
-  if self.offerEndTime then
-    local timeLeft = self.offerEndTime
-    self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
-    self.TimeLeft:SetTextColor(1,1,1)
-  elseif self.missionEndTime then
-
-    if self.isComplete then
-      return
-    end
-    local timeLeft = self.missionEndTime - time()
-    if timeLeft < 0 then
-      self:OnComplete()
-    else
-      self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
-      if timeLeft > 3600 then
-        self.TimeLeft:SetTextColor(1,1,1)
-      else
-        self.TimeLeft:SetTextColor(1,1,0)
-      end
-    end
-
-    if not self.isComplete then
-      local progress = (time() - (self.missionEndTime - self.durationSeconds)) / self.durationSeconds
-      local w = self.ProgressBG:GetWidth()
-      if progress >= 1 then
-        self.ProgressBar:SetWidth(w)
-      else
-        self.ProgressBar:SetWidth(progress * w)
-        local r, g = 1, 0
-        if progress >= 0.5 then
-          g = 1
-          r = 1-((progress-0.5)*2)
-        else
-          g = min(progress * 2, 1)
-          r = 1
-        end
-        self.ProgressBar:SetColorTexture(r,g,0,.4)
-        self.ProgressBG:SetColorTexture(r,g,0,0.125)
-      end
-      self.ProgressBG:Show()
-      self.ProgressBar:Show()
-    else
-      self.ProgressBG:Hide()
-      self.ProgressBar:Hide()
-    end
-  else
-    self.TimeLeft:SetText(self.missionEndTime)
-  end
-end
-
-function MissionEntry:OnLoad()
-  print('|cFFFF4400',self:GetName() or tostring(self), 'onload')
-  self.Count = self.Overlay.Count
-  self.Name = self.Overlay.Name
-  self.TimeLeft = self.Overlay.TimeLeft
-  self.Owner = self.Overlay.Owner
-
-  self.Icon:SetDesaturated(false)
-  self.Done:Hide()
-end
-
-function MissionEntry:Update()
-  local r,g,b = 1, 1, 1
-  if self.isRare then
-    r,g,b = 0.1, 0.4, 1
-    self.IconBorder:SetVertexColor(r, g, b, 1)
-  end
-
-  --self.missionData = data
-  self.Name:SetText(self.name)
-  if #self.rewards >= 1 then
-    self.Icon:SetTexture(self.rewards[1].icon or GetItemIcon(self.rewards[1].itemID))
-    self.rewardInfo = self.rewards[1]
-  else
-    self.Icon:SetAtlas(self.typeAtlas, false)
-  end
-
-
-
-  if self.isComplete then
-    self.TimeLeft:SetText('Complete!')
-    self.Background:SetColorTexture(.25,.25,.25,1)
-  else
-    self.Background:SetColorTexture(0,0,0,0.5)
-  end
-end
-
-function MissionEntry:OnEnter()
-  if self.rewardInfo and self.rewardInfo.itemID then
-    GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
-    GameTooltip:SetItemByID(self.rewardInfo.itemID)
-    GameTooltip:Show()
-  end
-end
-
-function MissionEntry:OnLeave()
-  if GameTooltip:IsOwned(self) then
-    GameTooltip:Hide()
-  end
+function  ShipmentList:OnShow()
+  print('|cFF00FF88'..self:GetName()..':OnShow()|r')
+  C_Garrison.RequestLandingPageShipmentInfo()
 end
 
 function ShipmentEntry:OnLoad()
@@ -785,52 +720,27 @@
 
 
   if (self.shipmentsReady and self.shipmentsTotal) and (self.shipmentsReady < self.shipmentsTotal) then
-    local timeLeft = SetActualShipmentTime(self)
+    local expires, duration = SetActualShipmentTime(self)
 
     if self.isComplete then
       self.TimeLeft:SetText('Complete!')
-      self.TimeLeft:SetTextColor(0,0.5,1)
+      self.TimeLeft:SetTextColor(0,1,1)
     elseif self.shipmentsReady >= 1 then
-      self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
+      self:SetTimeLeft(expires, duration)
       self.TimeLeft:SetTextColor(0,1,0)
     else
-      self.TimeLeft:SetText(GetTimeLeftString(timeLeft))
+      self:SetTimeLeft(expires, duration)
       self.TimeLeft:SetTextColor(1,1,1)
     end
 
   elseif self.isBeingResearched then
-    self.TimeLeft:SetText(GetTimeLeftString(self.researchStartTime + self.researchDuration - time()))
-    self.TimeLeft:SetTextColor(1,1,0)
+    self:SetTimeLeft(self.researchStartTime + self.researchDuration - time(), self.researchDuration)
+    self.TimeLeft:SetTextColor(1,1,1)
   else
     self.TimeLeft:SetText('Complete!')
     self.TimeLeft:SetTextColor(0,1,0)
   end
 
-  if not self.isComplete then
-    local progress =  ((time() - self.creationTime) / self.duration)
-    local w = self.ProgressBG:GetWidth()
-    if progress >= 1 then
-      self.ProgressBar:SetWidth(w)
-    else
-      self.ProgressBar:SetWidth(progress * w)
-    end
-
-    local r, g = 1, 0
-    if progress >= 0.5 then
-      g = 1
-      r = 1-((progress-0.5)*2)
-    else
-      g = min(progress * 2, 1)
-      r = 1
-    end
-    self.ProgressBar:SetColorTexture(r, g, 0, .4)
-    self.ProgressBG:SetColorTexture(r, g, 0, .125)
-    self.ProgressBG:Show()
-    self.ProgressBar:Show()
-  else
-    self.ProgressBG:Hide()
-    self.ProgressBar:Hide()
-  end
 end
 
 function ShipmentEntry:OnEnter()
@@ -855,9 +765,12 @@
   end
 end
 
+
+
+
 ClassPlanMissionHandler = Mixin(MissionList, SharedHandlers)
+ClassPlanMissionEntryMixin = Mixin(MissionEntry, SharedEntry)
 ClassPlanShipmentHandler = Mixin(ShipmentList, SharedHandlers)
-ClassPlanMissionEntryMixin = Mixin(MissionEntry, SharedEntry)
 ClassPlanShipmentEntryMixin = Mixin(ShipmentEntry,SharedEntry)
 
 ClassPlanHeaderMixin = {
@@ -866,4 +779,19 @@
     self:GetParent().isStale = true
     ClassOrderPlan:Update()
   end
-}
\ No newline at end of file
+}
+
+ClassPlanCharacterButtonMixin = {
+  Update = function(self)
+    print(CLASS_ICON_TCOORDS[self.className:upper()])
+    if self.className and CLASS_ICON_TCOORDS[self.className:upper()] then
+      self.Icon:SetTexCoord(unpack(CLASS_ICON_TCOORDS[self.className:upper()]))
+    end
+    self.Icon:SetDesaturated(self.showItems)
+    self.SelectGlow:SetShown(self.isMine)
+  end
+}
+
+function ClassPlanCharacterButtonMixin:OnEnter() end
+function ClassPlanCharacterButtonMixin:OnLeave() end
+function ClassPlanCharacterButtonMixin:OnClick() end
\ No newline at end of file
--- a/ClassPlan.xml	Wed Nov 02 19:04:47 2016 -0400
+++ b/ClassPlan.xml	Thu Nov 03 17:29:15 2016 -0400
@@ -35,56 +35,62 @@
         </Texture>
       </Layer>
     </Layers>
+  </Frame>
+
+
+
+  <Frame name="ClassPlanPanelTemplate" parent="ClassOrderPlan" enableMouse="true" parentArray="Handlers" virtual="true">
+
+    <Scripts>
+      <OnLoad method="OnLoad" />
+      <OnUpdate method="OnUpdate" />
+      <OnEvent method="OnEvent" />
+      <OnShow method="OnShow" />
+      <OnMouseWheel method="OnMouseWheel" />
+    </Scripts>
     <Frames>
-      <Frame name="$parentMissionList" parentKey="MissionList" parentArray="Handlers" mixin="ClassPlanMissionHandler">
-        <Scripts>
-          <OnLoad method="OnLoad" />
-          <OnUpdate method="OnUpdate" />
-          <OnEvent method="OnEvent" />
-          <OnShow method="OnShow" />
-        </Scripts>
-        <Frames>
-          <Button name="$parentTab" parentKey="ListTab" mixin="ClassPlanHeaderMixin">
-            <Scripts>
-              <OnClick method="OnClick" />
-            </Scripts>
-            <Size y="24" />
-            <Layers>
-              <Layer level="BACKGROUND">
-                <Texture parentKey="Background">
-                  <Color a="1" r="0" g="0" b="0" />
-                </Texture>
-              </Layer>
-              <Layer level="OVERLAY">
-                <FontString parentKey="Label" inherits="ClassPlanFont">
-                  <Anchors>
-                    <Anchor point="CENTER" />
-                  </Anchors>
-                </FontString>
-              </Layer>
-              <Layer level="HIGHLIGHT">
-                <Texture parentKey="Highlight">
-                  <Color a="0.5" r="1" g="1" b="1" />
-                </Texture>
-              </Layer>
-            </Layers>
+      <Frame parentKey="MoreItemsUp" frameStrata="HIGH" hidden="true">
+        <Size y="24" />
+        <Anchors>
+          <Anchor point="TOPLEFT" />
+          <Anchor point="TOPRIGHT" />
+        </Anchors>
+        <Layers>
+          <Layer level="OVERLAY">
+            <Texture parentKey="Overlay">
+              <Color a="1" r="1" g="1" b="1" />
+              <Gradient orientation="VERTICAL">
+                <MinColor r="0" g="0" b="0" a="0" />
+                <MaxColor r="0" g="0" b="0" a="0.5" />
+              </Gradient>
+            </Texture>
+          </Layer>
+        </Layers>
+      </Frame>
 
-          </Button>
-        </Frames>
-      </Frame>
-      <Frame name="$parentShipments" parentKey="Shipments" parentArray="Handlers" mixin="ClassPlanShipmentHandler">
-        <Scripts>
-          <OnLoad method="OnLoad" />
-          <OnUpdate method="OnUpdate" />
-          <OnEvent method="OnEvent" />
-          <OnShow method="OnShow" />
-        </Scripts>
+      <Frame parentKey="MoreItemsDown" frameStrata="HIGH" hidden="true">
+        <Size y="24" />
+        <Anchors>
+          <Anchor point="BOTTOMLEFT" />
+          <Anchor point="BOTTOMRIGHT" />
+        </Anchors>
+        <Layers>
+          <Layer level="OVERLAY">
+            <Texture parentKey="Overlay">
+              <Color a="1" r="1" g="1" b="1" />
+              <Gradient orientation="VERTICAL">
+                <MinColor r="0" g="0" b="0" a="0.5" />
+                <MaxColor r="0" g="0" b="0" a="0" />
+              </Gradient>
+            </Texture>
+          </Layer>
+        </Layers>
       </Frame>
     </Frames>
   </Frame>
 
 
-
+  <Frame name="$parentShipments" parentKey="Shipments" mixin="ClassPlanShipmentHandler" inherits="ClassPlanPanelTemplate" />
   <Button name="ClassPlanListEntryTemplate" virtual="true" hidden="true">
     <Scripts>
       <OnLoad method="OnLoad" />
@@ -192,11 +198,25 @@
   </Button>
 
 
-  <Button name="ClassPlanMissionEntry" inherits="ClassPlanListEntryTemplate" mixin="ClassPlanMissionEntryMixin" virtual="true">
-    <Size y="24" />
-    <Anchors>
-      <Anchor point="RIGHT" />
-    </Anchors>
+  <Button name="ClassOrderPlanCharacterButton" virtual="true" parent="ClassOrderPlan" mixin="ClassPlanCharacterButtonMixin" >
+    <Size x="48" y="48" />
+    <Scripts>
+      <OnLoad method="OnLoad" />
+      <OnEvent method="OnEvent" />
+      <OnClick method="OnClick" />
+      <OnEnter method="OnEnter" />
+      <OnLeave method="OnLeave" />
+    </Scripts>
+    <Layers>
+      <Layer level="ARTWORK">
+        <Texture parentKey="Icon" file="Interface\Glues\CHARACTERCREATE\UI-CHARACTERCREATE-CLASSES" setAllPoints="true" />
+      </Layer>
+      <Layer level="OVERLAY">
+        <Texture parentKey="SelectGlow" file="Interface\Glues\CHARACTERCREATE\UI-CharacterCreate-Highlights" alphaMode="ADD">
+          <TexCoords left="0.5" right="1" top="0" bottom="0.5" />
+        </Texture>
+      </Layer>
+    </Layers>
   </Button>
 
   <Button name="ClassPlanShipmentEntry" inherits="ClassPlanListEntryTemplate" mixin="ClassPlanShipmentEntryMixin" virtual="true">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ClassPlanFollowers.lua	Thu Nov 03 17:29:15 2016 -0400
@@ -0,0 +1,11 @@
+ClassPlanFollowerMixin = {}
+local c = ClassPlanFollowerMixin
+function c:OnEvent(event, arg)
+
+end
+
+function c:GetPlayerData(event, arg) end
+
+function c:UpdateItems() end
+
+function c:Reanchor() end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ClassPlanFollowers.xml	Thu Nov 03 17:29:15 2016 -0400
@@ -0,0 +1,11 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+  <Script file="FollowerList.lua" />
+  <Frame name="$parentFollowerList" parent="ClassOrderPlan"parentKey="FollowerList"  parentArray="Handlers" mixin="ClassPlanFollowerMixin">
+    <Scripts>
+      <OnEvent method="OnEvent" />
+      <OnUpdate method="OnUpdate" />
+      <OnShow method="OnShow" />
+    </Scripts>
+  </Frame>
+</Ui>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ClassPlanMissions.lua	Thu Nov 03 17:29:15 2016 -0400
@@ -0,0 +1,152 @@
+local MissionList = ClassPlanMissionHandler
+local ListEntry = ClassPlanMissionEntryMixin
+local ORDERHALL_TYPE = LE_GARRISON_TYPE_7_0
+function ClassPlanMissionHandler:Reanchor()
+  self:SetPoint('TOPRIGHT', 0, -24)
+  self:SetPoint('BOTTOMLEFT', ClassOrderPlan:GetWidth()/2, 0)
+
+end
+local GetPrimaryGarrisonFollowerType = GetPrimaryGarrisonFollowerType
+local C_Garrison = C_Garrison
+
+local wipe, tinsert, date, ipairs = table.wipe, table.insert, date, ipairs
+local GetItemIcon = GetItemIcon
+local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop
+
+function ClassPlanMissionHandler:GetPlayerData (profile)
+  local items = C_Garrison.GetAvailableMissions(GetPrimaryGarrisonFollowerType(ORDERHALL_TYPE));
+  if not items then
+    return
+  end
+  wipe(profile.missions)
+  wipe(profile.available)
+
+
+  for i = 1, #items do
+    if (not items[i].isBuilding and items[i].isZoneSupport) then
+    else
+
+      tinsert(profile.available, items[i])
+    end
+  end
+
+  local items = C_Garrison.GetLandingPageItems(ORDERHALL_TYPE)
+  for index, data in ipairs(items) do
+    print(' -',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime))
+    tinsert(profile.missions, data)
+  end
+  return true
+end
+
+function ClassPlanMissionHandler:OnGetItem (data)
+  if data.missionEndTime and (data.missionEndTime < self.currentTime) then
+    data.isComplete = true
+  end
+  if data.offerEndTime and (data.offerEndTime < self.currentTime) then
+    data.isExpired = true
+    data.timeToKeep = self.currentTime + 300
+  end
+end
+
+MissionList.SortHandler = function (a,b)
+  local result = false
+  --if not a or not b then
+  --  return true
+  --else
+  --if (a.isMine ~= b.isMine) then
+  --  result = a.isMine
+  --else
+  --if (not b.missionEndTime) or (not a.missionEndTime) then
+  --  print('missing article', b.missionEndTime, a.missionEndTime)
+  --end
+  if b.isComplete ~= a.isComplete then
+    return a.isComplete
+  elseif b.isMine ~= a.isMine then
+    return a.isMine
+  elseif b.missionEndTime then
+    return ( b.missionEndTime > a.missionEndTime)
+  else
+    return  ((b.offerEndTime or 0) > (a.offerEndTime or 0))
+  end
+
+  --end
+  --end
+end
+
+
+function MissionList:OnShow()
+  print('|cFF00FF88'..self:GetName()..':OnShow()|r')
+end
+
+
+
+function ClassPlanMissionEntryMixin:OnComplete()
+  print('flagging complete', self.name)
+  self:Update()
+end
+
+function ClassPlanMissionEntryMixin:OnUpdate(sinceLast)
+  self.throttle = (self.throttle or .5) + sinceLast
+  if self.throttle < .5 then
+    return
+  else
+    self.throttle = self.throttle - .5
+  end
+  if self.offerEndTime then
+    self:SetTimeLeft(self.offerEndTime)
+  elseif self.missionEndTime then
+    self:SetTimeLeft(self.missionEndTime, self.durationSeconds)
+  end
+end
+
+function ClassPlanMissionEntryMixin:OnLoad()
+  print('|cFFFF4400',self:GetName() or tostring(self), 'onload')
+  self.Count = self.Overlay.Count
+  self.Name = self.Overlay.Name
+  self.TimeLeft = self.Overlay.TimeLeft
+  self.Owner = self.Overlay.Owner
+  self.maxDisplayed = 10
+
+  self.Icon:SetDesaturated(false)
+  self.Done:Hide()
+end
+
+function ClassPlanMissionEntryMixin:Update()
+  local r,g,b = 1, 1, 1
+  if self.isRare then
+    r,g,b = 0.1, 0.4, 1
+    self.IconBorder:SetVertexColor(r, g, b, 1)
+  end
+
+  --self.missionData = data
+  self.Name:SetText(self.name)
+  if #self.rewards >= 1 then
+    self.Icon:SetTexture(self.rewards[1].icon or GetItemIcon(self.rewards[1].itemID))
+    self.rewardInfo = self.rewards[1]
+  else
+    self.Icon:SetAtlas(self.typeAtlas, false)
+  end
+
+
+
+  if self.isComplete then
+    self.TimeLeft:SetText('Complete!')
+    self.Background:SetColorTexture(.25,.25,.25,1)
+  else
+    self.Background:SetColorTexture(0,0,0,0.5)
+  end
+end
+
+function ListEntry:OnEnter()
+  if self.rewardInfo and self.rewardInfo.itemID then
+    GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
+    GameTooltip:SetItemByID(self.rewardInfo.itemID)
+    GameTooltip:Show()
+  end
+end
+
+function ListEntry:OnLeave()
+  if GameTooltip:IsOwned(self) then
+    GameTooltip:Hide()
+  end
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ClassPlanMissions.xml	Thu Nov 03 17:29:15 2016 -0400
@@ -0,0 +1,47 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+  <Script file="ClassPlanMissions.lua" />
+
+  <Button name="ClassPlanMissionEntry" inherits="ClassPlanListEntryTemplate" mixin="ClassPlanMissionEntryMixin" virtual="true">
+    <Size y="24" />
+    <Anchors>
+      <Anchor point="RIGHT" />
+    </Anchors>
+  </Button>
+  <Frame name="ClassPlanMissionList" parentKey="MissionList" mixin="ClassPlanMissionHandler" inherits="ClassPlanPanelTemplate">
+    <Scripts>
+      <OnLoad method="OnLoad" />
+      <OnUpdate method="OnUpdate" />
+      <OnEvent method="OnEvent" />
+      <OnShow method="OnShow" />
+    </Scripts>
+    <Frames>
+      <Button name="$parentTab" parentKey="ListTab" mixin="ClassPlanHeaderMixin">
+        <Scripts>
+          <OnClick method="OnClick" />
+        </Scripts>
+        <Size y="24" />
+        <Layers>
+          <Layer level="BACKGROUND">
+            <Texture parentKey="Background">
+              <Color a="1" r="0" g="0" b="0" />
+            </Texture>
+          </Layer>
+          <Layer level="OVERLAY">
+            <FontString parentKey="Label" inherits="ClassPlanFont">
+              <Anchors>
+                <Anchor point="CENTER" />
+              </Anchors>
+            </FontString>
+          </Layer>
+          <Layer level="HIGHLIGHT">
+            <Texture parentKey="Highlight">
+              <Color a="0.5" r="1" g="1" b="1" />
+            </Texture>
+          </Layer>
+        </Layers>
+
+      </Button>
+    </Frames>
+  </Frame>
+  </Ui>
\ No newline at end of file
--- a/FollowerList.lua	Wed Nov 02 19:04:47 2016 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-ClassPlanFollowerMixin = {}
-local c = ClassPlanFollowerMixin
-function c:OnEvent(event, arg)
-
-end
-
-function c:GetPlayerData(event, arg) end
-
-function c:UpdateItems() end
-
-function c:Reanchor() end
\ No newline at end of file
--- a/FollowerList.xml	Wed Nov 02 19:04:47 2016 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
-..\FrameXML\UI.xsd">
-  <Script file="FollowerList.lua" />
-  <Frame name="$parentFollowerList" parent="ClassOrderPlan"parentKey="FollowerList"  parentArray="Handlers" mixin="ClassPlanFollowerMixin">
-    <Scripts>
-      <OnEvent method="OnEvent" />
-      <OnUpdate method="OnUpdate" />
-      <OnShow method="OnShow" />
-    </Scripts>
-  </Frame>
-</Ui>
\ No newline at end of file
--- a/QuestPOI.lua	Wed Nov 02 19:04:47 2016 -0400
+++ b/QuestPOI.lua	Thu Nov 03 17:29:15 2016 -0400
@@ -4,7 +4,6 @@
 -- %file-revision%
 --
 
-WorldPlanPOIMixin = {}
 local TQ_GetQuestInfoByQuestID = C_TaskQuest.GetQuestInfoByQuestID -- Return the name of a quest with a given ID
 local TQ_GetQuestLocation = C_TaskQuest.GetQuestLocation
 local TQ_GetQuestTimeLeftMinutes = C_TaskQuest.GetQuestTimeLeftMinutes
@@ -168,6 +167,7 @@
 end
 
 function WorldPlanPOIMixin:OnEnter()
+  WorldMap_HijackTooltip(self)
   local completed = select(4,GetAchievementInfo(familiars_id))
   if not completed then
     if self.worldQuestType == LE_QUEST_TAG_TYPE_PET_BATTLE and familiars[self.questID] then
@@ -223,6 +223,7 @@
   TaskPOI_OnEnter(self)
 end
 function WorldPlanPOIMixin:OnLeave()
+  WorldMap_RestoreTooltip()
   TaskPOI_OnLeave(self)
 end
 function WorldPlanPOIMixin:OnMouseDown()
@@ -243,7 +244,7 @@
     if info.x and info.y then
       self.x = info.x or self.x
       self.y = info.y or self.y
-      qprint('|cFFFF4400applying taskInfo coords:', info.x, info.y)
+      --qprint('|cFFFF4400applying taskInfo coords:', info.x, info.y)
     end
 
   end
@@ -330,9 +331,9 @@
     self.isPending = isPending
 
 
-    qprint('  |cFF00FFFF'..questID..'|r hasUpdate:', hasUpdate, 'isPending:', isPending)
-    qprint('  ', 'rewardType:', self.rewardType, 'tag:', self.tagID)
-    qprint('  ', tostring(self.title), " |T"..tostring(self.itemTexture)..":12:12|t", tostring(self.itemName))
+    --qprint('  |cFF00FFFF'..questID..'|r hasUpdate:', hasUpdate, 'isPending:', isPending, 'isShown', self:IsShown())
+    --qprint('  ', 'rewardType:', self.rewardType, 'tag:', self.tagID)
+    --qprint('  ', tostring(self.title), " |T"..tostring(self.itemTexture)..":12:12|t", tostring(self.itemName))
   end
   self.cheevos = familiars[self.questID]
 
@@ -346,28 +347,27 @@
 
 -- run from OnShow if .isNew is set
 function WorldPlanPOIMixin:OnNew()
-  self:SetAlpha(0)
 
-  if WorldPlan.db.FadeWhileGrouped then
-    self.FadeIn.FadeIn:SetToAlpha(0.15)
-    self.PendingFade.FadeIn:SetToAlpha(0.15)
-    self.PendingFade.FadeIn:SetFromAlpha(0.15)
-  else
-    self.FadeIn.FadeIn:SetToAlpha(1)
-    self.PendingFade.FadeIn:SetToAlpha(1)
-    self.PendingFade.FadeIn:SetFromAlpha(1)
-  end
   if not self.isAnimating then
+    --qprint('|cFFFFFF00'.. self.title .. ' added to quest log.')
+    self:SetAlpha(0)
+    if WorldPlan.db.FadeWhileGrouped then
+      self.FadeIn.FadeIn:SetToAlpha(0.15)
+      self.PendingFade.FadeIn:SetToAlpha(0.15)
+      self.PendingFade.FadeOut:SetFromAlpha(0.15)
+    else
+      self.FadeIn.FadeIn:SetToAlpha(1)
+      self.PendingFade.FadeIn:SetToAlpha(1)
+      self.PendingFade.FadeOut:SetFromAlpha(1)
+    end
     self.isAnimating = true
-    WorldPlan:OnNext(function()
-      self.isNew = nil
-      self.FadeIn:Play()
-    end)
+    self.isNew = nil
+    self.FadeIn:Play()
   end
 end
 
 function WorldPlanPOIMixin:OnShow ()
-  qprint('|cFFFFFF00["'..tostring(self.title)..'"]|r:OnShow() update:', self.isStale, 'new:', self.isNew, 'animation:', self.isAnimating)
+  qprint('|cFFFFFF00'..tostring(self:GetName())..':OnShow()|r update:', self.isStale, 'new:', self.isNew, 'animation:', self.isAnimating)
   -- pop this on principle
 
   if self.isNew or self.isStale then
@@ -377,22 +377,20 @@
 
   -- is it a new quest?
   if self.isNew then
-    WorldPlan:print('|cFF0088FF', self.title, '|r', self.isNew and 'new', self.isStale and 'stale', self.isAnimating and 'animating')
+    print('|cFFFFFF00popping new pin handler')
     self:OnNew()
-    -- trap new but animating pins here
-  else
-    -- hard show existing self
-    --print('refresh #', questID, 'filtered:', self.filtered, 'hasUpdate', self.hasUpdate)
-    self:Show()
+  elseif not self.isAnimating then
+    self:SetAlpha(1)
   end
 
+  --WorldPlan:print(self:GetAlpha())
 
 end
 function WorldPlanPOIMixin:OnHide()
-  qprint('|cFFFFFF00["'..tostring(self.title)..'"]|r:OnHide()')
+  --qprint('|cFFFFFF00["'..tostring(self.title)..'"]|r:OnHide()')
   if not self:IsShown() then
     self.isAnimating = nil
-    self:SetAlpha(0)
+    self:SetAlpha(1)
   end
 
 end
@@ -439,11 +437,9 @@
 local PIN_UPDATE_DELAY = .016
 local TOP_PIN_ID
 function WorldPlanPOIMixin:OnUpdate (sinceLast)
-
-  if self.isStale then
-    print('|cFFFFFF00push poi update')
-    self:Refresh()
-    return
+  if self.isNew then
+    print('|cFFFFFF00push new poi stuff')
+    self:OnNew()
   end
   -- control update check intervals
   self.throttle = (self.throttle or PIN_UPDATE_DELAY) - sinceLast
@@ -453,6 +449,11 @@
   else
     return
   end
+  if self.isStale and not self.isAnimating then
+    print('|cFFFFFF00push poi update')
+    self:Refresh()
+    return
+  end
 
   -- query for reward data if it wasn't found in the original scan
   local questID = self.questID
@@ -505,7 +506,7 @@
 
 
   local questID = self:GetID()
-  local style,subStyle =  self:GetTypeInfo(self.rewardType)
+  local style,subStyle =  WorldPlanQuests:GetTypeInfo(self.rewardType)
   if self.filtered then
     subStyle = style.minimized
   end
@@ -582,10 +583,18 @@
 
 
   self:UpdateSize()
+
   self.isStale = nil
+
 end
 
-
+local cvar_check = {
+  [REWARD_CASH] = 'worldQuestFilterGold',
+  [REWARD_ARTIFACT_POWER] = 'worldQuestFilterArtifactPower',
+  [REWARD_CURRENCY] = 'worldQuestFilterOrderResources',
+  [REWARD_REAGENT]= 'worldQuestFilterProfessionMaterials',
+  [REWARD_GEAR] = 'worldQuestFilterEquipment',
+}
 
 
 function QuestPOI:IsShowable ()
@@ -598,14 +607,16 @@
 
 
   self.questId  = self:GetID()
-  if not (WorldMap_DoesWorldQuestInfoPassFilters(self, false, true)) then
-    self.filtered = true
-  end
-
-  for filterKey, value in pairs(WorldPlan.UsedFilters) do
-    if self[filterKey] ~= value then
+  if self.rewardType then
+    if cvar_check[self.rewardType] and not GetCVarBool(cvar_check[self.rewardType]) then
       self.filtered = true
     end
+  else
+    for filterKey, value in pairs(WorldPlan.UsedFilters) do
+      if self[filterKey] ~= value then
+        self.filtered = true
+      end
+    end
   end
 
   if not TQ_IsActive(self.questID) then
@@ -678,7 +689,9 @@
     tag:Hide()
   end
 
-  --qprint('using mask:', mask, self.name )
+  qprint('using mask:', pinMask, self.name )
   iconBorder:SetMask(pinMask)
   trackingBorder:SetMask(pinMask)
+  iconBorder:SetTexture(iconBorder:GetTexture())
+  trackingBorder:SetTexture(trackingBorder:GetTexture())
 end
\ No newline at end of file
--- a/WorldPlan.lua	Wed Nov 02 19:04:47 2016 -0400
+++ b/WorldPlan.lua	Thu Nov 03 17:29:15 2016 -0400
@@ -11,9 +11,12 @@
   QuestsByID = {},
   TaskQueue = {},
 }
+WorldPlanPOIMixin = {}
 local WorldPlan = WorldPlanCore
 
 local print = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
+
+local mprint = DEVIAN_WORKSPACE and function(...) _G.print('Canvas', ...) end or function() end
 local WP_VERSION = "1.0"
 local tinsert, pairs, floor = table.insert, pairs, floor
 local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
@@ -168,9 +171,14 @@
   if event == 'ADDON_LOADED' then
     local addon = ...
     if addon == "Blizzard_FlightMap" then
-      print('do mixin junk')
-      self.OnFlightMapLoaded()
+      mprint('sending data provider')
+      local dataProvider = Mixin(MapCanvasDataProviderMixin, WorldPlanDataProvider)
+      WorldPlanDataPinMixin = Mixin(MapCanvasPinMixin, WorldPlanDataPinMixin)
+      for k,v in pairs(dataProvider) do
+        mprint((v == WorldPlanDataProvider[k]) and ('|cFF00FF00'..tostring(k)..'|r') or ('|cFFFF4400'..tostring(k)..'|r'))
+      end
 
+      FlightMapFrame:AddDataProvider(dataProvider)
     end
     if IsLoggedIn() and not self.initialized then
       self:Setup()
@@ -179,8 +187,8 @@
     if event == 'WORLD_MAP_UPDATE' then
       self.currentMapID = GetCurrentMapAreaID()
       self.isContinentMap = (self.currentMapID == BROKEN_ISLES_ID)
-      self:print('|cFFFF4400currentMapID =', self.currentMapID)
-      --self.isStale = true
+      --self:print('|cFFFF4400currentMapID =', self.currentMapID)
+      self.isStale = true
     end
 
     for i, module in ipairs(self.modules) do
@@ -196,7 +204,7 @@
 
 
   tinsert(self.TaskQueue, func)
-  self:print('|cFF00FF00adding scheduled task #', #self.TaskQueue)
+  --self:print('|cFF00FF00adding scheduled task #', #self.TaskQueue)
 end
 
 function WorldPlanCore:OnUpdate()
@@ -410,43 +418,7 @@
 end
 
 --------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
-
-
--- data provider manipulations for the taxi map
-WorldPlan.OnFlightMapLoaded = function()
-  if true then return end
-  -- todo: figure out how to layer inside the map canvas
-  local res = {}
-  local t = {}
-  for k,v in pairs(FlightMapFrame) do
-    tinsert(res, tostring(k))
-  end
-
-  table.sort(res)
-  for i, k in ipairs(res) do
-    print(k)
-  end
-  hooksecurefunc(FlightMapFrame, 'RefreshAll', function(self)
-    print('|cFF0088FFWQDP RefreshAllData ', GetTime())
-
-    WorldPlan:GetPinsForMap(self:GetMapID())
-
-    for pin in self:EnumerateAllPins() do
-      if pin.worldQuest then
-        --print('got pin #', pin.questID)
-        local wp = self.QuestsByID[pin.questID]
-        if wp then
-          wp:ClearAllPoints()
-          wp:SetParent(FlightMapFrame.ScrollContainer)
-          wp:SetFrameStrata('MEDIUM')
-          wp:SetPoint('CENTER', pin, 'CENTER')
-          wp:Show()
-        end
-      end
-    end
-  end)
-end
+-------------------
 
 
 
@@ -465,4 +437,4 @@
   SetTimedCallbackForAllPins(5, function(self) self.PendingFade:Play() end)
   SetTimedCallbackForAllPins(8, function(self) self.PendingFade:Stop() end)
 end
---%end-debug%
+--%end-debug%
\ No newline at end of file
--- a/WorldPlan.toc	Wed Nov 02 19:04:47 2016 -0400
+++ b/WorldPlan.toc	Thu Nov 03 17:29:15 2016 -0400
@@ -13,3 +13,6 @@
 WorldQuests.xml
 FilterBar.xml
 ClassPlan.xml
+ClassPlanMissions.xml
+ClassPlanShipments.xml
+ClassPlanFollowers.xml
\ No newline at end of file
--- a/WorldPlan.xml	Wed Nov 02 19:04:47 2016 -0400
+++ b/WorldPlan.xml	Thu Nov 03 17:29:15 2016 -0400
@@ -155,4 +155,8 @@
     </Scripts>
   </Frame>
 
+  <Frame name="WorldPlanPinContainer" mixin="WorldPlanDataPinMixin" hidden="true" flattenRenderLayers="true" frameStrata="MEDIUM" enableMouseMotion="true" virtual="true">
+    <Size x="50" y="50"/>
+  </Frame>
+
 </Ui>
\ No newline at end of file
--- a/WorldQuests.lua	Wed Nov 02 19:04:47 2016 -0400
+++ b/WorldQuests.lua	Thu Nov 03 17:29:15 2016 -0400
@@ -3,6 +3,8 @@
 -- Created: 11/2/2016 3:40 PM
 -- %file-revision%
 
+WorldPlanDataProvider = {}
+WorldPlanDataPinMixin = {}
 WorldPlanQuestsMixin = {
   QuestsByZone = {},
   QuestsByID = {},
@@ -18,6 +20,7 @@
 local qprint = DEVIAN_WORKSPACE and function(...) _G.print('POI', ...) end or function() end
 local wqprint = DEVIAN_WORKSPACE and function(...) _G.print('WorldQuests', ...) end or function() end
 local wprint = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end
+local mprint = DEVIAN_WORKSPACE and function(...) _G.print('Canvas', ...) end or function() end
 
 
 local PinBaseIndex = 1600
@@ -178,19 +181,12 @@
 -- create of update quest pins for a map and its underlying zones
 function WorldQuests:RefreshData (mapID)
   local print = wqprint
-  mapID = mapID or GetCurrentMapAreaID()
-  superTrackedID = GetSuperTrackedQuestID()
+  mapID = mapID or WorldPlan.currentMapID
   if not mapID then
     -- info not available yet
     return
   end
 
-  if not self:IsVisible() then
-    self.isStale = true
-    print('frame closed, do it later')
-    return
-  end
-
 
     print('|cFF00FF88'..self:GetName()..':RefreshData()|r', 'map:', mapID, 'realMap:', GetCurrentMapAreaID())
 
@@ -204,7 +200,7 @@
     end
     self.fullSearch = nil
   elseif self.QuestsByZone[mapID] then
-    local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID)
+    local taskInfo = TQ_GetQuestsForPlayerByMapID(mapID, WorldPlan.currentMapID)
     local numQuests = 0
     if taskInfo and #taskInfo >= 1 then
       print('|cFF00FFFF  Zone:|r', mapID, GetMapNameByID(mapID), #taskInfo)
@@ -232,7 +228,7 @@
 
 end
 
-function WorldQuests:Refresh()
+function WorldQuests:Refresh(forced)
   local print = wqprint
   print('|cFF00FF88'..self:GetName()..':Refresh()|r')
   if not self:IsVisible() then
@@ -288,9 +284,9 @@
     for questID, pin in pairs(pins) do
       pin:IsShowable()
       if pin.used then
-        pin.hasUpdate = true
-        pin:SetFrameLevel(PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
-        print('level', PinBaseIndex+ (pin.whiteListed and 200 or 0) +numPins)
+        pin.isStale = true
+        pin:SetFrameLevel(PinBaseIndex+ numPins)
+        print('level', PinBaseIndex+ numPins)
         pin:SetAnchor(_G.WorldMapPOIFrame, currentMap, mapWidth, mapHeight)
         numPins = numPins + 1
       end
@@ -305,18 +301,14 @@
 function WorldQuests:Cleanup ()
   local print = wqprint
   local showQuestPOI = WorldPlan.db.EnablePins
-  WorldPlan:print('|cFFFFFF00'..self:GetName()..':Cleanup()|r')
+  print('|cFFFFFF00'..self:GetName()..':Cleanup()|r')
   -- continent or zone sizing
 
 
   numPins = 0
   for questID, pin in pairs(self.QuestsByID) do
-    -- can we show it?
     pin:SetShown((showQuestPOI and pin.used))
   end
-  print('   adding:', table.concat(debug_animate, ',' ))
-  print('  refresh:', table.concat(debug_show, ',' ))
-  print('  hiding:', table.concat(debug_hide, ',' ))
   self.isStale = nil
 end
 
@@ -324,3 +316,103 @@
   local pin = WorldQuests:GetPinByQuestID(questID)
   return pin:IsShowable()
 end
+
+
+
+
+function WorldPlanDataProvider:OnShow()
+  assert(self.ticker == nil);
+  self.ticker = C_Timer.NewTicker(10, function() self:RefreshAllData() end);
+end
+function WorldPlanDataProvider:OnHide()
+  self.ticker:Cancel();
+  self.ticker = nil;
+end
+
+function WorldPlanDataProvider:OnAdded(mapCanvas)
+  self.activePins = {};
+  self.owningMap = mapCanvas
+end
+
+
+
+function WorldPlanDataProvider:RefreshAllData()
+  local print = mprint
+  print('|cFFFF0088'..self.owningMap:GetName()..':RefreshAllData()|r')
+
+
+  local pinsToRemove = {};
+  for questId in pairs(self.activePins) do
+    pinsToRemove[questId] = true;
+  end
+
+  SetMapZoom(8)
+
+  local mapAreaID = self:GetMap():GetMapID();
+  for zoneIndex = 1, C_MapCanvas.GetNumZones(mapAreaID) do
+    local zoneMapID, zoneName, zoneDepth, left, right, top, bottom = C_MapCanvas.GetZoneInfo(mapAreaID, zoneIndex);
+    print(zoneMapID, zoneName)
+    if zoneDepth <= 1 then -- Exclude subzones
+    local taskInfo = C_TaskQuest.GetQuestsForPlayerByMapID(zoneMapID, mapAreaID);
+
+    if taskInfo then
+      for i, info in ipairs(taskInfo) do
+        if HaveQuestData(info.questId) then
+          if QuestUtils_IsQuestWorldQuest(info.questId) then
+            local pin = WorldPlanQuests:AcquirePin(info.questId, zoneMapID)
+            pin:RefreshData(info)
+            pin:IsShowable()
+            if pin.used then
+              print(i, pin.x, pin.y, pin.used, pin.isNew, pin.isStale, pin:IsShown(), pin:GetAlpha())
+              pinsToRemove[info.questId] = nil;
+
+              local frame = self.activePins[info.questId]
+              if not frame then
+                frame = self:GetMap():AcquirePin("WorldPlanPinContainer")
+                frame:SetAlphaLimits(1, 0.7, 1)
+                frame:SetScalingLimits(1, 3, 1.5);
+                frame:SetFrameLevel(1000 + self:GetMap():GetNumActivePinsByTemplate("WorldPlanPinContainer"));
+                frame:Show()
+                self.activePins[info.questId] = frame
+              end
+              frame:SetPosition(info.x, info.y)
+              frame.pin = pin
+
+              pin.isStale = true
+              pin:SetParent(frame)
+              pin:ClearAllPoints()
+              pin:SetPoint('CENTER', frame, 'CENTER')
+
+            end
+            pin:SetShown(pin.used)
+          end
+        end
+      end
+    end
+    end
+  end
+
+  for questId in pairs(pinsToRemove) do
+    self:GetMap():RemovePin(self.activePins[questId]);
+    self.activePins[questId] = nil;
+  end
+  self:GetMap():RemoveAllPinsByTemplate("WorldQuestPinTemplate");
+
+end
+
+function WorldPlanDataPinMixin:OnShow()
+  mprint('|cFFFFFF00'..tostring(self:GetName())..':OnShow()|r')
+end
+
+function WorldPlanDataPinMixin:OnMouseEnter ()
+  self.pin:OnEnter()
+end
+
+function WorldPlanDataPinMixin:OnMouseLeave ()
+  self.pin:OnLeave()
+end
+
+function WorldPlanDataPinMixin:RemoveAllData()
+  wipe(self.activePins);
+  self:GetMap():RemoveAllPinsByTemplate("WorldQuestPinTemplate");
+end
\ No newline at end of file