changeset 2:a2396b03ce63

- identify action buttons by the associated QuestID instead of QuestLogIndex - deferred button placement in general to a self-destructing OnUpdate -- and defer self-destruct to a end of combat event if InCombatLockdown - tracker wrapper has an experience/reputation bar; the two elements "feel" related and it's a very simple info display
author Nenue
date Thu, 31 Mar 2016 01:38:47 -0400
parents b0447b382f36
children 3397aae1f44d
files ObjectiveEvents.lua ObjectiveFrame.lua ObjectiveInfo.lua ObjectiveTracker.lua ObjectiveTracker.xml ObjectiveUI.lua
diffstat 6 files changed, 299 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/ObjectiveEvents.lua	Wed Mar 30 16:30:49 2016 -0400
+++ b/ObjectiveEvents.lua	Thu Mar 31 01:38:47 2016 -0400
@@ -25,6 +25,9 @@
   RemoveQuestWatch(questLogIndex)
 end
 
+mod.OnQuestRemoved = function(_, questLogIndex, questID)
+end
+
 mod.OnQuestFromLocation = function(event) end
 
 mod.OnAddQuestWatch = function(questID)
--- a/ObjectiveFrame.lua	Wed Mar 30 16:30:49 2016 -0400
+++ b/ObjectiveFrame.lua	Thu Mar 31 01:38:47 2016 -0400
@@ -4,7 +4,9 @@
 -- @file-revision@ @file-hash@
 -- Created: 3/30/2016 12:49 AM
 local B = select(2,...).frame
-local ipairs, max, unpack = ipairs, max, unpack
+local ipairs, max, min, unpack, floor, pairs, tostring, type = ipairs, max, min, unpack, floor, pairs, tostring, type
+local IsResting, UnitXP, UnitXPMax, GetXPExhaustion = IsResting, UnitXP, UnitXPMax, GetXPExhaustion
+local UnitLevel, IsQuestWatched, UIParent = UnitLevel, IsQuestWatched, UIParent
 local CreateFrame = CreateFrame
 local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
 local print = B.print('Objectives')
@@ -13,9 +15,9 @@
 --------------------------------------------------------------------
 
 --- Upvalues
-local Wrapper = _G.VeneerObjectiveWrapper
+local Wrapper = VeneerObjectiveWrapper
 local Scroller = Wrapper.scrollArea
-local Scroll = _G.VeneerObjectiveScroll
+local Scroll = VeneerObjectiveScroll
 local orderedHandlers = mod.orderedHandlers
 local orderedNames = mod.orderedNames
 
@@ -31,82 +33,31 @@
 local titleSpacing, textSpacing = 4, 3
 local textIndent = 5
 local wrapperMaxWidth, wrapperMaxHeight = 280, 490 -- these are the hard bounds, actual *Height variables are changed
+local wrapperHeadFont, wrapperHeadSize, wrapperHeadOutline = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], 16, 'NONE'
 local headerFont, headerSize, headerHeight = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], 18, 24
-local headerOutline, headerColor = 'OUTLINE', {1,1,1,1}
+local headerOutline, headerColor, headerSpacing = 'OUTLINE', {1,1,1,1}, 2
 local wrapperPosition = {'RIGHT', UIParent, 'RIGHT', -84, 0}
 
-local Scroller_OnShow = function()
-  Wrapper.watchMoneyReasons = 0;
-  mod.UpdateWrapper()
-end
-
-local Scroller_OnHide = function()
-  local self = Wrapper
-  Wrapper:UnregisterAllEvents()
-  Wrapper:SetScript('OnEvent', nil)
-  Wrapper.Background:Hide()
-  Wrapper.BackgroundR:Hide()
-end
-
-local Scroller_OnMouseWheel = function(self, delta)
-  local r = Scroll:GetHeight() - Scroller:GetHeight()
-  local s = self:GetVerticalScroll() - delta * floor(r/5+.5)
-  if r == 0 then return end
-  if s >= r then
-    s = r
-  elseif s < 1 then
-    s = 0
-  end
-  self:SetVerticalScroll(s)
-  print(s, r, self:GetVerticalScroll())
-
-  mod.UpdateActionButtons()
-end
-
-local WrapperCloseButton_OnClick = function(self)
-  if Scroller:IsVisible() then
-    Scroller:Hide()
-  else
-    Scroller:Show()
-  end
-end
-
-
-mod.InitializeTrackers = function()
-  for i, name in ipairs(orderedNames) do
-    if not mod.orderedHandlers[i] then
-      if mod.Tracker(name, i) then
-        local handler = mod[name]
-
-        local tracker = CreateFrame('Frame', 'Veneer'..name..'Tracker', Scroll, 'VeneerTrackerTemplate')
-        tracker.header:SetText(handler.name)
-        tracker.header:SetHeight(headerHeight)
-        tracker.header:SetFont(headerFont, headerSize, headerOutline)
-        tracker.header:SetTextColor(unpack(headerColor))
-
-        handler.Tracker = tracker
-        mod.orderedTrackers[i] = tracker
-        mod.namedTrackers[name] = tracker
-        mod.indexedTrackers[handler] = tracker
-        print('created new tracker frames for new handler')
-      end
-    end
-  end
-
-  Scroller:SetScrollChild(Scroll)
-  Scroller:SetScript('OnMouseWheel', Scroller_OnMouseWheel)
-  Scroller:SetScript('OnShow', Scroller_OnShow)
-  Scroller:SetScript('OnHide', Scroller_OnHide)
-  Wrapper.close:SetScript('OnClick', WrapperCloseButton_OnClick)
-  Wrapper:SetPoint(unpack(wrapperPosition))
-  Scroller_OnShow(Scroller)
-end
-
+--- These are mostly aesthetic choices so it lives here
 mod.defaults = {
   ObjectiveTrackerAnchor = {'BOTTOM', 'RIGHT'},
   ObjectiveTrackerParent = 'DebuffButton',
   ObjectiveTrackerSize = {250, 600},
   ObjectiveWrapperParent = '',
+  WrapperStyle = {
+    Header = {
+      Background = {Left = [[Objective-Header]], Right = [[Objective-Header]], Tile = [[Objective-Header]]},
+      BackgroundCrop = {Left = {0, 0.4, 0,1}, Right={0.6,1,0,1}, Tile = {0.4,.6,0,1,}},
+      BackgroundScale = {Left = 100, Right = 100},
+      Font = {wrapperHeadFont, wrapperHeadSize, wrapperHeadOutline}
+    }
+  },
+  ObjectiveHeaderStyle = {
+    Normal = {
+      Gradient = {MinColor = {0,0,0,0.5}, MaxColor = {0,0,0,1}},
+      Font = {headerFont, headerSize, headerOutline}, Spacing = headerSpacing,
+    }
+  },
   ObjectiveTrackerStyle = {
     Normal = {
       Title = {
@@ -158,12 +109,155 @@
   }
 }
 
+local Scroller_OnShow = function()
+  Wrapper.watchMoneyReasons = 0;
+  mod.UpdateWrapper()
+  mod.SetEvents()
+  for i, region in ipairs(Wrapper.header) do
+    region:Show()
+  end
+end
+
+local Scroller_OnHide = function()
+  local self = Wrapper
+  Wrapper:UnregisterAllEvents()
+  Wrapper:SetScript('OnEvent', nil)
+  for i, region in ipairs(Wrapper.header) do
+    region:Hide()
+  end
+end
+
+local Scroller_OnMouseWheel = function(self, delta)
+  local r = Scroll:GetHeight() - Scroller:GetHeight()
+  local s = self:GetVerticalScroll() - delta * floor(r/5+.5)
+  if r == 0 then return end
+  if s >= r then
+    s = r
+  elseif s < 1 then
+    s = 0
+  end
+  self:SetVerticalScroll(s)
+  print(s, r, self:GetVerticalScroll())
+
+  mod.UpdateActionButtons()
+end
+
+local WrapperCloseButton_OnClick = function(self)
+  if Scroller:IsVisible() then
+    Scroller:Hide()
+  else
+    Scroller:Show()
+  end
+end
+
+mod.InitializeTrackers = function()
+
+  local c = mod.defaults.ObjectiveHeaderStyle.Normal
+  local g1, g2, g3, g4 = unpack(c.Gradient.MinColor)
+  local h1, h2, h3, h4 = unpack(c.Gradient.MaxColor)
+
+  for i, name in ipairs(orderedNames) do
+    if not mod.orderedHandlers[i] then
+      if mod.Tracker(name, i) then
+        local handler = mod[name]
+
+        local tracker = CreateFrame('Frame', 'Veneer'..name..'Tracker', Scroll, 'VeneerTrackerTemplate')
+        tracker.header:SetText(handler.name)
+        tracker.header:SetHeight(headerHeight)
+        tracker.header:SetFont(unpack(c.Font))
+        tracker.header:SetTextColor(unpack(headerColor))
+
+        tracker.headerbg:SetGradientAlpha('HORIZONTAL', g1, g2 ,g3, g4, h1, h2, h3, h4)
+        tracker.headerbg:SetHeight(headerHeight)
+
+        handler.Tracker = tracker
+        mod.orderedTrackers[i] = tracker
+        mod.namedTrackers[name] = tracker
+        mod.indexedTrackers[handler] = tracker
+        print('created new tracker frames for new handler')
+      end
+    end
+  end
+
+  Scroller:SetScrollChild(Scroll)
+  Scroller:SetScript('OnMouseWheel', Scroller_OnMouseWheel)
+  Scroller:SetScript('OnShow', Scroller_OnShow)
+  Scroller:SetScript('OnHide', Scroller_OnHide)
+  Wrapper.close:SetScript('OnClick', WrapperCloseButton_OnClick)
+  Wrapper:SetPoint(unpack(wrapperPosition))
+  Scroller_OnShow(Scroller)
+
+  mod.UpdateWrapperStyle()
+end
+
+mod.InitializeXPTracker = function()
+  local XPBar = Wrapper.XPBar
+  if UnitLevel('player') == 100 then
+    XPBar:Hide()
+    return
+  end
+
+  --- xp bar
+  XPBar:Show()
+  XPBar.rested:SetTexture(2,.6,1,1)
+  XPBar.fg:SetTexture(.3,.1,.95,1)
+  XPBar.bg:SetTexture(0,0,0,.25)
+  XPBar:RegisterEvent('PLAYER_XP_UPDATE')
+  XPBar:RegisterEvent('PLAYER_LEVEL_UP')
+  XPBar:RegisterEvent('PLAYER_UPDATE_RESTING')
+  XPBar:SetScript('OnEvent', mod.UpdateXP)
+  mod.UpdateXP(Wrapper.xpBar)
+end
+
+mod.UpdateXP = function()
+  local XPBar = Wrapper.XPBar
+  local xp = UnitXP('player')
+  local xpmax = UnitXPMax('player')
+  local rest = GetXPExhaustion()
+
+  XPBar.bg:SetAllPoints(XPBar)
+  XPBar.fg:SetWidth((xp/xpmax) * XPBar:GetWidth())
+
+  if IsResting() then
+    XPBar.bg:SetTexture(.2,.8,.2,.5)
+  else
+    XPBar.bg:SetTexture(0,0,0,.25)
+  end
+
+  if rest then
+    XPBar.rested:ClearAllPoints()
+    if xp == 0 then
+      XPBar.rested:SetPoint('LEFT', XPBar, 'LEFT', 0, 0)
+    else
+      XPBar.rested:SetPoint('LEFT', XPBar.fg, 'RIGHT', 0, 0)
+    end
+
+    if (xp + rest) > xpmax then
+      XPBar.rested:SetPoint('RIGHT', XPBar, 'RIGHT', 0, 0)
+    else
+      XPBar.rested:SetWidth((xp/xpmax) * XPBar:GetWidth())
+    end
+    XPBar.rested:Show()
+  else
+    XPBar.rested:Hide()
+  end
+
+  XPBar.xpText:SetText(xp .. '/'.. xpmax .. (rest and (' ('..tostring(rest)..')') or ''))
+end
+
+mod.UpdateReputation = function(self)
+end
 
 --- Argument containers
 local a1, a2, a3, a4, b1, b2, b3, b4, f1, f2, f3, w1, w2
 mod.SetBlockStyle = function(block, name)
   -- var names intended to reflect argument order
+  --@debug@
   local c = mod.defaults.ObjectiveTrackerStyle[name]
+  --@end-debug@
+  --[===[@non-debug
+  local c = mod.Conf
+  --@end-non-debug]===]
   a1, a2, a3, a4 = unpack(c.Title.Gradient.MinColor)
   b1, b2, b3, b4 = unpack(c.Title.Gradient.MaxColor)
   block.titlebg:SetGradientAlpha('HORIZONTAL', a1, a2, a3, a4, b1, b2, b3, b4)
@@ -212,7 +306,19 @@
   block.width = blockWidth
   block.height = blockHeight
 
-  print('|cFF88DDFFApplyStyle(', block:GetName(), ')|r', blockWidth, 'x', blockHeight, '(textH', textHeight,', titleH', titleHeight, ')')
+  print('    |cFF00FFFF'..block:GetName()..'|r:|cFF0088FFSetStyle|r(', blockWidth, 'x', blockHeight, '(textH', textHeight,', titleH', titleHeight, ')')
+end
+
+local segments = {'Left', 'Right', 'Tile'}
+mod.UpdateWrapperStyle = function()
+  local c = mod.defaults.WrapperStyle
+  for _, segment in ipairs(segments) do
+    Wrapper['Background'..segment]:SetAtlas(c.Header.Background[segment])
+    Wrapper['Background'..segment]:SetTexCoord(unpack(c.Header.BackgroundCrop[segment]))
+    if c.Header.BackgroundScale[segment] then
+    Wrapper['Background'..segment]:SetWidth(c.Header.BackgroundScale[segment])
+    end
+  end
 end
 
 --- Updates the selected block frame to display the given info batch
@@ -221,7 +327,7 @@
 -- @param info the reference returned by the GetXInfo functions
 -- REMEMBER: t.info and questData[questID] are the same table
 mod.UpdateTrackerBlock = function (handler, blockIndex, info)
-  print('|cFF00FFFFUpdateTrackerBlock('..blockIndex..'|r')
+  print('  |cFF00FFFFUpdateTrackerBlock('..blockIndex..'|r')
   if not blockIndex or not info then
     return
   end
@@ -237,8 +343,8 @@
     end
     t:SetPoint('RIGHT', tracker,'RIGHT', 0, 0)
   end
-  print(t:GetName(), t:GetSize())
-  print(t:GetPoint(1))
+  --print(t:GetName(), t:GetSize())
+  --print(t:GetPoint(1))
 
   t.info = info
 
@@ -260,7 +366,7 @@
     t.objectives:SetText(info.completionText)
   elseif info.numObjectives >= 1 then
     t.objectives:Show()
-    print('objective lines:', info.numObjectives, 'can wrap:', t.objectives:CanWordWrap())
+    print('  - objective lines:', info.numObjectives, 'can wrap:', t.objectives:CanWordWrap())
     local text = ''
     for o, obj in ipairs(t.info.objectives) do
       local line = obj.text
@@ -277,12 +383,9 @@
 
 
     -- todo: set up a SecureActionButton template
-    if info.specialItem then
-      print('|cFF00FFFFretrieve item button')
+    if info.specialItem and not info.itemButton then
+      print('  - |cFF00FFFFupdate item button')
       mod.SetItemButton(t, info)
-    elseif t.itemButton then
-      print('|cFF00FF88drop item button')
-      mod.FreeItemButton(t, info)
     end
 
 
@@ -304,7 +407,7 @@
 
   local fullheight = t:GetHeight()
   t:Show()
-  print('|cFF00FFFF)|r -> ', t, t:GetHeight(), fullheight)
+  print('  |cFF00FFFF)|r -> ', t, t:GetHeight(), fullheight)
   return t
 end
 
@@ -326,7 +429,6 @@
       if info then
         local currentBlock = mod.UpdateTrackerBlock(handler, blockIndex, info)
         previousBlock = currentBlock
-        print('adding ', currentBlock.height)
         trackerHeight = trackerHeight + currentBlock.height
         numBlocks = max(numBlocks, watchIndex)
         actualBlocks = actualBlocks + 1
@@ -412,11 +514,13 @@
   headerHeight = floor(headerHeight+.5)
 
   if wrapperBlocks >= 1 then
-    Wrapper.Background:Show()
-    Wrapper.BackgroundR:Show()
+    for i, region in ipairs(Wrapper.header) do
+      region:Show()
+    end
   else
-    Wrapper.Background:Hide()
-    Wrapper.BackgroundR:Hide()
+    for i, region in ipairs(Wrapper.header) do
+      region:Hide()
+    end
     return
   end
   --wrapperHeight = scrollHeight
@@ -452,7 +556,8 @@
 --- Queue any active item buttons for update for that frame
 mod.UpdateActionButtons = function()
   local previousItem
-  for questIndex, itemButton in pairs(usedButtons) do
+  for questID, itemButton in pairs(usedButtons) do
+    local questIndex = mod.Quest.Info[questID].questLogIndex
     print('|cFF00FFFF', questIndex, itemButton:GetName())
     local block = mod.Quest.LogBlock[questIndex]
     print(block:GetTop())
@@ -469,13 +574,20 @@
           end)
         return
       else
-        mod.FreeItemButton(block, itemButton)
+        mod.FreeItemButtons(block)
       end
     end
   end
 end
 
 mod.UpdateBlockAction = function (block, itemButton, previousItem)
+  if block.itemButton ~= itemButton then
+    block.itemButton = itemButton
+  end
+  if itemButton.block ~= block then
+    itemButton.block = block
+  end
+
   if block:GetBottom() < Scroller:GetBottom() then
     print('|cFFFFFF00bottom not fully visible')
     if previousItem then
--- a/ObjectiveInfo.lua	Wed Mar 30 16:30:49 2016 -0400
+++ b/ObjectiveInfo.lua	Thu Mar 31 01:38:47 2016 -0400
@@ -19,11 +19,9 @@
   print('|cFF00DDFFQuest|r.|cFF0088FFGetInfo(|r'.. tostring(watchIndex)..'|r)')
   local questID, title, questIndex, numObjectives, requiredMoney, isComplete,
   startEvent, isAutoComplete, failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
-print(GetQuestWatchInfo(watchIndex))
   if not questID then
     return
   end
-  print(self.Info)
   self.Info[questID] = self.Info[questID] or {}
 
   local q = self.Info[questID]
@@ -52,9 +50,7 @@
   q.isDaily = QuestIsDaily()
   q.isWeekly = QuestIsWeekly()
   -----------------------------------------
-
   --- End QuestLogEntry calls
-  print('   |cFF0088FF', q.isDaily, q.isWeekly)
 
   q.isComplete = IsQuestComplete(questID)
   q.isBreadCrumb = IsBreadcrumbQuest(questID)
@@ -109,7 +105,7 @@
   end
 
   self.LogInfo[questIndex] = q
-  print('|cFF0088FFGetQuestInfo('..questID..')|r', questIndex, title)
+  print('- logIndex =', questIndex, 'title =', title)
   return q
 end
 
--- a/ObjectiveTracker.lua	Wed Mar 30 16:30:49 2016 -0400
+++ b/ObjectiveTracker.lua	Thu Mar 31 01:38:47 2016 -0400
@@ -151,6 +151,7 @@
 Tracker.BlockInfo = {}   -- find by block ID
 Tracker.LogInfo = {}     -- find by log ID (quest log mainly)
 Tracker.WatchBlock = {}
+Tracker.WatchInfo = {}
 Tracker.LogBlock = {}
 
 
@@ -172,11 +173,13 @@
   return handler.usedBlocks[blockIndex]
 end
 local SmallEvents = {
-  QUEST_ACCEPTED = 'OnQuestAccepted'
+  QUEST_ACCEPTED = 'OnQuestAccepted',
+  QUEST_REMOVED = 'OnQuestRemoved'
 }
 
 local HandlerEvents = {
   QUEST_ACCEPTED = mod.Quest,
+  QUEST_REMOVED = mod.Quest,
   QUEST_WATCH_LIST_CHANGED = mod.Quest,
   SUPER_TRACKED_QUEST_CHANGED = mod.Quest,
   QUEST_LOG_UPDATE = mod.Quest,
@@ -206,19 +209,25 @@
   end
 end
 
-function mod:OnInitialize()
-  self.InitializeTrackers()
+mod.SetEvents = function()
+
   for event, _ in pairs(SmallEvents) do
-    self:RegisterEvent(event)
+    mod:RegisterEvent(event)
   end
 
   for event, _ in pairs(HandlerEvents) do
-    self:RegisterEvent(event)
+    mod:RegisterEvent(event)
   end
-  self:SetScript('OnEvent', mod.OnEvent)
+  mod:SetScript('OnEvent', mod.OnEvent)
+end
 
+function mod:OnInitialize()
+  self.InitializeTrackers()
+
+  mod.SetEvents()
   ObjectiveTrackerFrame:UnregisterAllEvents()
   ObjectiveTrackerFrame:Hide()
+
 end
 
 --[[
--- a/ObjectiveTracker.xml	Wed Mar 30 16:30:49 2016 -0400
+++ b/ObjectiveTracker.xml	Thu Mar 31 01:38:47 2016 -0400
@@ -28,20 +28,27 @@
     <Layers>
 
       <Layer level="ARTWORK">
-        <Texture parentKey="headerbg" />
-        <Texture parentKey="Background" hidden="false" alpha="1" atlas="Objective-Header" useAtlasSize="false">
-          <Size y="84" x="210" />
-          <TexCoords up="0" down="1" left="0" right="0.7" />
+        <Texture parentKey="HeaderBounds" />
+        <Texture parentKey="BackgroundLeft" parentArray="header" hidden="false" alpha="1" atlas="Objective-Header" useAtlasSize="false">
+          <Size x="100" y="84" />
+          <TexCoords up="0" down="1" left="0" right="0.3" />
           <Anchors>
             <Anchor point="TOPLEFT" x="-30" y="12"/>
           </Anchors>
         </Texture>
-        <Texture parentKey="BackgroundR" hidden="false" alpha="1" atlas="Objective-Header" useAtlasSize="false">
-          <Size y="84" x="210" />
-          <TexCoords up="0" down="1" left="0.3" right="1" />
+        <Texture parentKey="BackgroundRight" parentArray="header"  hidden="false" alpha="1" atlas="Objective-Header" useAtlasSize="false">
+          <Size x="70" y="84" />
+          <TexCoords up="0" down="1" left="0.6" right="1" />
           <Anchors>
-            <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeKey="$parent.Background" />
-            <Anchor point="RIGHT" relativePoint="RIGHT" x="24" />
+            <Anchor point="TOPRIGHT"  x="24" y="12" />
+          </Anchors>
+        </Texture>
+        <Texture parentKey="BackgroundTile" parentArray="header" hidden="false" alpha="1" atlas="Objective-Header" useAtlasSize="false" tile="true">
+          <Size x="100" y="84" />
+          <TexCoords up="0" down="1" left=".3" right=".6" />
+          <Anchors>
+            <Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeKey="$parent.BackgroundLeft" />
+            <Anchor point="TOPRIGHT" relativePoint="TOPLEFT" relativeKey="$parent.BackgroundRight" />
           </Anchors>
         </Texture>
         <!--<Texture desatuated="true" parentKey="LineGlow" hidden="false" alpha="0" alphaMode="ADD" atlas="OBJFX_LineGlow" useAtlasSize="true">
@@ -72,6 +79,40 @@
     </Layers>
     <Frames>
 
+      <Frame name="$parentXP" parentKey="xpBar" hidden="true">
+        <Size x="250" y="24" />
+        <Anchors>
+          <Anchor point="TOPLEFT" />
+        </Anchors>
+        <Layers>
+          <Layer level="BACKGROUND">
+            <Texture name="$parentBackground" parentKey="bg" setAllPoints="true"/>
+          </Layer>
+          <Layer level="ARTWORK">
+
+            <Texture name="$parentForeground" parentKey="fg">
+              <Anchors>
+                <Anchor point="TOPLEFT" />
+                <Anchor point="BOTTOMLEFT" />
+              </Anchors>
+            </Texture>
+            <Texture name="$parentRested" parentKey="rested" >
+              <Anchors>
+                <Anchor point="TOPLEFT" />
+                <Anchor point="BOTTOMLEFT" />
+              </Anchors>
+            </Texture>
+          </Layer>
+          <Layer level="OVERLAY">
+            <FontString inherits="VeneerFontNormal" parentKey="xpText">
+              <Anchors>
+                <Anchor point="CENTER" />
+              </Anchors>
+            </FontString>
+          </Layer>
+        </Layers>
+      </Frame>
+
       <Button name="$parentClose" parentKey="close" inherits="UIPanelCloseButtonNoScripts">
         <Size x="25" y="20" />
         <Anchors>
@@ -133,6 +174,7 @@
         <Texture name="$parentHeaderBG" parentKey="headerbg">
           <Anchors>
             <Anchor point="TOPLEFT" relativePoint="TOPLEFT" />
+            <Anchor point="RIGHT" relativePoint="RIGHT" />
           </Anchors>
           <Color r="1" g="1" b="1" a="1" />
           <Gradient orientation="HORIZONTAL">
--- a/ObjectiveUI.lua	Wed Mar 30 16:30:49 2016 -0400
+++ b/ObjectiveUI.lua	Thu Mar 31 01:38:47 2016 -0400
@@ -90,11 +90,15 @@
   local itemButton
   if not info.itemButton then
     if #freeButtons >= 1 then
-      print('|cFF00FFFFfound a free button')
+      print('    |cFF00FFFFfound a free button')
       itemButton = freeButtons[#freeButtons]
       freeButtons[#freeButtons] = nil
+      if itemButton.block then
+        itemButton.block.itemButton = nil
+        itemButton.block = nil
+      end
     else
-      print('|cFFFF4400starting new button')
+      print('    |cFFFF4400starting new button')
       local buttonIndex = mod.Quest.numButtons + #freeButtons + 1
       itemButton = CreateFrame('Button', 'VeneerQuestItemButton' .. buttonIndex, UIParent, 'VeneerItemButtonTemplate')
       itemButton.buttonIndex = buttonIndex
@@ -103,17 +107,25 @@
     end
     mod.Quest.numButtons = mod.Quest.numButtons + 1
   else
-    print('|cFF00FF00found assigned button')
+    print('    |cFF00FF00found assigned button')
     itemButton = info.itemButton
+    if itemButton.block then
+      print('  - moving from old block')
+      itemButton.block.itemButton = nil
+    end
+
   end
   -- set values
+
+
   info.itemButton = itemButton
   block.itemButton = itemButton
-  usedButtons[info.questLogIndex] = itemButton
+  usedButtons[info.questID] = itemButton
 
   itemButton:SetAttribute("type", "item")
   itemButton:SetAttribute("item", itemInfo.link)
 
+  itemButton.questID = info.questID
   itemButton.questLogIndex = info.questLogIndex
   itemButton.charges = itemInfo.charges
   itemButton.rangeTimer = -1
@@ -126,22 +138,18 @@
   return itemButton
 end
 --- Clear an itemButton from the given block
-mod.FreeItemButton = function(block, itemButton)
-  if block.itemButton ~= itemButton then
-    print('|cFFFF0088trying to release mismatched action button')
-    return
+mod.FreeItemButtons = function(block)
+
+  if block.itemButton then
+    local itemButton = block.itemButton
+    itemButton.block = nil
+    itemButton:Hide()
+
+    usedButtons[itemButton.questID] = nil
+    freeButtons[#freeButtons + 1] = itemButton
+    mod.Quest.numButtons = mod.Quest.numButtons - 1
+    print('|cFFFF0088released', itemButton:GetName(),'and', block:GetName())
   end
-
-  block.itemButton = nil
-  block.icon:Hide()
-
-  itemButton.block = nil
-  itemButton:Hide()
-
-  usedButtons[itemButton.questLogIndex] = nil
-  freeButtons[#freeButtons + 1] = itemButton
-  mod.Quest.numButtons = mod.Quest.numButtons - 1
-  print('|cFFFF0088released', itemButton:GetName(),'from', block:GetName())
 end
 
 function Veneer_QuestObjectiveItem_OnUpdate (self, elapsed)
@@ -152,7 +160,7 @@
     if (rangeTimer <= 0) then
       local link, item, charges, showItemWhenComplete = GetQuestLogSpecialItemInfo(self.questLogIndex)
       if ((not charges) or (charges ~= self.charges)) then
-        QuestKing:UpdateTracker()
+        mod.UpdateWrapper()
         return
       end