changeset 4:4c7e9efec4b5

fix order of operations regarding frame visibility checking
author Nenue
date Mon, 17 Oct 2016 12:59:24 -0400
parents c006ce87a147
children 4e1883842abf
files ClassPlan.lua ClassPlan.xml WorldPlan.xml
diffstat 3 files changed, 278 insertions(+), 253 deletions(-) [+]
line wrap: on
line diff
--- a/ClassPlan.lua	Sat Oct 15 09:54:56 2016 -0400
+++ b/ClassPlan.lua	Mon Oct 17 12:59:24 2016 -0400
@@ -1,9 +1,10 @@
-local wipe = table.wipe
+local wipe, tinsert, sort = table.wipe, tinsert, table.sort
 local pairs, ipairs = pairs, ipairs
+local floor, mod, time = floor, mod, time
 local GetTime = GetTime
 local GI_currentTime = time()
 
-
+local BOUND_FRAMES = {}
 local blockTemplate = {
   point = 'TOPLEFT',
   relativePoint ='TOPLEFT',
@@ -27,19 +28,29 @@
 }
 ClassPlanBlockMixin = {
   templateName = 'ClassPlanBlock',
-  events = {'GARRISON_MISSION_LIST_UPDATE', 'GARRISON_MISSION_FINISHED', 'GARRISON_MISSION_FINISHED'},}
+  events = {'GARRISON_MISSION_LIST_UPDATE', 'GARRISON_MISSION_STARTED', 'GARRISON_MISSION_FINISHED'},}
 ClassPlanShipmentMixin = {
   templateName = 'ClassPlanShipment',
   parent = false,
   point = 'TOPRIGHT',
   relativePoint ='TOPRIGHT',
-  events = {'GARRISON_LANDINGPAGE_SHIPMENTS', 'GARRISON_TALENT_UPDATE', "GARRISON_TALENT_COMPLETE", 'GARRISON_TALENT_COMPLETE', 'GARRISON_SHIPMENT_RECEIVED', "GARRISON_SHIPMENT_RECEIVED"},
+  events = {'GARRISON_LANDINGPAGE_SHIPMENTS', 'GARRISON_TALENT_UPDATE', "GARRISON_TALENT_COMPLETE", "GARRISON_SHIPMENT_RECEIVED"},
 }
 setmetatable(ClassPlanShipmentMixin, {__index = ClassPlanBlockMixin})
 local core, MissionsHandler, ShipmentsHandler = ClassOrderPlanCore, ClassPlanBlockMixin, ClassPlanShipmentMixin
 local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop
 
-
+local GetTimeLeftString = function(timeLeft)
+  local days = floor(timeLeft/(24*3600))
+  local hours = floor(mod(timeLeft, (24*3600)) / 3600)
+  local minutes = floor(mod(timeLeft, 3600) / 60)
+  local seconds = mod(timeLeft, 60)
+  if days >= 1 then
+    return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h ') or '')
+  else
+    return ((hours > 0) and (hours .. 'h ') or '') .. ((minutes > 0) and (minutes .. ' min') or '')
+  end
+end
 
 MissionsHandler.GetPlayerData = function(self)
   if not self.profile then
@@ -47,36 +58,36 @@
   end
   self.items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0)
 
-  if #self.items >= 1 then
-    wipe(self.profile.missions)
-    for index, data in ipairs(self.items) do
-      print('  ',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime))
-      tinsert(self.profile.missions, data)
-    end
-    print('items update pending')
-    self.isStale = true
+  wipe(self.profile.missions)
+  for index, data in ipairs(self.items) do
+    print('  ',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime))
+    tinsert(self.profile.missions, data)
   end
+  print('items update pending')
+  self.isStale = true
 
   if self:IsVisible() then
     self:Refresh()
   end
 end
 
+MissionsHandler.FreeBlock = function(self, block)
+end
+
 MissionsHandler.SortHandler = function (a,b)
   local result = false
-  if not a or not b then
-    result = 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
-      result = ( b.missionEndTime > a.missionEndTime)
-    end
-  end
-  return result
+  --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
+      return ( b.missionEndTime > a.missionEndTime)
+    --end
+  --end
 end
 
 
@@ -99,10 +110,37 @@
 ShipmentsHandler.SortHandler = function(a, b)
   if b.isComplete ~= a.isComplete then
     return a.isComplete and true or false
+  elseif a.shipmentsReady or b.shipmentsReady then
+    return (a.shipmentsReady or 0) > (b.shipmentsReady or 0)
+  else
+    return (a.creationTime) < (b.creationTime)
   end
-  return (a.creationTime) < (b.creationTime)
 end
 
+local AddShipmentInfo = function(self, shipmentType, name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID, followerID)
+  -- early login queries may return empty tables, causing the sorter to compare nil
+  if not creationTime then
+    return
+  end
+  print(shipmentType, name, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString)
+  tinsert(self.shipments,
+    {
+      shipmentType = shipmentType,
+      name = name,
+      icon = texture,
+      shipmentCapacity = shipmentCapacity,
+      shipmentsReady = shipmentsReady,
+      shipmentsTotal = shipmentsTotal,
+      creationTime = creationTime,
+      duration = duration,
+      timeleftString = timeleftString,
+      itemName = itemName,
+      itemIcon = itemIcon,
+      itemQuality = itemQuality,
+      itemID = itemID,
+      followerID = followerID,
+    })
+end
 ShipmentsHandler.GetPlayerData = function (self)
   if not self.profile then
     return
@@ -116,59 +154,21 @@
   --print('Buildings:')
   for i = 1, #buildings do
     local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID = C_Garrison.GetLandingPageShipmentInfo(buildingID);
-    tinsert(self.shipments,
-      {
-        shipmentType = 'Work Order',
-        name = name,
-        icon = texture,
-        shipmentCapacity = shipmentCapacity,
-        shipmentsReady = shipmentsReady,
-        shipmentsTotal = shipmentsTotal,
-        creationTime = creationTime,
-        duration = duration,
-        timeleftString = timeleftString,
-        itemName = itemName,
-        itemIcon = itemIcon,
-        itemQuality = itemQuality,
-        itemID = itemID
-      })
+    AddShipmentInfo(self, 'Building', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID)
   end
 
   --print('Follower:')
   local followerShipments = C_Garrison.GetFollowerShipments(garrisonType);
   for i = 1, #followerShipments do
     local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = C_Garrison.GetLandingPageShipmentInfoByContainerID(followerShipments[i]);
-    tinsert(self.shipments,
-      {
-        shipmentType = '',
-        name = name,
-        icon = texture,
-        shipmentCapacity = shipmentCapacity,
-        shipmentsReady = shipmentsReady,
-        shipmentsTotal = shipmentsTotal,
-        creationTime = creationTime,
-        duration = duration,
-        timeleftString = timeleftString,
-        followerID = followerID,
-      })
+    AddShipmentInfo(self, 'Follower', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, nil, nil, nil, nil, followerID)
   end
 
   --print('Loose:')
   local looseShipments = C_Garrison.GetLooseShipments(garrisonType)
   for i = 1, #looseShipments do
     local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = C_Garrison.GetLandingPageShipmentInfoByContainerID(looseShipments[i]);
-    tinsert(self.shipments,
-      {
-        shipmentType = '',
-        name = name,
-        icon = texture,
-        shipmentCapacity = shipmentCapacity,
-        shipmentsReady = shipmentsReady,
-        shipmentsTotal = shipmentsTotal,
-        creationTime = creationTime,
-        duration = duration,
-        timeleftString = timeleftString,
-      })
+    AddShipmentInfo(self, 'Follower', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString)
   end
 
   local talentTrees = C_Garrison.GetTalentTrees(garrisonType, select(3, UnitClass("player")));
@@ -179,18 +179,8 @@
     for treeIndex, tree in ipairs(talentTrees) do
       for talentIndex, talent in ipairs(tree) do
         local showTalent = false;
-        if (talent.isBeingResearched) then
-          showTalent = true;
-        end
-        if (talent.id == completeTalentID) then
-          showTalent = true;
-        end
-        if (showTalent) then
-          print(talent.name)
-          talent.creationTime = talent.researchStartTime
-          talent.duration = talent.researchDuration
-          talent.shipmentType = 'Talent: '
-          tinsert(self.shipments, talent)
+        if (talent.isBeingResearched) or (talent.id == completeTalentID) then
+          AddShipmentInfo(self, 'Talent', talent.name, talent.icon, 1, (talent.isBeingResearched and 0 or 1), 1, talent.researchStartTime, talent.researchDuration, talent.timeleftString)
         end
       end
     end
@@ -198,11 +188,10 @@
 
   self.profile.shipments = self.profile.shipments or {}
   if #self.shipments >= 1 then
-
-
     wipe(self.profile.shipments)
     for index, data in ipairs(self.shipments) do
-      print(' ', data.shipmentType .. data.name, data.creationTime, data.duration)
+
+      --DEFAULT_CHAT_FRAME:AddMessage(data.shipmentType ..' '.. tostring(data.name) ..' '.. tostring(data.creationTime) ..' '.. tostring(data.duration))
       tinsert(self.profile.shipments, data)
     end
     self.isStale = true
@@ -219,9 +208,58 @@
   self:RegisterEvent('PLAYER_ENTERING_WORLD')
   self:RegisterEvent('ADDON_LOADED')
   self:RegisterEvent('PLAYER_REGEN_ENABLED')
+  -- Blizzard_GarrisonUI already fires a shipment data request for GARRISON_SHIPMENT_RECEIVED; this is unlikely to
+
 
   self:AddHandler('missions', MissionsHandler)
   self:AddHandler('shipments', ShipmentsHandler)
+
+
+  self:Reanchor()
+end
+local parentFrames = {'VeneerWorldState', 'OrderHallCommandBar'}
+function core:Reanchor()
+
+
+  self:ClearAllPoints()
+
+  self.anchorParent = UIParent
+  for i, name in ipairs(parentFrames) do
+    local frame = _G[name]
+    if frame then
+      if not BOUND_FRAMES[frame] then
+        BOUND_FRAMES[frame] = {visible = frame:IsVisible()}
+        hooksecurefunc(frame, 'Show', function()
+          BOUND_FRAMES[frame].visible = true
+          print(frame:GetName(), 'Show', 'reanchor trigger')
+          self:Reanchor()
+        end)
+        hooksecurefunc(frame, 'Hide', function()
+          BOUND_FRAMES[frame].visible = false
+          print(frame:GetName(), 'Hide', 'reanchor trigger')
+          self:Reanchor()
+        end)
+      end
+      print('f:', frame:GetName(), frame:IsVisible())
+      if BOUND_FRAMES[frame].visible then
+        self.anchorParent = frame
+        break
+      end
+    end
+  end
+  print('|cFFFF8800Using ' .. tostring(self.anchorParent:GetName()) .. ' as anchor point')
+
+  if self:IsVisible() then
+    self:SetPoint('TOP', ClassPlanButton, 'BOTTOM', 0, 0)
+    ClassPlanButton.Background:Show()
+    ClassPlanButton:SetWidth(600)
+  else
+    ClassPlanButton.Background:Hide()
+    ClassPlanButton:SetWidth(200)
+  end
+
+  ClassPlanButton:SetPoint('TOP', self.anchorParent, (self.anchorPoint == UIParent) and 'TOP' or 'BOTTOM', 0, 0)
+
 end
 
 function core:AddHandler(name, prototype)
@@ -246,40 +284,44 @@
   self.sortedItems[name] = {}
 end
 
+function core:Setup()
+  if IsLoggedIn() then
+    WorldPlanData.OrderHall = WorldPlanData.OrderHall or {}
+    self.data = WorldPlanData.OrderHall
+    self.data.characters = self.data.characters or {}
+
+    local name, realm = UnitName('player')
+    realm  = realm or GetRealmName()
+    self.profileKey = name .. '-' .. realm
+    if not self.data.characters[self.profileKey] then
+      self.data.characters[self.profileKey] = {}
+    end
+    self.profile = self.data.characters[self.profileKey]
+
+    self.profile.shipments = self.profile.shipments or {}
+    self.profile.missions = self.profile.missions or {}
+    self.profile.classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))]
+
+    if self.data.IsShown then
+      self:Show()
+    end
+    self.initialized = true
+  end
+end
+
 function core:OnEvent (event, ...)
   print(event)
   if event == 'UNIT_PORTRAIT_UPDATE' then
     SetPortraitTexture(self.portrait, 'player')
   elseif event == 'PLAYER_LOGIN' then
     if not self.initialized then
-      if IsLoggedIn() then
-        WorldPlanData.OrderHall = WorldPlanData.OrderHall or {}
-        self.data = WorldPlanData.OrderHall
-
-
-        local name, realm = UnitName('player')
-        realm  = realm or GetRealmName()
-        self.profileKey = name .. '-' .. realm
-        if not self.data[self.profileKey] then
-          self.data[self.profileKey] = {}
-        end
-        self.profile = self.data[self.profileKey]
-
-        self.profile.shipments = self.profile.shipments or {}
-        self.profile.missions = self.profile.missions or {}
-        self.profile.classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))]
-
-        C_Garrison.RequestLandingPageShipmentInfo();
-
-        if self.data.IsShown then
-          self:Show()
-        end
-        self.initialized = true
-      end
+      self:Setup()
     end
-  elseif self.events[event] then
+  elseif self.initialized and self.events[event] then
+    local numCalls = 0
     for ptype, eventFunc in pairs(self.events[event]) do
-      print('|cFF88FF00' .. tostring(ptype) .. '|r:GetPlayerData()')
+      numCalls = numCalls + 1
+      print('|cFF88FF00' .. tostring(ptype) .. '|r:GetPlayerData() --', numCalls)
       eventFunc(self, event)
     end
   end
@@ -288,6 +330,17 @@
 function core:UpdateNotifications()
 end
 
+
+local SetOwnerData = function(self, data)
+  local name, realm = string.match(data.profileKey, "(.+)%-(.+)")
+  local ownerText = '|c'.. data.classColor.colorStr .. name .. '|r'
+  if realm ~= GI_currentRealm then
+    ownerText = ownerText .. ' (' .. realm .. ')'
+  end
+  self.Owner:SetText(ownerText)
+  self.Background:SetColorTexture(data.classColor.r, data.classColor.g, data.classColor.b)
+end
+
 function core:RefreshItems(configKey, prototype)
   local sortedItems = self.sortedItems[configKey]
 
@@ -303,6 +356,7 @@
     if not block then
       block = CreateFrame('Button', nil, self, prototype.templateName)
       block:SetID(i)
+      block.handler = prototype
       prototype.numBlocks = prototype.numBlocks + 1
 
       if prototype.lastBlock then
@@ -316,7 +370,14 @@
 
     totalHeight = totalHeight + block:GetHeight()
     block.lastProfile = lastProfile
+    for k,v in pairs(data) do
+      if type(block[k]) ~= 'function' then
+        block[k] = v
+      end
+    end
     block:Refresh(data)
+    SetOwnerData(block, data)
+
     block:Show()
     lastProfile = data.profileKey
   end
@@ -342,18 +403,7 @@
     self.currentHeight = max(itemsHeight, self.currentHeight)
   end
 
-  if OrderHallCommandBar and OrderHallCommandBar:IsVisible() then
-    self:ClearAllPoints()
-    self:SetPoint('TOP', OrderHallCommandBar, 'BOTTOM')
-  else
-
-    local posX = self.data.posX or 0
-    local posY = self.data.posY or -24
-    local point = self.point or 'TOP'
-    local relativePoint = self.point or 'TOP'
-    self:SetPoint(point, UIParent, relativePoint, posX, posY)
-  end
-
+  self:Reanchor()
   self:SetHeight(self.currentHeight)
 end
 
@@ -380,20 +430,25 @@
     print('updating items on show')
     self:Refresh()
   end
-  ClassPlanButton:SetPoint('TOP', self, 'TOP', 0, 0)
+  -- grab this at least once
+  C_Garrison.RequestLandingPageShipmentInfo();
+  ClassPlanButton.Background:Show()
+  ClassPlanButton.Grip:SetShown(true)
 end
 function core:OnHide()
-  ClassPlanButton:SetPoint('TOP', UIParent, 'TOP', 0, 0)
+  ClassPlanButton.Background:Hide()
+  ClassPlanButton.Grip:SetShown(false)
 end
 
 local GI_profileKey, GI_profile, GI_isMine
-local GetItemList = function (source, dest, onGetItem)
+local defaultClassColor = {r = 0.7, g = 0.7, b =0.7, colorStr = "ffffffff"}
+local DoItemList = function (source, dest, onGetItem)
   if not source then
     return
   end
   local numItems = 0
   for index, data in ipairs(source) do
-    data.classColor = GI_profile.classColor or {r = 0.7, g = 0.7, b =0.7}
+    data.classColor = GI_profile.classColor or defaultClassColor
     data.profileKey = GI_profileKey
     data.isMine = GI_isMine
     if onGetItem then
@@ -412,49 +467,28 @@
   for key, sortedItems in pairs(self.sortedItems) do
     wipe(sortedItems)
     local ptype = self.prototypes[key]
-    print(  'object:', ptype)
+    --print(  'object:', ptype)
     for name, profile in pairs(self.data.characters) do
       GI_profileKey = name
       GI_profile = profile
       GI_isMine = (profile == self.profile)
-
-        local results = GetItemList(profile[key], sortedItems, ptype.OnGetItem)
-        print(' - ', name, results, 'items')
-
+      local results = DoItemList(profile[key], sortedItems, ptype.OnGetItem)
+      --print(' - ', name, results, 'items')
     end
 
     if ptype.SortHandler then
-      print(' sorting', key, #sortedItems)
-      table.sort(sortedItems, ptype.SortHandler)
+      sort(sortedItems, ptype.SortHandler)
     end
   end
 end
 
-
-
-function core:UpdateItems ()
-end
-
 function MissionsHandler:OnComplete()
-  self.data.isComplete = true
+  self.isComplete = true
   self:Refresh()
 end
 
-local GetTimeLeftString = function(timeLeft)
-
-  local days = floor(timeLeft/(24*3600))
-  local hours = floor(mod(timeLeft, (24*3600)) / 3600)
-  local minutes = floor(mod(timeLeft, 3600) / 60)
-  local seconds = mod(timeLeft, 60)
-  if days >= 1 then
-    return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h ') or '')
-  else
-    return ((hours > 0) and (hours .. 'h ') or '') .. ((minutes > 0) and (minutes .. ' min') or '')
-  end
-end
-
 function MissionsHandler:OnUpdate()
-  if self.data.isComplete then
+  if self.isComplete then
     return
   end
 
@@ -477,45 +511,30 @@
   end
 end
 
-local SetClassColors = function(self, data)
+function MissionsHandler:Refresh()
 
-  if self.lastProfile ~= data.profileKey then
-    self.Owner:SetText(data.profileKey)
-    self.Owner:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b)
-  else
-    self.Owner:SetText(nil)
-  end
-  self.Background:SetColorTexture(data.classColor.r, data.classColor.g, data.classColor.b,
-    (data.isComplete and 0.5 or 0.1))
-end
-
-function MissionsHandler:Refresh(data)
-  data = data or self.data
-  self.data = data
-
-  self.isComplete = data.isComplete
-  self.missionEndTime = data.missionEndTime
 
   local r,g,b = 1, 1, 1
-  if data.isRare then
+  if self.isRare then
     r,g,b = 0.1, 0.4, 1
   end
 
 
   --self.missionData = data
-  self.Label:SetText(data.name)
+  self.Label:SetText(self.name)
   self.Label:SetTextColor(r, g, b)
 
-  if #data.rewards >= 1 then
-    self.Icon:SetTexture(data.rewards[1].icon or GetItemIcon(data.rewards[1].itemID))
-    self.rewardInfo = data.rewards[1]
+  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(data.typeAtlas, false)
+    self.Icon:SetAtlas(self.typeAtlas, false)
   end
   if self.isComplete then
     self.TimeLeft:SetText('Complete!')
   end
-  SetClassColors(self, data)
+
+  self.Background:SetAlpha(self.isComplete and 1 or 0.1)
 end
 
 
@@ -534,8 +553,7 @@
 
 
 
-function ShipmentsHandler:Refresh(data)
-  data = data or self.data
+function ShipmentsHandler:Refresh()
 
   --[[
   self.icon = data.icon
@@ -560,41 +578,35 @@
 
   --]]
 
-  self.Icon:SetTexture(data.icon)
-  self.data = data
+  self.Icon:SetTexture(self.icon)
 
-
-  local isComplete = data.isComplete
-
-
-
-  self.Name:SetText(data.shipmentType .. data.name)
-  self.Count:SetText(data.shipmentsReady)
-  self.Done:SetShown(data.shipmentsReady and (data.shipmentsReady >= 1))
+  self.Name:SetText(self.name)
+  self.Count:SetText(self.shipmentsReady)
+  self.Done:SetShown(self.shipmentsReady and (self.shipmentsReady >= 1))
 
 
   -- flag as complete
-  if ( data.shipmentsReady == data.shipmentsTotal ) and (not data.isBeingResearched) then
+  if ( self.shipmentsReady == self.shipmentsTotal ) and (not self.isBeingResearched) then
     self.Swipe:SetCooldownUNIX(0, 0);
     self.Done:Show();
-    isComplete = true
+    self.isComplete = true
   else
-    self.Swipe:SetCooldownUNIX(data.creationTime or 0 , data.duration or 0);
+    self.Swipe:SetCooldownUNIX(self.creationTime or 0 , self.duration or 0);
   end
 
-  data.isComplete = isComplete
+  local hasPickups = (self.isComplete or (self.shipmentsTotal and (self.shipmentsReady > 0)))
+  self.Background:SetAlpha(hasPickups and 1 or 0.1)
+end
+local time = time
+function ShipmentsHandler:OnUpdate()
 
-  SetClassColors(self, data)
-end
-function ShipmentsHandler:OnUpdate()
-  local data = self.data
-  if (data.shipmentsReady and data.shipmentsTotal) and (data.shipmentsReady ~= data.shipmentsTotal) then
-    local timeLeft = data.creationTime + data.duration - time()
-    self.TimeLeft:SetText('Next: '.. GetTimeLeftString(timeLeft) .. ' |cFFFFFF00'..data.shipmentsTotal..' orders|r')
-  elseif data.isStale then
+  if (self.shipmentsReady and self.shipmentsTotal) and (self.shipmentsReady ~= self.shipmentsTotal) then
+    local timeLeft = self.creationTime + self.duration - time()
+    self.TimeLeft:SetText('Next: '.. GetTimeLeftString(timeLeft) .. ' |cFFFFFF00'..self.shipmentsTotal..' orders|r')
+  elseif self.isStale then
     self.TimeLeft:SetText('|cFFFF0000Needs refresh|r')
-  elseif data.isBeingResearched then
-    self.TimeLeft:SetText(GetTimeLeftString(data.researchStartTime + data.researchDuration - time()))
+  elseif self.isBeingResearched then
+    self.TimeLeft:SetText(GetTimeLeftString(self.researchStartTime + self.researchDuration - time()))
   else
     self.TimeLeft:SetText('Complete!')
   end
@@ -602,10 +614,13 @@
 end
 
 function ShipmentsHandler:OnEnter()
-  local data = self.data
-  if ( data.shipmentsReady and data.shipmentsTotal ) then
+
+  if ( self.shipmentsReady and self.shipmentsTotal ) then
     GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
-    GameTooltip:AddLine(data.shipmentsReady .. ' of '.. data.shipmentsTotal)
+
+    GameTooltip:AddLine(self.Owner:GetText(), self.Owner:GetTextColor())
+    GameTooltip:AddLine(self.shipmentType)
+    GameTooltip:AddLine(self.shipmentsReady .. ' of '.. self.shipmentsTotal)
     GameTooltip:Show()
   end
 end
@@ -618,13 +633,6 @@
 
 function ShipmentsHandler:OnClick(button)
   if button == 'RightButton' then
-    for name, profile in pairs(ClassOrderPlan.data) do
-      for index, shipment in pairs(profile.shipments) do
-        if shipment == self.data then
-          profile.shipments[index] = nil
-          ClassOrderPlan:Refresh()
-        end
-      end
-    end
+    self.handler:FreeBlock(self)
   end
 end
\ No newline at end of file
--- a/ClassPlan.xml	Sat Oct 15 09:54:56 2016 -0400
+++ b/ClassPlan.xml	Mon Oct 17 12:59:24 2016 -0400
@@ -6,40 +6,22 @@
   <Font name="ClassPlanFont" font="Interface\AddOns\Veneer\Font\ArchivoNarrow-Regular.ttf" height="14" outline="NORMAL" virtual="true" />
   <Font name="ClassPlanNumberFont" font="Interface\AddOns\Veneer\Font\ArchivoNarrow-Bold.ttf" height="14" outline="NORMAL" virtual="true" />
 
-  <Frame name="ClassOrderPlan" mixin="ClassOrderPlanCore" parent="UIParent" hidden="true">
-    <Size x="600" y="40" />
-    <Anchors>
-      <Anchor point="TOP" />
-    </Anchors>
-    <Scripts>
-      <OnLoad method="OnLoad" />
-      <OnEvent method="OnEvent" />
-      <OnShow method="OnShow" />
-      <OnHide method="OnHide" />
-    </Scripts>
-    <Layers>
-      <Layer level="ARTWORK">
-        <Texture parentKey="portrait">
-          <Size x="40" y="40" />
-          <Anchors>
-            <Anchor point="TOPLEFT" />
-
-          </Anchors>
-        </Texture>
-      </Layer>
-    </Layers>
-  </Frame>
-
-  <Button name="ClassPlanButton" parent="UIParent">
-    <Size x="400" y="16" />
+  <Button name="ClassPlanButton" parent="UIParent" frameStrata="HIGH">
+    <Size x="600" y="16" />
     <Anchors>
       <Anchor point="TOP" relativePoint="BOTTOM" relativeTo="ClassOrderPlan" />
       <Anchor point="LEFT" relativeTo="ClassOrderPlan" />
       <Anchor point="RIGHT" relativeTo="ClassOrderPlan" />
     </Anchors>
     <Layers>
+      <Layer level="BACKGROUND">
+        <Texture setAllPoints="true" parentKey="Background" hidden="true">
+          <Color a="1" r="0" g="0" b="0" />
+        </Texture>
+      </Layer>
       <Layer level="ARTWORK">
-        <Texture alphaMode="BLEND" file="Interface\RaidFrame\Raid-Move-Down">
+
+        <Texture parentKey="Grip" alphaMode="BLEND" file="Interface\RaidFrame\Raid-Move-Down">
           <Anchors>
             <Anchor point="TOP" />
           </Anchors>
@@ -59,6 +41,36 @@
     </Scripts>
   </Button>
 
+  <Frame name="ClassOrderPlan" mixin="ClassOrderPlanCore" parent="UIParent" hidden="true">
+    <Size x="600" y="40" />
+    <Anchors>
+      <Anchor point="TOP" />
+    </Anchors>
+    <Scripts>
+      <OnLoad method="OnLoad" />
+      <OnEvent method="OnEvent" />
+      <OnShow method="OnShow" />
+      <OnHide method="OnHide" />
+    </Scripts>
+    <Layers>
+      <Layer level="BACKGROUND">
+        <Texture parentKey="Background" setAllPoints="true">
+          <Color a="0.5" r="0" b="0" g="0" />
+        </Texture>
+      </Layer>
+      <Layer level="ARTWORK">
+        <Texture parentKey="portrait">
+          <Size x="40" y="40" />
+          <Anchors>
+            <Anchor point="TOPLEFT" />
+
+          </Anchors>
+        </Texture>
+      </Layer>
+    </Layers>
+  </Frame>
+
+
   <Button name="ClassPlanBlock" mixin="ClassPlanBlockMixin" virtual="true" hidden="true">
     <Size x="400" y="32" />
     <Scripts>
@@ -79,12 +91,13 @@
           <Anchors>
             <Anchor point="TOPLEFT" />
           </Anchors>
+          <TexCoords left="0.15" right=".85" top="0.15" bottom="0.85" />
         </Texture>
       </Layer>
       <Layer level="OVERLAY">
         <FontString name="$parentLabel" inherits="ClassPlanFont" parentKey="Label" text="base text">
           <Anchors>
-            <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeKey="$parent.Icon" x="4" y="0" />
+            <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeKey="$parent.Icon" x="4" y="-2" />
           </Anchors>
         </FontString>
         <FontString name="$parentTimeLeft" inherits="ClassPlanNumberFont" parentKey="TimeLeft" text="base text">
@@ -92,16 +105,16 @@
             <Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeKey="$parent.Label" x="4" y="-2" />
           </Anchors>
         </FontString>
-        <FontString name="$parentOwner" inherits="ClassPlanFont" parentKey="Owner" text="base text">
-          <Anchors>
-            <Anchor point="TOPRIGHT" />
-          </Anchors>
-        </FontString>
       </Layer>
       <Layer level="HIGHLIGHT">
         <Texture setAllPoints="true" alphaMode="ADD">
           <Color a="1" r="0.1" g="0.1" b="0.1" />
         </Texture>
+        <FontString name="$parentOwner" inherits="ClassPlanFont" parentKey="Owner" text="base text">
+          <Anchors>
+            <Anchor point="TOPRIGHT" x="-2" y="-2" />
+          </Anchors>
+        </FontString>
       </Layer>
     </Layers>
   </Button>
@@ -120,11 +133,12 @@
         <Texture parentKey="Background" setAllPoints="true" />
       </Layer>
       <Layer level="BACKGROUND" textureSubLevel="1">
-        <Texture parentKey="Icon" alpha="0.5" desaturated="true">
-          <Size x="30" y="30"/>
+        <Texture parentKey="Icon" alpha="1" desaturated="true">
+          <Size x="32" y="32"/>
           <Anchors>
             <Anchor point="LEFT"/>
           </Anchors>
+          <TexCoords left="0.15" right=".85" top="0.15" bottom="0.85" />
         </Texture>
       </Layer>
       <Layer level="BORDER">
@@ -154,20 +168,23 @@
             <Anchor point="BOTTOM" relativeKey="$parent.Icon" x="0" y="0"/>
           </Anchors>
         </FontString>
+      </Layer>
+      <Layer level="HIGHLIGHT">
+
         <FontString name="$parentOwner" inherits="WorldPlanFont" parentKey="Owner" text="base text">
           <Anchors>
-            <Anchor point="TOPRIGHT" />
+            <Anchor point="TOPRIGHT" x="-2" y="-2" />
           </Anchors>
         </FontString>
       </Layer>
     </Layers>
     <Frames>
-      <Cooldown parentKey="Swipe" reverse="true" hideCountdownNumbers="true">
+      <Cooldown parentKey="Swipe" inherits="CooldownFrameTemplate" reverse="true" hideCountdownNumbers="true">
         <Size x="32" y="32"/>
         <Anchors>
-          <Anchor point="LEFT"/>
+          <Anchor point="TOPLEFT"/>
+          <Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMLEFT" x="32" y="0" />
         </Anchors>
-        <SwipeTexture file="Interface\Garrison\GarrLanding-TradeskillTimerFill"/>
         <Scripts>
           <OnCooldownStart>
             self:Show()
--- a/WorldPlan.xml	Sat Oct 15 09:54:56 2016 -0400
+++ b/WorldPlan.xml	Mon Oct 17 12:59:24 2016 -0400
@@ -154,7 +154,7 @@
     </KeyValues>
     <Size x="600" y="24" />
     <Anchors>
-      <Anchor point="TOP" />
+      <Anchor point="TOPRIGHT" />
     </Anchors>
     <Scripts>
       <OnLoad method="OnLoad" />