Arrgh
[QuestHelper.git] / tracker.lua
blob66ec9684c0896d6d804726c477f4762de21c2338
1 QuestHelper_File["tracker.lua"] = "Development Version"
2 QuestHelper_Loadtime["tracker.lua"] = GetTime()
4 local debug_output = false
5 if QuestHelper_File["tracker.lua"] == "Development Version" then debug_output = true end
7 --[[ NOTES TO SELF
9 So here's what we want to do.
11 We want a "refresh notification" where we send it the current route.
13 If things aren't in the route, we don't care about them . . . unless they're pinned.
15 So we have "refresh notification" and "pin toggles". In both cases, the objective and only the objective is passed in. Right now there's no concept of priority within the pins.
17 We're also not bothering with the whole metaobjective tree, we're just going one step up.
19 So, our algorithm:
21 Note that "add" means "add iff it hasn't already been added."
23 Iff we haven't loaded yet, add a loaded message and a gap.
25 For each pinned objective, add the metaobjective and all objectives in its internal order. Iff we added things, add a gap.
27 For each route objective, add the metaobjective and all objectives in route order.
29 Later on we'll add an option for "splitting" metaobjectives, or possibly following the metaobjective tree all the way up.
33 So, "add" is complicated, due to the two requirements. We have to both add everything, and not add everything *yet*. I think the goal here is to make an Add function for adding a metaobjective that takes a list of objectives to be children, then doublecheck inside the function that we have all objectives.
35 We don't actually want "all objectives" long-term, note, we want only unfinished objectives. I sort of don't like the idea of keeping "finished objectives" around, however. Maybe we should only toss objectives in if they're in the routing system? Then how do I handle unknown objectives? (Simple - you pin them, and point out that we don't know how to do them.)
37 Also, to handle the "moving things around", we need to be a little clever. One line might be either a metaobjective or an objective, but in either case, we need a counter for which case it is. If everything shuffles, and we had two copies of metaobjective, MO1 moves to MO1 and MO2 moves to MO2. Easy.
40 local tracker = CreateFrame("Frame", "QuestHelperQuestWatchFrame", UIParent)
41 local minbutton = CreateFrame("Button", "QuestHelperQuestWatchFrameMinimizeButton", UIParent)
43 QuestHelper.tracker = tracker
45 local resizing = false
46 tracker:SetWidth(200)
47 tracker:SetHeight(100)
48 tracker:SetFrameStrata("BACKGROUND")
49 tracker.dw, tracker.dh = 200, 100
51 local in_tracker = 0
53 minbutton:SetFrameStrata("LOW")
54 minbutton:Hide()
55 minbutton:SetPoint("TOPRIGHT", WatchFrame) -- We default to a different location to make it more likely to display the right item.
56 minbutton:SetMovable(true)
57 minbutton:SetUserPlaced(true)
58 minbutton:SetWidth(32 / 1.6)
59 minbutton:SetHeight(32)
60 minbutton:SetFrameLevel(3)
61 local minbutton_tex = minbutton:CreateTexture()
62 minbutton_tex:SetAllPoints()
63 minbutton_tex:SetTexture(.6, .6, .6)
64 minbutton_tex:SetParent(minbutton)
66 local sigargh = CreateFrame("Frame", minbutton)
67 sigargh:SetFrameStrata("LOW")
68 sigargh:SetFrameLevel(4)
70 local sigil = sigargh:CreateTexture("BACKGROUND")
71 sigil:SetHeight(32)
72 sigil:SetWidth(32)
73 --sigil:SetPoint("CENTER", 0, 0)
74 sigil:SetTexture("Interface\\AddOns\\QuestHelper\\sigil")
75 sigil:SetPoint("CENTER", minbutton_tex, "CENTER")
78 tracker:SetPoint("CENTER", minbutton)
80 function minbutton:moved()
81 local x, y = self:GetCenter()
82 local w, h = UIParent:GetWidth(), UIParent:GetHeight()
83 local anchor = (y < h*.45 and "BOTTOM" or y > h*.55 and "TOP" or "")..(x < w*.45 and "LEFT" or x > w*.55 and "RIGHT" or "")
85 tracker:ClearAllPoints()
86 tracker:SetPoint("CENTER", self)
88 if anchor ~= "" then
89 tracker:SetPoint(anchor, self)
90 end
91 end
93 function QuestHelper:ResetTrackerPosition(cmd)
94 minbutton:ClearAllPoints()
95 if cmd and string.find(cmd, "center") then
96 minbutton:SetPoint("CENTER", nil, "CENTER", 100, 100)
97 else
98 minbutton:SetPoint("RIGHT", nil, "RIGHT", -20, 230)
99 end
100 minbutton:moved()
101 QuestHelper_Pref.track_minimized = false
102 tracker:Show()
103 self:TextOut("Quest tracker postion reset.")
106 QH_Event({"DISPLAY_SIZE_CHANGED", "PLAYER_ENTERING_WORLD"}, function () minbutton:moved() end)
108 QH_Hook(minbutton, "OnClick", function ()
109 QuestHelper_Pref.track_minimized = not QuestHelper_Pref.track_minimized
110 if QuestHelper_Pref.track_minimized then
111 tracker:Hide()
112 else
113 tracker:Show()
115 end)
117 minbutton:RegisterForDrag("LeftButton")
119 QH_Hook(minbutton, "OnDragStart", function(self)
120 if self:IsVisible() then
121 self:StartMoving()
122 QH_Hook(self, "OnUpdate", self.moved)
124 end)
126 QH_Hook(minbutton, "OnDragStop", function(self)
127 QH_Hook(self, "OnUpdate", nil)
128 self:StopMovingOrSizing()
129 self:moved()
130 end)
132 QH_Hook(minbutton, "OnEnter", function (self)
133 self:SetAlpha(1)
134 sigargh:SetAlpha(1)
135 end)
137 QH_Hook(minbutton, "OnLeave", function (self)
138 self:SetAlpha(QuestHelper_Pref.track_minimized and .3 or .5)
139 sigargh:SetAlpha(QuestHelper_Pref.track_minimized and .3 or .5)
140 end)
142 -- used_items[objective][index]
143 -- used_count[objective] is incremented as the last valid index
144 -- so, therefore, used_items[objective][used_count[objective]] is not nil
145 local used_items = {}
146 local used_count = {}
148 -- it's possible for an item to be in neither used_items nor recycled_items, if it's in the process of fading out
149 local recycled_items = {}
151 -- These two functions are basically identical. Combine them.
152 local function itemupdate(item, delta)
153 local done = true
155 local a = item:GetAlpha()
156 a = a + delta
158 if a < 1 then
159 item:SetAlpha(a)
160 done = false
161 else
162 item:SetAlpha(1)
165 local t = item.t + delta
167 if t < 1 then
168 item.t = t
169 local it = 1-t
170 local sp = math.sqrt(t-t*t)
171 item.x, item.y = item.sx*it+item.ex*t+(item.sy-item.ey)*sp, item.sy*it+item.ey*t+(item.ex-item.sx)*sp
172 done = false
173 else
174 item.t = 1
175 item.x, item.y = item.ex, item.ey
178 item:ClearAllPoints()
179 item:SetPoint("TOPLEFT", tracker, "TOPLEFT", item.x, -item.y)
181 if done then
182 QH_Hook(item, "OnUpdate", nil)
186 local function itemfadeout(item, delta)
187 local a = item:GetAlpha()
188 a = a - delta
190 if a > 0 then
191 item:SetAlpha(a)
192 else
193 item:SetAlpha(1)
194 item:Hide()
195 QH_Hook(item, "OnUpdate", nil)
196 table.insert(recycled_items, item)
197 return
200 local t = item.t + delta
202 if t < 1 then
203 item.t = t
204 local it = 1-t
205 local sp = math.sqrt(t-t*t)
206 item.x, item.y = item.sx*it+item.ex*t+(item.sy-item.ey)*sp, item.sy*it+item.ey*t+(item.ex-item.sx)*sp
207 else
208 item.t = 1
209 item.x, item.y = item.ex, item.ey
212 item:ClearAllPoints()
213 item:SetPoint("TOPLEFT", tracker, "TOPLEFT", item.x, -item.y)
216 --[[function QH_ToggleQuestLog() -- This seems to be gone in 3.0, so I'm adding it here.
217 if (QuestLogFrame:IsShown()) then
218 HideUIPanel(QuestLogFrame);
219 else
220 ShowUIPanel(QuestLogFrame);
224 -- Grim stuff with uberquest, I need a better way to handle this
225 local function itemclick(item, button)
226 if button == "RightButton" then
227 local quest = item.quest
228 local index = 1
229 while true do
230 local title = GetQuestLogTitle(index)
231 if not title then break end
233 if title == quest then
234 if UberQuest then
235 -- UberQuest needs a little extra effort to work properly.
237 if UberQuest_List:IsShown() and GetQuestLogSelection() == index then
238 QH_ToggleQuestLog()
239 else
240 QuestLog_SetSelection(index)
242 -- By hiding the list, the replaced ToggleQuestLog function should try to reshow it
243 -- and in the process update the frames to reflect the selected quest.
244 UberQuest_List:Hide()
245 UberQuest_Details:Show()
246 QH_ToggleQuestLog()
248 else
249 -- This code seems to work properly with the builtin questlog, as well as bEQL and DoubleWide.
251 if QuestLogFrame:IsShown() and GetQuestLogSelection() == index then
252 -- If the selected quest is already being shown, hide it.
253 QH_ToggleQuestLog()
254 else
255 -- Otherwise, select it and show it.
256 QuestLog_SetSelection(index)
258 if not QuestLogFrame:IsShown() then
259 QH_ToggleQuestLog()
264 return
267 index = index + 1
270 end]]
272 local function allocateItem()
273 local item
275 item = table.remove(recycled_items)
276 if item then return item end
278 item = CreateFrame("Frame", nil, tracker)
279 item.text = item:CreateFontString()
280 item.text:SetShadowColor(0, 0, 0, .8)
281 item.text:SetShadowOffset(1, -1)
282 item.text:SetPoint("TOPLEFT", item)
283 return item
286 local specitem_max = 1
287 local specitem_unused = {}
289 -- This is adding a *single item*. This won't be called by the main parsing loop, but it does need some serious hackery. Let's see now
290 local function addItem(objective, y, meta)
291 local obj_key = objective
292 if obj_key.cluster then obj_key = obj_key.cluster end
293 used_count[obj_key] = (used_count[obj_key] or 0) + 1
294 if not used_items[obj_key] then used_items[obj_key] = QuestHelper:CreateTable("additem used_items") end
295 local item = used_items[obj_key][used_count[obj_key]]
297 local x = meta and 4 or 20
299 if not item then
300 used_items[obj_key][used_count[obj_key]] = allocateItem()
301 item = used_items[obj_key][used_count[obj_key]]
303 if meta then
304 item.text:SetFont(QuestHelper.font.serif, 12)
305 item.text:SetTextColor(.82, .65, 0)
306 else
307 item.text:SetFont(QuestHelper.font.sans, 12)
308 item.text:SetTextColor(.82, .82, .82)
311 item.obj = objective
313 item.sx, item.sy, item.x, item.y, item.ex, item.ey, item.t = x+30, y, x, y, x, y, 0
314 QH_Hook(item, "OnUpdate", itemupdate)
315 item:SetAlpha(0)
316 item:Show()
319 item.text:SetText(item.obj.tracker_desc or "(no description)")
321 local w, h = item.text:GetWidth(), item.text:GetHeight()
322 item:SetWidth(w)
323 item:SetHeight(h)
325 if objective.tracker_clicked then
326 QH_Hook(item, "OnMouseDown", function (self, button) if button == "RightButton" then objective.tracker_clicked() end end)
327 item:EnableMouse(true)
330 if item.ex ~= x or item.ey ~= y then
331 item.sx, item.sy, item.ex, item.ey = item.x, item.y, x, y
332 item.t = 0
333 QH_Hook(item, "OnUpdate", itemupdate)
336 -- we're just going to recycle this each time
337 if item.specitem then
338 item.specitem:Hide()
339 table.insert(specitem_unused, item.specitem)
340 item.specitem = nil
343 local spacer = 0
344 -- hacky - progress only shows up if we're not on a metaobjective. wheee
345 if objective.type_quest and objective.type_quest.index and not objective.progress and GetQuestLogSpecialItemInfo(objective.type_quest.index) then
346 item.specitem = table.remove(specitem_unused)
347 if not item.specitem then
348 item.specitem = CreateFrame("BUTTON", "QH_SpecItem_" .. tostring(specitem_max), item, "WatchFrameItemButtonTemplate")
349 QuestHelper: Assert(item.specitem)
351 local rangey = _G["QH_SpecItem_" .. tostring(specitem_max) .. "HotKey"]
352 QuestHelper: Assert(rangey)
353 local fn, fh, ff = rangey:GetFont()
354 rangey:SetFont("Fonts\\ARIALN.TTF", fh, ff)
355 rangey:SetText(RANGE_INDICATOR)
356 rangey:ClearAllPoints()
357 rangey:SetPoint("BOTTOMRIGHT", item.specitem, "BOTTOMRIGHT", 0, 2)
359 specitem_max = specitem_max + 1
362 item.specitem:SetScale(0.9)
363 item.specitem:ClearAllPoints()
364 item.specitem:SetParent(item)
365 item.specitem:SetPoint("TOPRIGHT", item, "TOPLEFT", 0, 0)
367 local _, tex, charges = GetQuestLogSpecialItemInfo(objective.type_quest.index)
368 item.specitem:SetID(objective.type_quest.index)
369 SetItemButtonTexture(item.specitem, tex)
370 item.specitem.rangeTimer = -1 -- This makes the little dot go away. Why does it do that?
371 item.specitem.charges = charges
373 item.specitem:Show()
375 spacer = h
378 return w+x+4, y+h, y+h+spacer
381 local function addMetaObjective(metaobj, items, y, depth)
382 local x, spacer
383 x, y, spacer = addItem(metaobj, y, true)
384 for _, v in ipairs(items) do
385 x, y = addItem(v, y, false)
387 return math.max(y, spacer), depth + #items + 1
390 --[[ -- these will be plugged in later one way or another
391 local function ccode(r1, g1, b1, r2, g2, b2, p)
392 local ip
393 p, ip = p*255, 255-p*255
394 return string.format("|cff%02x%02x%02x", r1*ip+r2*p, g1*ip+g2*p, b1*ip+b2*p)
397 local function qname(title, level)
398 if QuestHelper_Pref.track_level and level ~= 7777 and level ~= 7778 then
399 title = string.format("[%d] %s", level, title)
402 if level == 7778 then
403 level = -7778
406 if QuestHelper_Pref.track_qcolour then
407 local player_level = QuestHelper.player_level
408 local delta = level - player_level
410 local colour
412 if delta >= 5 then
413 colour = "|cffff0000"
414 elseif delta >= 0 then
415 colour = ccode(1, 1, 0, 1, 0, 0, delta/5)
416 else
417 local grey
419 if player_level >= 60 then grey = player_level - 9
420 elseif player_level >= 40 then grey = player_level - math.floor(player_level/5) - 1
421 elseif player_level >= 6 then grey = player_level - math.floor(player_level/10) - 5
422 else grey = 0 end
424 if level == -7778 then
425 colour = "|cff808080"
426 elseif level > grey then
427 colour = ccode(0, 1, 0, 1, 1, 0, (grey-level)/(grey-player_level))
428 else
429 colour = ccode(.4, .4, .4, .2, .8, .2, (1-level)/(1-grey))
433 title = string.format("%s%s", colour, title)
436 return title
439 local function oname(text, pct)
440 if QuestHelper_Pref.track_ocolour then
441 text = string.format("%s%s", pct < 0.5 and ccode(1, 0, 0, 1, 1, 0, pct*2) or ccode(1, 1, 0, 0, 1, 0, pct*2-1), text)
444 return text
448 local function removeUnusedItem(item)
449 item.t = 0
450 item.sx, item.sy, item.dx, item.dy = item.x, item.y, item.x+30, item.y
451 QH_Hook(item, "OnMouseDown", nil)
452 item:EnableMouse(false)
453 QH_Hook(item, "OnUpdate", itemfadeout)
455 if item.specitem then
456 item.specitem:Hide()
457 table.insert(specitem_unused, item.specitem)
458 item.specitem = nil
462 --[=[
463 local was_inside = false
465 -- :ughh:
467 local function addobj(objective, seen, obj_index_lookup, filter, x, y, gap)
468 local count = 0
469 local quest
471 if objective.cat == "quest" then
472 quest = objective
473 else
474 quest = objective.quest
477 if quest and quest.watched and not seen[quest] and (not filter or filter(quest)) then
478 seen[quest] = true
480 local level, name = string.match(quest.obj, "^(%d+)/%d*/(.*)$")
482 if not level then
483 level, name = string.match(quest.obj, "^(%d+)/(.*)$")
484 if not level then
485 level, name = 1, quest.obj
489 level = tonumber(level) or 1
491 count = count + 1
492 local w, h = addItem(qname(name, level), true, quest, -(y+gap), name, quest.index)
493 x = math.max(x, w)
494 y = y + h + gap
495 gap = 2
497 for obj in pairs(quest.swap_after or quest.after) do
498 if obj.progress then
499 table.insert(obj_list, obj)
503 table.sort(obj_list, objlist_sort)
505 for i, obj in ipairs(obj_list) do
506 local pct, text = 0, obj.obj
507 local seen_sum, seen_max = 0, 0
509 if obj.progress then
510 local seen_have, seen_need = QuestHelper:CreateTable(), QuestHelper:CreateTable()
512 for user, progress in pairs(obj.progress) do
513 seen_sum = seen_sum + progress[3]
514 seen_max = seen_max + 1
515 seen_have[progress[1]] = true
516 seen_need[progress[2]] = true
519 if seen_max > 0 then
520 pct = seen_sum / seen_max
521 local list = QuestHelper:CreateTable()
523 for val in pairs(seen_have) do
524 table.insert(list, val)
527 table.sort(list)
529 local have = table.concat(list, ", ")
531 for i = #list,1,-1 do
532 list[i] = nil
535 for val in pairs(seen_need) do
536 table.insert(list, val)
539 if #list ~= 1 or list[1] ~= 1 then
540 -- If there is only one thing needed, ignore the progress, it's redundant.
541 -- It's either shown or it isn't.
543 table.sort(list)
545 local need = table.concat(list, ", ")
547 text = string.format((tonumber(have) and tonumber(need) and QUEST_ITEMS_NEEDED) or QUEST_FACTION_NEEDED,
548 text, have, need)
551 QuestHelper:ReleaseTable(list)
554 QuestHelper:ReleaseTable(seen_have)
555 QuestHelper:ReleaseTable(seen_need)
558 if seen_sum ~= seen_max then
559 count = count + 1
560 w, h = addItem(oname(text, pct), quest, obj, -y)
561 x = math.max(x, w)
562 y = y + h
566 for i = #obj_list, 1, -1 do obj_list[i] = nil end
569 return x, y, gap, count
573 local loading_vquest = {tracker_desc = QHFormat("QH_LOADING", "0")}
574 local flightpath_vquest = {tracker_desc = QHFormat("QH_FLIGHTPATH", "0")}
577 local hidden_vquest1 = { tracker_desc = QHText("QUESTS_HIDDEN_1"), tracker_clicked = QH_Hidden_Menu }
578 local hidden_vquest2 = { tracker_desc = " " .. QHText("QUESTS_HIDDEN_2"), tracker_clicked = QH_Hidden_Menu }
580 local route = {}
581 local pinned = {}
583 -- This is actually called surprisingly often.
584 function QH_Tracker_Rescan()
585 used_count = QuestHelper:CreateTable("tracker rescan used_count")
587 local mo_done = QuestHelper:CreateTable("tracker rescan mo_done")
588 local obj_done = QuestHelper:CreateTable("tracker rescan obj_done")
590 local y, depth = 0, 0
593 local had_pinned = false
595 local objs = QuestHelper:CreateTable("tracker objs")
596 for k, v in pairs(pinned) do
597 if not objs[k.why] then objs[k.why] = QuestHelper:CreateTable("tracker objs sub") end
598 if not k.ignore and not k.tracker_hidden then table.insert(objs[k.why], k) end
599 obj_done[k.cluster] = true
602 local sort_objs = QuestHelper:CreateTable("tracker sobjs")
603 for k, v in pairs(objs) do
604 v.cluster = k
605 v.trackkey = k
606 table.insert(sort_objs, v)
609 table.sort(sort_objs, function (a, b) return tostring(a.trackkey) < tostring(b.trackkey) end)
611 for _, v in ipairs(sort_objs) do
612 y, depth = addMetaObjective(v.cluster, v, y, depth)
613 had_pinned = true
614 QuestHelper:ReleaseTable(v)
616 QuestHelper:ReleaseTable(sort_objs)
617 QuestHelper:ReleaseTable(objs)
619 if had_pinned then y = y + 10 end
622 if QuestHelper.loading_main then
623 loading_vquest.tracker_desc = QHFormat("QH_LOADING", string.format("%d", QuestHelper.loading_main:GetPercentage() * 100))
624 local x, ty = addItem(loading_vquest, y)
625 y = ty + 10
627 if QuestHelper.flightpathing then
628 flightpath_vquest.tracker_desc = QHFormat("QH_FLIGHTPATH", string.format("%d", QuestHelper.flightpathing:GetPercentage() * 100))
629 local x, ty = addItem(flightpath_vquest, y)
630 y = ty + 10
633 local metalookup = QuestHelper:CreateTable("tracker rescan metalookup")
634 for k, v in ipairs(route) do
635 if not v.ignore then
636 if not metalookup[v.why] then metalookup[v.why] = QuestHelper:CreateTable("tracker rescan metalookup item") end
637 if not v.tracker_hidden then table.insert(metalookup[v.why], v) end
642 local current_mo
643 local current_mo_cluster
644 for k, v in ipairs(route) do
645 if depth > QuestHelper_Pref.track_size and not debug_output then break end
646 if not v.ignore and not v.why.tracker_hidden and not obj_done[v.cluster] then
647 if current_mo and v.why ~= current_mo then
648 y, depth = addMetaObjective(current_mo, current_mo_cluster, y, depth)
649 QuestHelper:ReleaseTable(current_mo_cluster)
650 current_mo, current_mo_cluster = nil, nil
653 if not v.why.tracker_split then
654 if not mo_done[v.why] then
655 y, depth = addMetaObjective(v.why, metalookup[v.why], y, depth)
656 mo_done[v.why] = true
658 else
659 if not current_mo then
660 current_mo = v.why
661 current_mo_cluster = QuestHelper:CreateTable("tracker current cluster")
663 if not v.tracker_hidden then table.insert(current_mo_cluster, v) end
666 obj_done[v] = true
669 if current_mo and not (depth > QuestHelper_Pref.track_size and not debug_output) then
670 y, depth = addMetaObjective(current_mo, current_mo_cluster, y, depth)
672 if current_mo_cluster then
673 QuestHelper:ReleaseTable(current_mo_cluster)
677 -- now we check to see if we need a hidden display
678 if (debug_output or depth < QuestHelper_Pref.track_size) and not QuestHelper.loading_main and not QuestHelper_Pref.filter_done and not QuestHelper_Pref.filter_zone and not QuestHelper_Pref.filter_watched then
679 local show = false
681 QH_Route_TraverseClusters(
682 function (clust)
683 if not show then
684 QH_Route_IgnoredReasons_Cluster(clust, function (reason)
685 show = true
686 end)
688 for _, v in ipairs(clust) do
689 QH_Route_IgnoredReasons_Node(v, function (reason)
690 show = true
691 end)
697 if show then
698 y = y + 10
699 _, y = addItem(hidden_vquest1, y)
700 _, y = addItem(hidden_vquest2, y)
705 -- any manipulations of the tracker should be done by now, everything after this is bookkeeping
707 for k, v in pairs(used_items) do
708 if not used_count[k] or used_count[k] < #v then
709 local ttp = QuestHelper:CreateTable("used_items ttp")
710 for m = 1, (used_count[k] or 0) do
711 table.insert(ttp, v[m])
713 for m = (used_count[k] or 0) + 1, #v do
714 removeUnusedItem(v[m])
717 if used_items[k] then
718 QuestHelper:ReleaseTable(used_items[k])
721 if #ttp > 0 then
722 used_items[k] = ttp
723 else
724 used_items[k] = nil
725 QuestHelper:ReleaseTable(ttp)
730 QuestHelper:ReleaseTable(mo_done)
731 QuestHelper:ReleaseTable(obj_done)
732 for k, v in pairs(metalookup) do
733 QuestHelper:ReleaseTable(v)
735 QuestHelper:ReleaseTable(metalookup)
737 QuestHelper:ReleaseTable(used_count)
738 used_count = nil
740 if y ~= tracker.dh then
741 tracker.t = 0
742 tracker.sh = tracker:GetHeight()
743 tracker.dh = y
744 tracker.sw = tracker.dw
745 resizing = true
753 --[[
754 if x ~= tracker.dw or y ~= tracker.dy then
755 tracker.t = 0
756 tracker.sw, tracker.sh = tracker:GetWidth(), tracker:GetHeight()
757 tracker.dw, tracker.dh = x, y
758 resizing = true
759 end]]
761 --[[
763 local quests = QuestHelper.quest_log
764 local added = 0
765 local x, y = 4, 4
766 local gap = 0
767 local track_size = QuestHelper_Pref.track_size
768 local quests_added = {}
770 for quest, objs in pairs(used_items) do
771 for obj, item in pairs(objs) do
772 item.used = false
776 for i, objective in pairs(QuestHelper.route) do
777 if objective.watched then
778 obj_index_lookup[objective] = i
782 for q, data in pairs(QuestHelper.quest_log) do
783 quest_lookup[data.index] = q
786 -- Add our little "not yet loaded" notification
787 local loadedshow = false
788 if not QuestHelper.Routing.map_walker then
789 local count
790 x, y, gap, count = addobj(loading_vquest, seen, nil, nil, x, y, gap)
791 added = added + count
792 loadedshow = true
794 if QuestHelper_Flight_Updates and QuestHelper_Flight_Updates_Current and QuestHelper_Flight_Updates > 0 and QuestHelper_Flight_Updates_Current < QuestHelper_Flight_Updates then
795 loading_vquest.obj = string.format("7777/" .. QHFormat("QH_LOADING", string.format("%d", QuestHelper_Flight_Updates_Current * 100 / QuestHelper_Flight_Updates)))
799 -- Add an extra large gap to seperate the notification from everything else
800 gap = gap * 5
802 -- Add Quests that are watched but not in the route.
803 if UberQuest then
804 local uq_settings = UberQuest_Config[UnitName("player")]
805 if uq_settings then
806 local list = uq_settings.selected
807 if list then
808 local i = 1
809 while true do
810 local name = GetQuestLogTitle(i)
811 if not name then break end
812 quest_lookup[name] = quest_lookup[i]
813 i = i + 1
815 for name in pairs(list) do
816 local q = quest_lookup[name]
817 if q and not obj_index_lookup[q] then
818 local count
819 x, y, gap, count = addobj(q, seen, obj_index_lookup, nil, x, y, gap)
820 added = added + count
821 quests_added[q] = true
826 else
827 for i = 1,GetNumQuestWatches() do
828 local q = quest_lookup[GetQuestIndexForWatch(i)]
829 if q and not obj_index_lookup[q] then
830 local count
831 x, y, gap, count = addobj(q, seen, obj_index_lookup, nil, x, y, gap)
832 added = added + count
837 -- Add Quests that are watched and are in the route.
838 for i, objective in ipairs(QuestHelper.route) do
839 local count
840 x, y, gap, count = addobj(objective, seen, obj_index_lookup, watched_filter, x, y, gap)
841 added = added + count
842 quests_added[objective] = true
845 -- Add an extra large gap to seperate the watched objectives from the automatic objectives.
846 gap = gap * 5
848 -- Add Quests that aren't watched and are in the route.
849 if added <= track_size then
850 for i, objective in ipairs(QuestHelper.route) do
851 local count
852 x, y, gap, count = addobj(objective, seen, obj_index_lookup, nil, x, y, gap)
853 added = added + count
854 quests_added[objective] = true
856 if added > track_size then
857 break
862 if not loadedshow and added < track_size and not QuestHelper_Pref.filter_done and not QuestHelper_Pref.filter_zone and not QuestHelper_Pref.filter_watched then
863 local added = 0
864 local notadded = 0
865 for k, v in pairs(quest_lookup) do
866 if not quests_added[v] then
867 notadded = notadded + 1
868 else
869 added = added + 1
873 if notadded > 0 then
874 gap = gap * 10
875 x, y, gap, count = addobj(hidden_vquest1, seen, nil, nil, x, y, gap)
876 added = added + count
877 x, y, gap, count = addobj(hidden_vquest2, seen, nil, nil, x, y, gap)
878 added = added + count
882 for obj in pairs(obj_index_lookup) do
883 obj_index_lookup[obj] = nil
886 for key in pairs(quest_lookup) do
887 quest_lookup[key] = nil
890 for quest, objs in pairs(used_items) do
891 for obj, item in pairs(objs) do
892 if not item.used then
893 removeUnusedItem(quest, obj, item)
898 for key in pairs(seen) do
899 seen[key] = nil
902 y = y+4
904 if x ~= tracker.dw or y ~= tracker.dy then
905 tracker.t = 0
906 tracker.sw, tracker.sh = tracker:GetWidth(), tracker:GetHeight()
907 tracker.dw, tracker.dh = x, y
908 resizing = true
911 added = 0
915 function QH_Tracker_UpdateRoute(new_route)
916 route = new_route
917 QH_Tracker_Rescan()
920 function QH_Tracker_Pin(metaobjective, suppress)
921 if not pinned[metaobjective] then
922 pinned[metaobjective] = true
924 if not suppress then
925 QH_Tracker_Rescan()
930 function QH_Tracker_Unpin(metaobjective, suppress)
931 if pinned[metaobjective] then
932 pinned[metaobjective] = nil -- nil, not false, so it'll be garbage-collected appropriately
934 if not suppress then
935 QH_Tracker_Rescan()
940 function QH_Tracker_SetPin(metaobjective, flag, suppress)
941 if flag then
942 QH_Tracker_Pin(metaobjective, suppress)
943 else
944 QH_Tracker_Unpin(metaobjective, suppress)
949 local check_delay = 4
951 -- This function does the grunt work of cursor positioning and rescaling. It does not actually reorganize items.
952 function tracker:update(delta)
953 if not delta then
954 -- This is called without a value when the questlog is updated.
955 -- We'll make sure we update the display on the next update.
956 check_delay = 1e99
957 return
960 if resizing then
961 local t = self.t+delta
963 if t > 1 then
964 self:SetWidth(self.dw)
965 self:SetHeight(self.dh)
966 resizing = false
967 else
968 self.t = t
969 local it = 1-t
970 self:SetWidth(self.sw*it+self.dw*t)
971 self:SetHeight(self.sh*it+self.dh*t)
975 -- Manually checking if the mouse is in the frame, because if I used on OnEnter, i'd have to enable mouse input,
976 -- and if I did that, it would prevent the player from using the mouse to change the view if they clicked inside
977 -- the tracker.
978 local x, y = GetCursorPosition()
979 local s = 1/self:GetEffectiveScale()
980 x, y = x*s, y*s
982 QuestHelper: Assert(x)
983 QuestHelper: Assert(y)
984 --[[ QuestHelper: Assert(self:GetLeft())
985 QuestHelper: Assert(self:GetBottom())
986 QuestHelper: Assert(self:GetRight())
987 QuestHelper: Assert(self:GetTop())]]
989 -- Sometimes it just doesn't know its own coordinates. Not sure why. Maybe this will fix it.
990 local inside = (self:GetLeft() and (x >= self:GetLeft() and y >= self:GetBottom() and x < self:GetRight() and y < self:GetTop()))
991 if inside ~= was_inside then
992 was_inside = inside
993 if inside then
994 minbutton:SetAlpha(.5)
995 sigargh:SetAlpha(.5)
996 elseif not QuestHelper_Pref.track_minimized then
997 minbutton:SetAlpha(0)
998 sigargh:SetAlpha(0)
1002 check_delay = check_delay + delta
1003 if check_delay > 1 then
1004 check_delay = 0
1006 QH_Tracker_Rescan()
1010 QH_Hook(tracker, "OnUpdate", tracker.update)
1012 -- Some hooks to update the tracker when quests are added or removed. These should be moved into the quest director.
1013 --[[
1014 local orig_AddQuestWatch, orig_RemoveQuestWatch = AddQuestWatch, RemoveQuestWatch
1016 function AddQuestWatch(...)
1017 tracker:update()
1018 return orig_AddQuestWatch(...)
1021 function RemoveQuestWatch(...)
1022 tracker:update()
1023 return orig_RemoveQuestWatch(...)
1024 end]]
1026 -------------------------------------------------------------------------------------------------
1027 -- This batch of stuff is to make sure the original tracker (and any modifications) stay hidden
1029 local orig_TrackerBackdropOnShow -- bEQL (and perhaps other mods) add a backdrop to the tracker
1030 local TrackerBackdropFound = false
1032 local function TrackerBackdropOnShow(self, ...)
1033 if QuestHelper_Pref.track and not QuestHelper_Pref.hide then
1034 TrackerBackdropFound:Hide()
1037 if orig_TrackerBackdropOnShow then
1038 return orig_TrackerBackdropOnShow(self, ...)
1042 function tracker:HideDefaultTracker()
1043 -- The easy part: hide the original tracker
1044 WatchFrame_RemoveObjectiveHandler(WatchFrame_DisplayTrackedQuests)
1045 WatchFrame_ClearDisplay()
1046 WatchFrame_Update()
1048 -- The harder part: hide all those little buttons
1050 local index = 1
1051 while true do
1052 local orig = _G["WatchFrameItem" .. tostring(index)]
1053 if orig then orig:Hide() else break end
1054 index = index + 1
1058 -- The harder part: check if a known backdrop is present (but we don't already know about it).
1059 -- If it is, make sure it's hidden, and hook its OnShow to make sure it stays that way.
1060 -- Unfortunately, I can't figure out a good time to check for this once, so we'll just have
1061 -- to keep checking. Hopefully, this won't happen too often.
1062 if not TrackerBackdropFound then
1063 if QuestWatchFrameBackdrop then
1064 -- Found bEQL's QuestWatchFrameBackdrop...
1065 TrackerBackdropFound = QuestWatchFrameBackdrop
1068 if TrackerBackdropFound then
1069 -- OK, we found something - so hide it, and make sure it doesn't rear its ugly head again
1070 TrackerBackdropFound:Hide()
1072 orig_TrackerBackdropOnShow = TrackerBackdropFound:GetScript("OnShow")
1073 QH_Hook(TrackerBackdropFound, "OnShow", TrackerBackdropOnShow)
1078 function tracker:ShowDefaultTracker()
1079 -- I like how there's code explicitly to allow us to do this without checking if it's already added
1080 WatchFrame_AddObjectiveHandler(WatchFrame_DisplayTrackedQuests)
1081 -- Make sure the default tracker is up to date on what what's being watched and what isn't.
1082 WatchFrame_Update()
1084 if TrackerBackdropFound then
1085 TrackerBackdropFound:Show()
1089 function QuestHelper:ShowTracker()
1090 tracker:HideDefaultTracker()
1091 minbutton:Show()
1093 if QuestHelper_Pref.track_minimized then
1094 minbutton:SetAlpha(.3)
1095 sigargh:SetAlpha(.3)
1096 else
1097 minbutton:SetAlpha(0)
1098 sigargh:SetAlpha(0)
1099 tracker:Show()
1103 function QuestHelper:HideTracker()
1104 tracker:ShowDefaultTracker()
1105 tracker:Hide()
1106 minbutton:Hide()