· 8 years ago · May 21, 2018, 07:04 PM
1
2local LQI = LibStub("LibQuestInfo")
3
4local DEBUG_MODE = true
5QUESTTRACKER_DEBUG_TABLE = {}
6
7local ADDON_NAME = "Ravalox'QuestTracker"
8local VERSION_CODE = "3.6.0.0"
9
10local CONSTRAINT_WIDTH = 100
11local CONSTRAINT_HEIGHT = 60
12-- I cut it close on the right hand border, there is practically no padding
13-- If text gets cut off, try changing this, but no more than +5
14-- If it takes that much then something is wrong, let me know & I'll look into it.
15local TEXT_LABEL_PADDING = 0
16
17local colorYellow = "|cFFFF00" -- yellow
18local colorSoftYellow = "|cCCCC00" -- Duller Yellow for Description
19local colorRed = "|cFF0000" -- Red
20local colorRavalox = "|cB60000" -- Ravalox Red -- B6 = Red 182 a brighter 82 red
21local colorCMDBlue = "|c1155bb" -- Dull blue used to indicate "typable" text
22--[[
23the game calls forceAssist on more than one quest before a final starting quest is arrived at. This will block us from wasting time selecting & displaying auto-tooltips for those quests until the player is completely activated and all game callbacks have been fired to prevent displaying an auto-tooltip on load, reloadUI, & zoning and from leaving nodes open the user did not open themselves, if they have exclusitivity turned off & the game selects random quests.
24--]]
25local ALLOW_QUEST_ASSIST_CALLBACK = false
26local SORT_TYPE_QUEST_CATEGORIES = 1
27local SORT_TYPE_QUESTS = 2
28local USER_REQUESTED_OPEN = true
29
30local QuestTracker = ZO_Object:New()
31
32--=====================================================--
33--======= DEBUG =========--
34--=====================================================--
35local function debugMsg(msg, tableItem)
36 if not DEBUG_MODE then return end
37
38 if msg and msg ~= "" then
39 d(msg)
40 table.insert(QUESTTRACKER_DEBUG_TABLE, msg)
41 end
42
43 -- Used to save object references for later examination:
44 if tableItem then
45 table.insert(QUESTTRACKER_DEBUG_TABLE, tableItem)
46 end
47end
48
49--=====================================================--
50--======= BACKDROP FUNCTIONS =========--
51--=====================================================--
52local backdrops = {
53 [1] = {name = "None"},
54 [2] = {name = "Fancy"},
55 [3] = {name = "Colored"},
56}
57 -- Used in settings menu to populate choices
58function QuestTracker:GetBackdropChoices()
59 local choices = {}
60 for k,v in ipairs(backdrops) do
61 choices[#choices+1] = v.name
62 end
63 return choices
64end
65
66--=====================================================--
67--======= FONT FUNCTIONS =========--
68--=====================================================--
69local NodeFonts = {
70 [1] = {name = "Bold", font = "BOLD_FONT"},
71 [2] = {name = "Medium", font = "MEDIUM_FONT"},
72 [3] = {name = "Chat", font = "CHAT_FONT"},
73 [4] = {name = "Antique", font = "ANTIQUE_FONT"},
74 [5] = {name = "Handwritten", font = "HANDWRITTEN_FONT"},
75 [6] = {name = "Stone Tablet", font = "STONE_TABLET_FONT"},
76 [7] = {name = "Gamepad Bold", font = "GAMEPAD_BOLD_FONT"},
77 [8] = {name = "Gamepad Medium", font = "GAMEPAD_MEDIUM_FONT"},
78 [9] = {name = "Arial Narrow", font = "univers55"},
79}
80 -- Used in settings menu to populate choices
81function QuestTracker:GetFontChoices()
82 local choices = {}
83
84 for k,v in ipairs(NodeFonts) do
85 choices[#choices+1] = v.name
86 end
87 return choices
88end
89function QuestTracker:GetFontByName(name)
90 for k,v in ipairs(NodeFonts) do
91 if v.name == name then
92 return v.font
93 end
94 end
95 return "ZoFontHeader"
96end
97
98-- Font outline
99local NodeOutlines = {
100 [1] = {name = "None"},
101 [2] = {name = "Soft Thick Shadow", outline = "soft-shadow-thick"},
102 [3] = {name = "Soft Thin Shadow", outline = "soft-shadow-thin"},
103 [4] = {name = "Shadow", outline = "shadow"},
104}
105function QuestTracker:GetOutlineChoices()
106 local choices = {}
107
108 for k,v in ipairs(NodeOutlines) do
109 choices[#choices+1] = v.name
110 end
111 return choices
112end
113
114function QuestTracker:GetOutlineByName(outlineName)
115 for k,v in ipairs(NodeOutlines) do
116 if v.name == outlineName then
117 return v.outline
118 end
119 end
120end
121
122
123-- font string layout example: "$(BOLD_FONT)|30|soft-shadow-thick"
124function QuestTracker:BuildFontString(font, size, outline)
125 local fontString = zo_strformat("$(<<1>>)|<<2>>", font,size)
126 --
127 if outline then
128 fontString = zo_strformat("<<1>>|<<2>>", fontString,outline)
129 end
130 --]]
131 return fontString
132end
133
134function QuestTracker:GetCategoryFontString()
135 local categoryFontSettings = self.svCurrent.fontSettings.categories
136 local font = self:GetFontByName(categoryFontSettings.font)
137 local fontOutline = self:GetOutlineByName(categoryFontSettings.outline)
138 local fontSize = categoryFontSettings.size
139
140 return self:BuildFontString(font, fontSize, fontOutline)
141end
142
143function QuestTracker:GetQuestFontString()
144 local questFontSettings = self.svCurrent.fontSettings.quests
145 local font = self:GetFontByName(questFontSettings.font)
146 local fontOutline = self:GetOutlineByName(questFontSettings.outline)
147 local fontSize = questFontSettings.size
148
149 return self:BuildFontString(font, fontSize, fontOutline)
150end
151function QuestTracker:GetConditionFontString()
152 local conditionFontSettings = self.svCurrent.fontSettings.conditions
153 local font = self:GetFontByName(conditionFontSettings.font)
154 local fontOutline = self:GetOutlineByName(conditionFontSettings.outline)
155 local fontSize = conditionFontSettings.size
156
157 return self:BuildFontString(font, fontSize, fontOutline)
158end
159
160--===========================================================--
161--======= HOOKS =========--
162--===========================================================--
163-- Handles when quests are added/removed. List must be repopulated instead of manually adding/removing
164-- a single quest because the game calls this function and the quest indices may change. Rather than
165-- trying to loop through our entire tree, compare the data and fix things, we just repopulate
166-- the tree by wiping it & recreating it.
167-- Updates are handled differently
168local OrigRefreshQuestMasterList = ZO_QuestJournal_Keyboard.RefreshQuestMasterList
169function ZO_QuestJournal_Keyboard:RefreshQuestMasterList()
170 OrigRefreshQuestMasterList(self)
171
172 QUESTTRACKER:RepopulateQuestTree()
173end
174
175-- QUESTTRACKER must be passed in because it does not exist yet
176local function HookUpdateCurrentChildrenHeightsToRoot(QUESTTRACKER)
177 local rootNode = QUESTTRACKER.navigationTree.rootNode
178 local metaTable = getmetatable(rootNode)
179 local origUpdateCurrentChildrenHeightsToRoot = metaTable.UpdateCurrentChildrenHeightsToRoot
180
181 function metaTable.UpdateCurrentChildrenHeightsToRoot(self)
182 origUpdateCurrentChildrenHeightsToRoot(self)
183 QUESTTRACKER:UpdateCurrentChildrenWidthsToRoot(self)
184
185 if QUESTTRACKER.svCurrent.mainWindow.autoWindowSizeWidth then
186 QUESTTRACKER:AutoSizeWinWidth()
187 end
188
189 if QUESTTRACKER.svCurrent.mainWindow.autoWindowSizeHeight then
190 QUESTTRACKER:AutoSizeWinHeight()
191 end
192 end
193end
194
195--===========================================================--
196--======= LOCAL REGISTERED CALLBACK/EVENT FUNCTIONS =========--
197--===========================================================--
198-- Registered callback for QuestTrackerAssistStateChanged, to select the quest
199-- which, in turn, scrolls the node into view.
200local function OnAssistChanged(self, unassistedData, assistedData)
201 if not assistedData then return end
202 local questIndex = assistedData.arg1
203
204 --[[ ALLOW_QUEST_ASSIST_CALLBACK is used here because the game fires this more than once on load, before finally deciding what quest should be originally selected, this blocks that so random auto-tooltips don't get displayed on load and so that nodes don't get opened by those random calls and left open if the user has node exclusitivity off.
205 --]]
206 if questIndex and ALLOW_QUEST_ASSIST_CALLBACK then
207 self:SelectQuestIndexNode(questIndex, true)
208
209 if self.svCurrent.tooltips.autoTooltip and not QUESTTRACKER.WINDOW_FRAGMENT:IsHidden() then
210 self:ShowQuestTooltip(questIndex)
211
212 local fadeTime = self.svCurrent.tooltips.fadeTime*1000
213 EVENT_MANAGER:RegisterForUpdate("QuestTrackerClearAutoTooltip", fadeTime, function()
214 ClearTooltip(InformationTooltip)
215 EVENT_MANAGER:UnregisterForUpdate("QuestTrackerClearAutoTooltip")
216 end)
217 end
218 end
219end
220
221-- This is cheesy, but the node won't scroll into view on player activation. The scroll
222-- doesn't have its extents updated yet & its still 0 so it can't scroll, must delay.
223local function OnPlayerActivated()
224 zo_callLater(function() QUESTTRACKER:RefreshSelectedQuest() end, 10)
225
226 -- Allow auto-tooltips after the player has completely activated AND the game has finished firing all
227 -- callbacks for setting the current quest to prevent displaying an auto-tooltip on load, reloadUI, & zoning
228 zo_callLater(function() ALLOW_QUEST_ASSIST_CALLBACK = true end, 100)
229
230 -- Initialize the ingame questtracker state. Needed to ensure ZOS QT is hidden on initial load of the addon or a new character.
231 local newSetting = QUESTTRACKER.svCurrent.hideDefaultQuestTracker and "false" or "true"
232 SetSetting(SETTING_TYPE_UI, UI_SETTING_SHOW_QUEST_TRACKER, newSetting)
233end
234
235local function OnPlayerDeactivated()
236 -- Set to false to block auto-tooltips until the player is completely Re-activated
237 ALLOW_QUEST_ASSIST_CALLBACK = false
238end
239
240local function OnQuestAdded(eventCode, journalIndex, questName)
241 local chatAlertType = QUESTTRACKER.svCurrent.chatAlertType
242
243 if QUESTTRACKER.svCurrent.questTrackForceAssist then
244 FOCUSED_QUEST_TRACKER:ForceAssist(journalIndex)
245 end
246
247 if chatAlertType == "Off" then return end
248
249 local fQuestName = zo_strformat(SI_QUEST_JOURNAL_QUEST_NAME_FORMAT, questName)
250 local darkOrange = "FFA500"
251 local questAddedMsg = zo_strformat("|c<<1>><<2>>:|r <<3>>", darkOrange, "Quest Added: ", fQuestName)
252
253 if chatAlertType == "Detailed" then
254 local isValid, questData = LQI:GetCurrentQuestStepInfo(journalIndex)
255
256 if isValid then
257 questAddedMsg = zo_strformat("|c<<1>><<2>>:|r <<3>>", darkOrange, fQuestName, questData.stepText)
258 end
259 end
260 d(questAddedMsg)
261end
262
263-- called on event EVENT_LEVEL_UPDATE
264local function OnLevelUpdate(eventCode, unitTag, level)
265 if unitTag ~= "player" then return end
266
267 -- This will update all nodes, forcing their setup functions to fire. Specifically we want
268 -- all of the QuestNodeSetup 's to fire so they will recall GetCon(nodeData.level) & RefreshTextColor()
269 QUESTTRACKER.navigationTree:RefreshVisible()
270end
271
272-- Called on events EVENT_QUEST_ADVANCED & EVENT_QUEST_CONDITION_COUNTER_CHANGED
273-- If you have problems with quests not updating properly...this is where to start looking
274local function OnQuestUpdate(eventCode, journalIndex)
275 QUESTTRACKER:UpdateQuest(journalIndex)
276end
277
278-- temporary test, split up for debug messages
279local function OnQuestAdvanced(eventCode, journalIndex)
280 OnQuestUpdate(eventCode, journalIndex)
281end
282
283-- temporary test, split up for debug messages
284local function OnQuestCondtionChange(eventCode, journalIndex)
285 OnQuestUpdate(eventCode, journalIndex)
286end
287
288-- if the user toggles the "Show quest tracker" setting, update it in settings
289local function OnInterfaceSettingChanged(eventCode, system, settingId)
290 if not system == SETTING_TYPE_UI then return end
291 if not settingId == UI_SETTING_SHOW_QUEST_TRACKER then return end
292
293 local newValue = not GetSetting_Bool(SETTING_TYPE_UI, UI_SETTING_SHOW_QUEST_TRACKER)
294
295 if QUESTTRACKER_HIDEDEFAULTQUESTTRACKERWINDOW then
296 QUESTTRACKER_HIDEDEFAULTQUESTTRACKERWINDOW:UpdateValue(false, newValue)
297 ZO_FocusedQuestTracker:UpdateVisibility (false, newValue)
298 end
299end
300
301-- hide QT window when in combat
302local function OnCombatStateChange(eventCode, isInCombat)
303 local svCurrent = QUESTTRACKER.svCurrent
304 -- If its manually hidden or the combat hide feature is off do nothing
305 if svCurrent.hideQuestWindow or not QUESTTRACKER.svCurrent.hideInCombat then return end
306
307 if isInCombat then
308 QUESTTRACKER.questTreeWin:SetHidden(true)
309 return
310 end
311 QUESTTRACKER.questTreeWin:SetHidden(false)
312end
313
314--=====================================================--
315--======= QuestTracker NEW/INITIALIZE FUNCTIONS =========--
316--=====================================================--
317function QuestTracker:New()
318 -- First setup references:
319 self.questTreeWin = QuestTrackerWin
320 self.backdrop = QuestTrackerWinBackdrop
321 self.dragBar = QuestTrackerWinDragBar
322 self.lockBtn = QuestTrackerWinLockBtn
323 self.unlockBtn = QuestTrackerWinUnlockBtn
324 self.navigationContainer = QuestTrackerWinNavigationContainer
325 self.codeVersion = VERSION_CODE
326
327 -- Here just in case I need it for later I wont have to look it up again.
328 --ZO_HIGHLIGHT_TEXT = ZO_ColorDef:New(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_HIGHLIGHT))
329 --ZO_NORMAL_TEXT = ZO_ColorDef:New(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_NORMAL))
330 --ZO_DISABLED_TEXT = ZO_ColorDef:New(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_DISABLED))
331 --ZO_SELECTED_TEXT = ZO_ColorDef:New(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
332 local norm = ZO_NORMAL_TEXT
333 self.FONT_COLOR_NORMAL_DEFAULT = {norm.r, norm.g, norm.b, norm.a}
334
335 -- Then setup the UI & everything else
336 local defaultSV = {
337 mainWindow = {
338 offsetX = 100,
339 offsetY = 100,
340 width = 300,
341 height = 400,
342 locked = false,
343 isItLocked = false,
344 hideLockIcon = "Never",
345 hideQuestWindow = false,
346 --hideWithUI = false,
347 showInGameScene = false,
348 autoWindowSizeHeight = true,
349 autoWindowSizeWidth = true,
350 backdrop = {
351 backdropName = "Colored", -- defaults to none in code
352 backdropAlpha = .5, --1,
353 backdropColor = {0,0,0,.5}, --{.25, .25, .25, 1},
354 dragBarColor = {1,1,1,.5},
355 hideMungeOverlay = false,
356 backdropHideOnLock = false,
357 },
358 },
359 fontSettings = {
360 categories = {
361 font = "Bold",
362 outline = "Soft Thick Shadow",
363 size = 20,
364 color = self.FONT_COLOR_NORMAL_DEFAULT,
365 },
366 quests = {
367 font = "Bold",
368 outline = "Soft Thick Shadow",
369 size = 16,
370 color = self.FONT_COLOR_NORMAL_DEFAULT,
371 },
372 conditions = {
373 font = "Bold",
374 outline = "Soft Thick Shadow",
375 size = 14,
376 color = self.FONT_COLOR_NORMAL_DEFAULT,
377 },
378 },
379 nodeExclusitivity = {
380 currentSetting = "None",
381 allNodes = false,
382 categoryNodes = false,
383 questNodes = false,
384 isTreeExclusive = false,
385 },
386 tooltips = {
387 show = true,
388 anchorPoint = LEFT,
389 relativeTo = RIGHT,
390 autoTooltip = false,
391 fadeTime = 5,
392 },
393 autoOpenNodes = false,
394 autoOpenCategoryOnLogin = false,
395 showQuestLevel = true,
396 showNumCategoryQuests = true,
397 overrideConColors = false,
398 chatAlertType = "Detailed",
399 questTrackForceAssist = true,
400 accountWide = true,
401 hideDefaultQuestTracker = true,
402 hideFocusedQuestTracker = true,
403 hideInCombat = true, -- Hide RQT window when in combat
404 sortByLevel = true, -- Sort Quests by level
405 }
406
407 --********************************************************************************************--
408 -- SavedVar stuff MUST be done before inializing the tree
409 --********************************************************************************************--
410 -- Will hold the saved vars, either: accountwdie or per character:
411 self.svCurrent = {}
412
413 self.svAccount = ZO_SavedVars:NewAccountWide("QuestTrackerSavedVars", 3.0, nil, defaultSV)
414 self.svCharacter = ZO_SavedVars:New("QuestTrackerSavedVars", 3.0, nil, defaultSV)
415 self:SwapSavedVars(self.svAccount.accountWide)
416 --********************************************************************************************--
417
418 -- Initialize HotKeys
419 ZO_CreateStringId("SI_BINDING_NAME_QUESTTRACKER_TOGGLE_MAIN_WINDOW", "Toggle the Quest Tracker Window")
420
421 -- Setup the tree
422 local scrollChild = self.questTreeWin:GetNamedChild("NavigationContainerScrollChild")
423 local navigationTree = ZO_Tree:New(scrollChild, 25, 0, 1000)
424
425 self.navigationTree = navigationTree
426
427 self:InitializeTree() -- initialize the tree, must be done before Initialize()
428
429 self:Initialize() -- initialize everything else
430
431 return self
432end
433
434-- Initialize everything else
435function QuestTracker:Initialize()
436 local svMainWindow = self.svCurrent.mainWindow
437
438 self:InitializeWindow()
439
440 HookUpdateCurrentChildrenHeightsToRoot(self) -- do before population so it auto-fires resize
441
442 self:RepopulateQuestTree() -- populates the tree with categories/quests/conditions
443
444 QuestTracker_CreateSettingsMenu(self)
445
446 -- Sets the selected quest in our tree, whenever it is changed somewhere else
447 FOCUSED_QUEST_TRACKER:RegisterCallback("QuestTrackerAssistStateChanged", function(unassistedData, assistedData) OnAssistChanged(self, unassistedData, assistedData) end)
448
449 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_INTERFACE_SETTING_CHANGED, OnInterfaceSettingChanged)
450 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_QUEST_CONDITION_COUNTER_CHANGED, OnQuestCondtionChange)
451 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_QUEST_ADDED, OnQuestAdded) -- only for chat window alert
452 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_PLAYER_ACTIVATED, OnPlayerActivated)
453 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_PLAYER_DEACTIVATED, OnPlayerDeactivated)
454 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_QUEST_ADVANCED, OnQuestAdvanced)
455 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_LEVEL_UPDATE, OnLevelUpdate) -- To update con colors when leveling
456 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_PLAYER_COMBAT_STATE, OnCombatStateChange) -- To hide QT when in combat
457
458 -- Auto open options
459 if self.svCurrent.autoOpenNodes then
460 self:OpenAllQuestNodes()
461 end
462
463 if self.svCurrent.autoOpenCategoryOnLogin then
464 self:OpenSelectedCategoryQuestNodes()
465 end
466
467 -- Since we can't add/remove quests and must instead repopulate the entire tree when these happen
468 -- because the game calls RefreshQuestMasterList at which time
469 -- quest indices may change and it also calls RefreshQuestMasterList on init during zone changes.
470 -- Were not going to use these, but instead just hook the RefreshQuestMasterList instead.
471 -- If we registered these & hooked RefreshQuestMasterList every time one of these events fired
472 -- our code would get run twice, once for the event firing & once for the RefreshQuestMasterList firing.
473 --EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_QUEST_ADDED, OnQuestAdded)
474 --EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_QUEST_REMOVED, OnQuestRemoved)
475 --EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_QUEST_LIST_UPDATED, function() self:RepopulateQuestTree() end)
476end
477
478function QuestTracker:InitializeWindow()
479 local svMainWindow = self.svCurrent.mainWindow
480 local offsetX = svMainWindow.offsetX
481 local offsetY = svMainWindow.offsetY
482 local width = svMainWindow.width
483 local height = svMainWindow.height
484 local isItLocked = svMainWindow.isItLocked
485
486 self.questTreeWin:ClearAnchors()
487 self.questTreeWin:SetAnchor(TOPLEFT, nil, TOPLEFT, offsetX, offsetY)
488 self.questTreeWin:SetDimensions(width, height)
489
490 self:UpdateBackdrop(svMainWindow.backdrop.backdropName)
491 self:SetLockState(svMainWindow.isItLocked)
492
493 local WINDOW_FRAGMENT = ZO_HUDFadeSceneFragment:New(self.questTreeWin)
494 self.WINDOW_FRAGMENT = WINDOW_FRAGMENT
495
496 --Automatically show QuesTracker when game says to
497 HUD_SCENE:AddFragment(WINDOW_FRAGMENT)
498 HUD_UI_SCENE:AddFragment(WINDOW_FRAGMENT)
499
500 --Use this with force show setting in options above "auto" lines override this (use either those or this)
501 -- wtf? lol thats obviously not one of my comments !!!
502 -- Add/Remove fragment from the GAME_MENU_SCENE
503 QuestTracker:SetupFragmentForGameScene(svMainWindow.showInGameScene)
504
505 self:UpdateWindowVisibility(self.svCurrent.mainWindow.hideQuestWindow)
506end
507
508--===========================================================--
509--==================== UTILITY CODE =========================--
510--===========================================================--
511
512function QuestTracker:SwapSavedVars(useAccountWide)
513 if useAccountWide then
514 self.svCurrent = self.svAccount
515 else
516 self.svCurrent = self.svCharacter
517 end
518end
519
520function QuestTracker_ToggleWindow()
521 local questWindow = QUESTTRACKER.questTreeWin
522 local svMainWindow = QUESTTRACKER.svCurrent.mainWindow
523 local hideQuestWindow = not svMainWindow.hideQuestWindow
524 svMainWindow.hideQuestWindow = hideQuestWindow
525
526 QUESTTRACKER.WINDOW_FRAGMENT:SetHiddenForReason("QuestTracker_UserSetting_Hidden", hideQuestWindow)
527end
528
529function QuestTracker:UpdateWindowVisibility(shouldHide)
530 local hideQuestWindow = shouldHide or self.svCurrent.mainWindow.hideQuestWindow
531
532 self.WINDOW_FRAGMENT:SetHiddenForReason("QuestTracker_UserSetting_Hidden", hideQuestWindow)
533end
534
535-- your shouldHide doesn't match with what its doing. It says if shouldHide then add it to the scene
536-- which makes it visible. Thats not hiding it. Changing it.
537function QuestTracker:SetupFragmentForGameScene(showInGameScene) -- for force show setting
538 local showInGameScene = showInGameScene or self.svCurrent.mainWindow.showInGameScene
539 local WINDOW_FRAGMENT = self.WINDOW_FRAGMENT
540
541 if showInGameScene then
542 GAME_MENU_SCENE:AddFragment(WINDOW_FRAGMENT)
543 else
544 GAME_MENU_SCENE:RemoveFragment(WINDOW_FRAGMENT)
545 end
546end
547
548-- Auto Size functions
549function QuestTracker:AutoSizeWinHeight()
550 if not self.svCurrent.mainWindow.autoWindowSizeHeight then return end
551
552 local childrenCurrentHeight = self.navigationTree.rootNode.childrenCurrentHeight
553 local win = self.questTreeWin
554
555 local width, height = win:GetDimensions()
556 local dragBarHeight = self.dragBar:GetHeight()
557
558 -- +5 is padding for the -5 offsetY anchor on the navigationContainer
559 -- +2 to prevent the scrollbar from flashing as the extents change
560 height = childrenCurrentHeight+dragBarHeight+7
561
562 win:SetDimensions(width, height)
563end
564
565function QuestTracker:AutoSizeWinWidth()
566 if not self.svCurrent.mainWindow.autoWindowSizeWidth then return end
567
568 local maxNodeWidth = self.navigationTree.width
569
570 local win = self.questTreeWin
571 local width, height = win:GetDimensions()
572
573 -- Padding for scrollbar width 16 + navigationContainer both offsetX anchors left & right 5 each (in xml)
574 win:SetDimensions(maxNodeWidth+26, height)
575end
576
577-- Calculates & returns the container width required for treeNode and all of its children.
578function QuestTracker:CalculateNodeContainerWidths(treeNode, totalIndent)
579 local children = treeNode.children
580 local treeNodeIndent = totalIndent or 0
581 local treeNodeWidth = (treeNode.totalControlWidth or 0) + treeNodeIndent
582 local containerWidth = 0
583
584 if(children and treeNode:IsOpen()) then
585 local childIndent = treeNodeIndent+treeNode.childIndent
586
587 for i = 1, #children do
588 local childNode = children[i]
589 local childContainerWidth = self:CalculateNodeContainerWidths(childNode, childIndent)
590
591 containerWidth = zo_max(containerWidth, childNode.totalControlWidth+childIndent, childContainerWidth)
592 end
593 end
594 containerWidth = zo_max(treeNodeWidth, containerWidth)
595
596 treeNode.containerWidth = containerWidth
597 treeNode.NodeIsIndentedBy = treeNodeIndent
598
599 return containerWidth
600end
601
602
603function QuestTracker:UpdateCurrentChildrenWidthsToRoot()
604 local tree = self.navigationTree
605 local rootNode = tree.rootNode
606 local rootContainerWidth = self:CalculateNodeContainerWidths(rootNode)
607
608 tree.width = rootContainerWidth
609 tree.control:SetWidth(rootContainerWidth)
610
611 local function UpdateChildWidths(treeNode)
612 local control = treeNode.control
613 local childContainer = treeNode.childContainer
614 local children = treeNode.children
615 local containerWidth = treeNode.containerWidth
616
617 if control then
618 control:SetWidth(containerWidth)
619 end
620 if childContainer then
621 childContainer:SetWidth(containerWidth)
622 end
623
624 if(children) then
625 for i = 1, #children do
626 local child = children[i]
627 UpdateChildWidths(child)
628 end
629 end
630 end
631 UpdateChildWidths(rootNode)
632end
633
634function QuestTracker:ScrollQuestNodeIntoView(questIndex, questNode)
635 local questNode = questNode or self.navigationTree.questIndexToTreeNode[questIndex]
636
637 if questNode then
638 ZO_Scroll_ScrollControlIntoCentralView(self.navigationContainer, questNode.control)
639 end
640end
641
642-- Get the tree node for the currently selected quest. If it exists, set that node selected
643function QuestTracker:SelectQuestIndexNode(questIndex, scrollIntoView)
644 local selectedQuestNode = self.navigationTree.questIndexToTreeNode[questIndex]
645
646 if selectedQuestNode then
647 selectedQuestNode:OnSelected()
648
649 if scrollIntoView then
650 self:ScrollQuestNodeIntoView(questIndex, selectedQuestNode)
651 end
652 end
653end
654
655function QuestTracker:RefreshSelectedQuest()
656 local selectedQuestIndex = QUEST_JOURNAL_MANAGER:GetFocusedQuestIndex()
657
658 self:SelectQuestIndexNode(selectedQuestIndex, true)
659end
660
661function QuestTracker:ShowQuestTooltip(questIndex)
662 if QUESTTRACKER.WINDOW_FRAGMENT:IsHidden() then return end
663
664 local svTooltips = self.svCurrent.tooltips
665 local anchorPoint = svTooltips.anchorPoint
666 local relativeTo = svTooltips.relativeTo
667
668 -- In case auto-tooltips are on & a tooltip was just set...and the user
669 -- mouses over a quest node, which opens a new tooltip. We don't want it to fade until the user
670 -- exits the node with the mouse, so cancel auto registered ClearTooltip
671 EVENT_MANAGER:UnregisterForUpdate("QuestTrackerClearAutoTooltip")
672
673 InitializeTooltip(InformationTooltip, self.questTreeWin, anchorPoint, 0, 0, relativeTo)
674
675 LQI:CreateQuestTooltip(questIndex, InformationTooltip)
676end
677
678function QuestTracker:SetLockState(lock)
679 local lockBtn = self.lockBtn
680 local unlockBtn = self.unlockBtn
681 local mainWin = self.questTreeWin
682 local svMainWindow = self.svCurrent.mainWindow
683 local svMainWindowBackdrop = svMainWindow.backdrop
684
685 svMainWindow.isItLocked = lock
686
687 local isWindowLocked = lock
688 local isWindowUnlocked = not lock
689
690 if svMainWindow.hideLockIcon == "Never" then
691 lockBtn:SetHidden(isWindowUnlocked)
692 lockBtn:SetEnabled(isWindowLocked)
693 unlockBtn:SetHidden(isWindowLocked)
694 unlockBtn:SetEnabled(isWindowUnlocked)
695 elseif svMainWindow.hideLockIcon == "Always" then
696 unlockBtn:SetHidden(true)
697 lockBtn:SetHidden(true)
698 elseif svMainWindow.hideLockIcon == "Locked" then
699 lockBtn:SetHidden(true)
700 unlockBtn:SetHidden(isWindowLocked)
701 unlockBtn:SetEnabled(isWindowUnlocked)
702 end
703
704 mainWin:SetMovable(isWindowUnlocked)
705 mainWin:SetMouseEnabled(isWindowUnlocked)
706
707 if not svMainWindowBackdrop.backdropHideOnLock then return end
708
709 local backdropControl = self.backdrop
710 local dragBar = self.dragBar
711 local isBackdropHidden = backdropControl:IsHidden()
712
713 if isWindowLocked and not isBackdropHidden then
714 backdropControl:SetHidden(true)
715 dragBar:SetHidden(true)
716 end
717
718 if isWindowUnlocked and isBackdropHidden then
719 if svMainWindowBackdrop.backdropName ~= "None" then
720 backdropControl:SetHidden(false)
721 dragBar:SetHidden(false)
722 end
723 end
724end
725
726-- DONT try to compare condition nodes. I did not write an equality function for them
727-- we don't need it. Were not updating condition nodes. When needed we wipe them out & re-add them.
728function QuestTracker:AreTreeNodesEqual(treeNode1, treeNode2)
729 if treeNode1.equalityFunction == treeNode2.equalityFunction then
730 if treeNode1.equalityFunction(treeNode1.data, treeNode2.data) then
731 return true
732 end
733 end
734 return false
735end
736
737--===========================================================--
738--=========== ADD/REMOVE NODE UTILITY CODE ==================--
739--===========================================================--
740function QuestTracker:UpdateChildHeightsToRoot(treeNode)
741 treeNode:UpdateChildrenHeightsToRoot()
742 treeNode:UpdateCurrentChildrenHeightsToRoot()
743
744 -- widths are now updated in the hook on UpdateCurrentChildrenHeightsToRoot()
745end
746
747-- When removing a node, this is used to reanchor the previous node to the next node
748function QuestTracker:AnchorPreviousNodeToNextNode(nodeToRemove)
749 local previousNode = self:GetPreviousNode(nodeToRemove)
750 local parentNode = nodeToRemove.parentNode
751 local nextNode = nodeToRemove.nextNode
752
753 if nextNode then
754 local childControl = nextNode:GetControl()
755 -- This is not needed, nextNode is already a sibling, were only ever reanchoring siblings
756 childControl:SetParent(parentNode.childContainer)
757
758 if(previousNode) then
759 previousNode:AttachNext(nextNode)
760 else
761 childControl:ClearAnchors()
762 childControl:SetAnchor(TOPLEFT, parentNode.childContainer, TOPLEFT, parentNode.childIndent, 0)
763 end
764 end
765
766 self:UpdateChildHeightsToRoot(parentNode)
767end
768
769-- Used to get the previous node, to reanchor nodes, when removing a node
770function QuestTracker:GetPreviousNode(treeNode)
771 local parentNode = treeNode.parentNode
772 local siblingsTable = parentNode.children
773 local next = next
774
775 if not siblingsTable or next(siblingsTable) == nil then return end
776
777 for k, siblingNode in pairs(siblingsTable) do
778 if self:AreTreeNodesEqual(treeNode, siblingNode)then
779
780 -- If treeNode is the first indexed child, this will be k-1 = 0 & it will return nil, thats ok
781 -- It is expected to return nil if treeNode is the first child
782 return siblingsTable[k-1]
783 end
784 end
785end
786
787-- Used to get the table index for a treeNode, when removing nodes, so that after we
788-- release all of the node objects we can remove the node reference from the node table.
789function QuestTracker:GetNodeTableIndex(treeNode)
790 local parentNode = treeNode.parentNode
791 local siblingsTable = parentNode.children
792
793 for tableIndex, siblingNode in pairs(siblingsTable) do
794 if self:AreTreeNodesEqual(treeNode, siblingNode)then
795 return tableIndex
796 end
797 end
798end
799
800-- When creating a new Category node this is used to get the categories default table data
801function QuestTracker:GetDefaultCategoryNodeData(categoryName, allCategories)
802 for k, categoryData in pairs(allCategories) do
803 if categoryData.name == categoryName then
804 return categoryData
805 end
806 end
807end
808
809-- When we add quest nodes, this is used to get the correct parent (category) node
810-- This happens before the quest node is created, so we can't use questNode.parentNode...we
811-- need to know what categoryNode to create the quest node under
812function QuestTracker:GetCategoryNodeByName(categoryName)
813 local rootChildren = self.navigationTree.rootNode.children
814
815 for k, categoryNode in ipairs(rootChildren) do
816 if categoryNode.data.name == categoryName then
817 return categoryNode
818 end
819 end
820end
821
822-- Add step & condition info to the questData table
823local function AddStepConditionInfo(questData)
824 local questInfo = LQI:GetCurrentQuestInfo(questData.questIndex)
825
826 local trackerOverrideText = questInfo.trackerOverrideText
827 questData.stepIndex = questInfo.stepIndex -- Only for /zgoo debugging, not used
828 questData.stepText = questInfo.stepText -- Only for /zgoo debugging, not used
829 questData.trackerOverrideText = trackerOverrideText
830
831 -- This really isn't a condition, but we want to display it like one if it exists instead of the conditions.
832 -- BE AWARE, by doing this it means that other condition info you see in the condition tables like
833 -- current, isComplete, isCreditShared, exc... will not always be available in the table...here we will
834 -- only store the tracker override text because thats what is suppposed to be displayed & it does not belong
835 -- to any single condition, so we can't just copy another conditions info...there may not even be any
836 -- other conditions.
837 if(trackerOverrideText and trackerOverrideText ~= "") then
838 local fOverrideStepText = zo_strformat(SI_QUEST_HINT_STEP_FORMAT, trackerOverrideText)
839
840 questData.conditions = {
841 [1] = {conditionText = fOverrideStepText},
842 }
843 else
844 questData.conditions = questInfo.conditions
845 end
846
847 return questData
848end
849
850--===========================================================--
851--================ SORT/REANCHOR CODE =======================--
852--===========================================================--
853-- Called from SortChildrenByType to reanchor the children after they have been sorted
854function QuestTracker:ReanchorChildren(parentNode)
855 local siblingsTable = parentNode.children
856
857 if not siblingsTable then return end
858
859 local previousNode = nil
860
861 for _, treeNode in ipairs(siblingsTable) do
862 treeNode.nextNode = nil
863
864 if previousNode then
865 previousNode:AttachNext(treeNode)
866 else
867 local treeNodeControl = treeNode:GetControl()
868 treeNodeControl:ClearAnchors()
869 treeNodeControl:SetAnchor(TOPLEFT, parentNode.childContainer, TOPLEFT, parentNode.childIndent, 0)
870 end
871
872 previousNode = treeNode
873 end
874
875 self:UpdateChildHeightsToRoot(parentNode)
876end
877
878--==================================================================================================--
879-- ZO_TreeNode will not let you insert a child into a specific position & ZO_TreeNode is local.
880-- So to keep nodes in order, we let the game add it to the end of the list, resort
881-- the node table, and then re-anchor the nodes in the table.
882--==================================================================================================--
883-- NEVER try to sort the condition nodes !!!
884-- They are ordered in a special way, for step/condition order & visibility
885--==================================================================================================--
886--**** Sorts by category type and THEN by name, so all items may not "appear" to show up in alphabetical order ****--
887--**** This was intentional ****--
888function QuestTracker:SortQuestNodes(sortByLevel)
889 local sortByLevel = sortByLevel or self.svCurrent.sortByLevel
890 local categoryTable = self.navigationTree.rootNode.children
891
892 for k,categoryNode in pairs(categoryTable) do
893 self:SortChildrenByType(categoryNode, SORT_TYPE_QUESTS)
894 end
895end
896
897function QuestTracker:SortChildrenByType(parentNode, sortType)
898 local siblingsTable = parentNode.children
899 if not siblingsTable then return end
900
901 if sortType == SORT_TYPE_QUESTS then
902 local sortByLevel = self.svCurrent.sortByLevel
903 local function SortQuestTableEntries(questTableEntry1, questTableEntry2)
904 local quest1NodeData = questTableEntry1.data
905 local quest2NodeData = questTableEntry2.data
906
907 if quest1NodeData.categoryType == quest2NodeData.categoryType then
908 if quest1NodeData.categoryName == quest2NodeData.categoryName then
909 if sortByLevel then
910 return quest1NodeData.level < quest2NodeData.level
911 end
912 return quest1NodeData.name < quest2NodeData.name
913 end
914 return quest1NodeData.categoryName < quest2NodeData.categoryName
915 end
916 return quest1NodeData.categoryType < quest2NodeData.categoryType
917 end
918
919 table.sort(siblingsTable, SortQuestTableEntries)
920
921 elseif sortType == SORT_TYPE_QUEST_CATEGORIES then
922 local function SortCategoryTableEntries(categoryTableEntry1, categoryTableEntry2)
923 local category1NodeData = categoryTableEntry1.data
924 local category2NodeData = categoryTableEntry2.data
925
926 if category1NodeData.type == category2NodeData.type then
927 return category1NodeData.name < category2NodeData.name
928 else
929 return category1NodeData.type < category2NodeData.type
930 end
931 end
932
933 table.sort(siblingsTable, SortCategoryTableEntries)
934 end
935 self:ReanchorChildren(parentNode)
936end
937
938--=============================================================--
939--==================== ADD NODE CODE ==========================--
940--=============================================================--
941function QuestTracker:AddCategoryNode(categoryData, parentNode)
942 local headerNode = self.navigationTree:AddNode("QuestTrackerCategoryNode", categoryData, parentNode, SOUNDS.QUEST_BLADE_SELECTED)
943
944 return headerNode
945end
946
947function QuestTracker:AddQuestEntryNode(questData, parentNode)
948 local questNode = self.navigationTree:AddNode("QuestTrackerQuestNode", questData, parentNode, SOUNDS.QUEST_SELECTED)
949 self.navigationTree.questIndexToTreeNode[questData.questIndex] = questNode
950
951 if QUESTTRACKER and QUESTTRACKER.svCurrent.autoOpenNodes then
952 questNode:SetOpenPercentage(1)
953 questNode.open = true
954 end
955
956 return questNode
957end
958
959function QuestTracker:AddQuestConditionNode(conditionData, parentNode)
960 local conditionNode = self.navigationTree:AddNode("QuestTrackerConditionNode", conditionData, parentNode, nil)
961
962 return conditionNode
963end
964
965
966--=============================================================--
967--================== UPDATE QUEST CODE ========================--
968--=============================================================--
969-- Used to update quest condition nodes...well actualy wipe them out & recreate them
970-- on quest advance or quest condition counter change. We wipe them out rather than update them because
971-- its much easier/faster than looping through each node to edit/add new conditions & looping through again
972-- to wipe out any old left over condition nodes that are no longer valid
973function QuestTracker:UpdateQuest(journalIndex)
974 local tree = self.navigationTree
975 local questNode = tree.questIndexToTreeNode[journalIndex]
976
977 -- If it doesn't exist....something is wrong somewhere else
978 assert(questNode, "UpdateQuest failed. Quest does not exist in the quest tree")
979
980 -- Not really the most efficient method here, but easy
981 local allQuests, allCategories, seenCategories = QUEST_JOURNAL_MANAGER:GetQuestListData()
982 local newQuestData
983
984 for k,questData in pairs(allQuests) do
985 if questData.questIndex == journalIndex then
986 newQuestData = questData
987 break
988 end
989 end
990 -- If newQuestData doesn't exist....something is wrong, the quest must have been removed somehow/somewhere
991 -- and it wasn't supposed to be or else an update event would not have fired, but don't do this:
992 -- if not newQuestData then return end....we want an error to let us know whats wrong
993 assert(newQuestData, "UpdateQuest failed. Quest does not exist in the QUEST_JOURNAL_MANAGER")
994
995 self:ReleaseAllQuestConditionNodes(questNode)
996
997 -- Add step & condition info to the newQuestData table
998 AddStepConditionInfo(newQuestData)
999
1000 questNode.data = newQuestData
1001
1002 -- Add all of the new condition nodes....NEVER sort the condition nodes !!!
1003 -- They are already ordered in a special way, for step/condition order & visibility
1004 local conditions = newQuestData.conditions
1005 for conditionKey, conditionData in ipairs(conditions) do
1006 local conditionNode = self:AddQuestConditionNode(conditionData, questNode)
1007 end
1008 self:UpdateChildHeightsToRoot(questNode)
1009end
1010
1011--=============================================================--
1012--=============== ADD/REMOVE CATEGORY CODE ====================--
1013--=============================================================--
1014-- When a quest is added, if the category does not already exist, used to add the new quest category
1015function QuestTracker:AddQuestCategory(categoryNodeData)
1016 local rootNode = self.navigationTree.rootNode
1017 local categoryNode = self:AddCategoryNode(categoryNodeData, rootNode)
1018
1019 self:SortChildrenByType(rootNode, SORT_TYPE_QUEST_CATEGORIES)
1020
1021 return categoryNode
1022end
1023
1024--==============================================================--
1025--============ REPOPULATE/ADDTABLE NODES CODE ============--
1026--==============================================================--
1027function QuestTracker:RepopulateQuestTree()
1028 -- these tables are ALREADY sorted, so use ipairs !
1029 local allQuests, allCategories, seenCategories = QUEST_JOURNAL_MANAGER:GetQuestListData()
1030 local quests = {}
1031
1032 -- Combine the quest/category data into one table
1033 for categoryKey, categoryData in ipairs(allCategories) do
1034 local categoryName = categoryData.name
1035
1036 quests[categoryKey] = {
1037 name = categoryName,
1038 type = categoryData.type,
1039 -- Note this quests table is ONLY valid here & in the below call to AddTableNodes, when repopulating the
1040 -- tree from scratch. When we add/remove/update nodes we do NOT update this quests table...theres no need to.
1041 -- This is only to reorganize the data returned by GetQuestListData to make the repopulation/AddTableNodes() easier.
1042 quests = {}
1043 }
1044 for questKey, questData in ipairs(allQuests) do
1045 if questData.categoryName == categoryName then
1046 AddStepConditionInfo(questData)
1047
1048 table.insert(quests[categoryKey].quests, questData)
1049 end
1050 end
1051 if self.svCurrent.sortByLevel then
1052 local function SortQuestsByLevel(questTableEntry1, questTableEntry2)
1053 return questTableEntry1.level < questTableEntry2.level
1054 end
1055 table.sort(quests[categoryKey].quests, SortQuestsByLevel)
1056 end
1057 end
1058
1059 self:AddTableNodes(quests, nil)
1060
1061 -- If there are quests when the table nodes are added it automatically calls
1062 -- the required functions to resize the window. If the quests table is empty, no quests
1063 -- no nodes are added so we must call the update ourselves.
1064 if next(quests) == nil then
1065 self:UpdateChildHeightsToRoot(self.navigationTree.rootNode)
1066 end
1067
1068 -- Must refresh selected quest, that way when quests are added or removed,
1069 -- we keep the correct quest selected because the QuestTrackerAssistStateChanged
1070 -- will have already fired and it wont get updated by that !
1071 self:RefreshSelectedQuest()
1072 -- AFTER that, update the tree exclusitivity. Must be after so a quest is selected to set the
1073 -- exclusive path if the tree is set as exclusive.
1074 self:UpdateTreeExclusitivity()
1075 self.navigationTree:RefreshVisible() -- Extra refresh to prevent text from being chopped off (workaround for a ZOS issue)
1076end
1077
1078function QuestTracker:AddTableNodes(allQuests, parentNode)
1079 local tree = self.navigationTree
1080 -- Clear the tree nodes & questIndexToTreeNode table
1081 tree:Reset()
1082 tree.questIndexToTreeNode = {}
1083
1084 -- They are sorted use ipairs !!
1085 for categoryKey, categoryData in ipairs(allQuests) do
1086 local categoryNode = self:AddCategoryNode(categoryData, parentNode)
1087 local quests = categoryData.quests
1088
1089 for questKey, questData in ipairs(quests) do
1090 local questNode = self:AddQuestEntryNode(questData, categoryNode)
1091 tree.questIndexToTreeNode[questData.questIndex] = questNode
1092
1093 local conditions = questData.conditions
1094 for conditionKey, conditionData in ipairs(conditions) do
1095 local conditionNode = self:AddQuestConditionNode(conditionData, questNode)
1096 end
1097 questData.conditions = nil -- Wipe this out so you don't accidently "think" you can use it later, we don't update this data
1098 end
1099 categoryData.quests = nil -- Wipe this out so you don't accidently "think" you can use it later, we don't update this data
1100 end
1101
1102 -- If the user has exclusitivity set to "All" so tree.exclusive == true this will cause problems if you do not
1103 -- specify which node to select...even though it really wont select the node because its not a leaf,
1104 -- it blocks the SelectAnything() func
1105 local selectedQuestIndex = QUEST_JOURNAL_MANAGER:GetFocusedQuestIndex()
1106 local selectedQuestNode = self.navigationTree.questIndexToTreeNode[selectedQuestIndex]
1107 tree:Commit(selectedQuestNode)
1108
1109 -- On category nodes, the number of quests is only set when the category node is created (or visible/control is refreshed)
1110 -- But children (quests) get added after that. So after were done adding all the quests, refresh the entire visible tree
1111 -- to update the number of quests for every category control
1112 tree:RefreshVisible()
1113end
1114
1115--===========================================================--
1116--============ BACKDROP SETTINGS MENU FUNCTIONS ============--
1117--===========================================================--
1118function QuestTracker:UpdateBackdropColor()
1119 local backdropControl = self.backdrop
1120 local bgColor = self.svCurrent.mainWindow.backdrop.backdropColor
1121 local dragBar = self.dragBar
1122 local r,g,b,alpha = unpack(bgColor)
1123
1124 backdropControl:SetCenterColor(r,g,b,alpha)
1125 backdropControl:SetEdgeColor(r,g,b,alpha)
1126 dragBar:SetAlpha(alpha)
1127end
1128function QuestTracker:UpdateDragBarColor()
1129 local bgColor = self.svCurrent.mainWindow.backdrop.dragBarColor
1130 local dragBar = self.dragBar
1131 local r,g,b,alpha = unpack(bgColor)
1132
1133 dragBar:SetCenterColor(r,g,b,alpha)
1134 --dragBar:SetEdgeColor(r,g,b,alpha)
1135end
1136
1137function QuestTracker:UpdateBackdrop(backdropName)
1138 local backdropControl = self.backdrop
1139 local dragBar = self.dragBar
1140 local mungeOverlay = backdropControl:GetNamedChild("MungeOverlay")
1141
1142 local svMainWindow = self.svCurrent.mainWindow
1143 local svMainWindowBackdrop = svMainWindow.backdrop
1144 local bgColor = svMainWindowBackdrop.backdropColor
1145 local backdropName = backdropName or svMainWindowBackdrop.backdropName
1146
1147 if svMainWindowBackdrop.hideMungeOverlay then
1148 mungeOverlay:SetHidden(true)
1149 else
1150 mungeOverlay:SetHidden(false)
1151 end
1152
1153 if backdropName == "None" then
1154 backdropControl:SetHidden(true)
1155 dragBar:SetHidden(true)
1156
1157 else
1158 if backdropName == "Fancy" then
1159 backdropControl:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds", 16, WRAP)
1160 backdropControl:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16, 0, 0)
1161 backdropControl:SetEdgeColor(1,1,1,1)
1162
1163 elseif backdropName == "Colored" then
1164 backdropControl:SetCenterTexture(nil, 16, WRAP)
1165 backdropControl:SetEdgeTexture(nil, 128, 16, 0, 0)
1166 local r,g,b,alpha = unpack(bgColor)
1167 backdropControl:SetCenterColor(r,g,b,alpha)
1168 backdropControl:SetEdgeColor(r,g,b,alpha)
1169 local dragBar = self.dragBar
1170 self:UpdateDragBarColor()
1171 dragBar:SetAlpha(alpha)
1172 end
1173 local shouldHide = svMainWindowBackdrop.backdropHideOnLock and svMainWindow.isItLocked
1174 backdropControl:SetHidden(shouldHide)
1175 dragBar:SetHidden(shouldHide)
1176 end
1177end
1178
1179--==========================================================--
1180--================== EXCLUSITIVITY CODE ==================--
1181--==========================================================--
1182function QuestTracker:OpenAllQuestNodes()
1183 local tree = self.navigationTree
1184 local selectedNode = tree.selectedNode
1185
1186 -- The game is still loading, the user has no quests...or else theres always something selected?
1187 if not selectedNode then return end
1188
1189 local categoryNodesTable = tree.rootNode.children
1190
1191 for k,categoryNode in pairs(categoryNodesTable) do
1192 local questNodeTable = categoryNode.children
1193
1194 for k,questNode in pairs(questNodeTable) do
1195 tree:SetNodeOpen(questNode, true, USER_REQUESTED_OPEN)
1196 end
1197 end
1198end
1199
1200function QuestTracker:OpenSelectedCategoryQuestNodes()
1201 local tree = self.navigationTree
1202 local selectedNode = tree.selectedNode
1203
1204 -- The game is still loading, the user has no quests...or else theres always something selected?
1205 if not selectedNode then return end
1206
1207 local selectedCategoryNode = selectedNode.parentNode
1208 local questNodeTable = selectedCategoryNode.children
1209
1210 for k,questNode in pairs(questNodeTable) do
1211 tree:SetNodeOpen(questNode, true, USER_REQUESTED_OPEN)
1212 end
1213end
1214
1215function QuestTracker:CloseAllQuestNodes()
1216 local tree = self.navigationTree
1217 local selectedNode = tree.selectedNode
1218
1219 -- The game is still loading, the user has no quests...or else theres always something selected?
1220 if not selectedNode then return end
1221
1222 local categoryNodesTable = tree.rootNode.children
1223
1224 for k,categoryNode in pairs(categoryNodesTable) do
1225 local questNodeTable = categoryNode.children
1226
1227 for k,questNode in pairs(questNodeTable) do
1228 if questNode.open and not self:AreTreeNodesEqual(questNode, selectedNode) then
1229 tree:SetNodeOpen(questNode, false, USER_REQUESTED_OPEN)
1230 end
1231 end
1232 end
1233end
1234
1235function QuestTracker:CloseAllCategoryNodes()
1236 local tree = self.navigationTree
1237 local selectedNode = tree.selectedNode
1238
1239 -- The game is still loading, the user has no quests...or else theres always something selected?
1240 if not selectedNode then return end
1241
1242 local categoryNodeTable = tree.rootNode.children
1243 local selectedCategoryNode = selectedNode.parentNode
1244
1245 for k,categoryNode in pairs(categoryNodeTable) do
1246 if categoryNode.open and not self:AreTreeNodesEqual(categoryNode, selectedCategoryNode) then
1247 tree:SetNodeOpen(categoryNode, false, USER_REQUESTED_OPEN)
1248 end
1249 end
1250end
1251
1252function QuestTracker:OpenAllCategoryNodes()
1253 local tree = self.navigationTree
1254 local selectedNode = tree.selectedNode
1255
1256 -- The game is still loading, the user has no quests...or else theres always something selected?
1257 if not selectedNode then return end
1258
1259 local categoryNodeTable = tree.rootNode.children
1260 local selectedCategoryNode = selectedNode.parentNode
1261
1262 for k,categoryNode in pairs(categoryNodeTable) do
1263 if categoryNode.closed and not self:AreTreeNodesEqual(categoryNode, selectedCategoryNode) then
1264 tree:SetNodeOpen(categoryNode, true, USER_REQUESTED_OPEN)
1265 end
1266 end
1267end
1268
1269--[[ Note we do not always need to "set" the saved vars for changing node exclusitivity, this is why it is split into
1270 two functions For example, on load, we only need to update the newly created trees setting, so we pass in nil. But in
1271 the settings menu we call SetTreeExclusitivity, which saves the new sv value & calls this function to update the tree
1272 setting. In that route, since we already have the nodeExclusitivity table theres no reason to look it up again here, thus the parameter.
1273--]]
1274function QuestTracker:UpdateTreeExclusitivity(exclusitivityTable)
1275 local tree = self.navigationTree
1276 local isTreeExclusive = tree.exclusive
1277 local newExclusitivityTable = exclusitivityTable or self.svCurrent.nodeExclusitivity
1278 local shouldTreeBeExclusive = newExclusitivityTable.isTreeExclusive
1279
1280 -- If the tree is already exclusive, other nodes are already closed, so we don't need to worry about
1281 -- closing categories or quest nodes, just set the new exclusitivity (if needed)
1282 if isTreeExclusive then
1283 if not shouldTreeBeExclusive then
1284 tree:SetExclusive(false)
1285 end
1286
1287 else
1288 -- Tree is not currently exclusive. If it should be, set it exclusive & close all nodes
1289 if shouldTreeBeExclusive then
1290 local curSelectedNode = tree.selectedNode
1291
1292 tree:SetExclusive(true)
1293
1294 if curSelectedNode then
1295 -- exclusivePath has not been set yet, when SetExclusive is false it does not set the path
1296 -- so call OpenNode (even though it may already be open) to force it to set the path
1297 -- and run exclusivitity close function after we set exclusive to true
1298 tree:SetNodeOpen(curSelectedNode, true, USER_REQUESTED_OPEN)
1299 end
1300
1301 else
1302 -- Tree is not exclusive & should not be, dont change exclusitivity, but since tree is not exclusive
1303 -- category/quest nodes may be open that are not supposed to be. Check & update their exclusitivity.
1304 if newExclusitivityTable.categoryNodes then
1305 self:CloseAllCategoryNodes()
1306 end
1307 if newExclusitivityTable.questNodes then
1308 self:CloseAllQuestNodes()
1309 end
1310 end
1311 end
1312end
1313
1314-- Update saved vars with new exclusitivity info
1315function QuestTracker:SetTreeExclusitivity(exclusiveName)
1316 local exclusitivity = {
1317 ["None"] = {
1318 currentSetting = "None",
1319 allNodes = false,
1320 categoryNodes = false,
1321 questNodes = false,
1322 isTreeExclusive = false,
1323 },
1324 ["All"] = {
1325 currentSetting = "All",
1326 allNodes = true,
1327 categoryNodes = false,
1328 questNodes = false,
1329 isTreeExclusive = true,
1330 },
1331 ["Categories Only"] = {
1332 currentSetting = "Categories Only",
1333 allNodes = false,
1334 categoryNodes = true,
1335 questNodes = false,
1336 isTreeExclusive = false,
1337 },
1338 ["Quests Only"] = {
1339 currentSetting = "Quests Only",
1340 allNodes = false,
1341 categoryNodes = false,
1342 questNodes = true,
1343 isTreeExclusive = false,
1344 },
1345 }
1346 local tree = self.navigationTree
1347 local newExclusitivity = exclusitivity[exclusiveName]
1348 self.svCurrent.nodeExclusitivity = newExclusitivity
1349
1350 self:UpdateTreeExclusitivity(newExclusitivity)
1351
1352 -- Make sure it scrolls back into view, just incase
1353 self:RefreshSelectedQuest()
1354end
1355
1356--=========================================================--
1357--=========================================================--
1358--====================== TREE CODE ======================--
1359--=========================================================--
1360--=========================================================--
1361-- I would strongly suggest you don't mess with any of this InitializeTree code.
1362-- The games tree class does not do everything I needed it to do. Like selecting nodes that have children.
1363-- So I changed some stuff & manually called/did whatever I needed instead of using the ZO_Tree functions.
1364-- There are several tree functions that you can NOT use. Some just wont work & some will mess things up.
1365function QuestTracker:InitializeTree()
1366 local navigationTree = self.navigationTree
1367
1368 local openTexture = "EsoUI/Art/Buttons/tree_open_up.dds"
1369 local closedTexture = "EsoUI/Art/Buttons/tree_closed_up.dds"
1370 local overOpenTexture = "EsoUI/Art/Buttons/tree_open_over.dds"
1371 local overClosedTexture = "EsoUI/Art/Buttons/tree_closed_over.dds"
1372
1373 --============ Category Node Code ============================================--
1374 local function CategoryNodeSetup(node, control, data, open, userRequested)
1375 local fontString = self:GetCategoryFontString()
1376 local textControl = control.text
1377 local icon = control.icon
1378 local categoryName = data.name
1379 local numQuests = node.children and #node.children
1380
1381
1382 if numQuests and self.svCurrent.showNumCategoryQuests then
1383 categoryName = zo_strformat("[<<1>>] <<2>>", numQuests, categoryName)
1384 end
1385
1386 node.label = textControl
1387 node.icon = icon
1388
1389 textControl:SetFont(fontString)
1390 textControl:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE)
1391 textControl:SetText(categoryName)
1392
1393 local textWidth = textControl:GetTextWidth()
1394 local iconWidth = icon:GetWidth()
1395 node.textWidth = textWidth
1396 node.iconWidth = iconWidth
1397
1398 -- if theres a problem with this, check the global UI scale
1399 node.totalControlWidth = textWidth + iconWidth + TEXT_LABEL_PADDING
1400
1401 -- if theres a problem with this, check the global UI scale
1402 local textHeight = textControl:GetTextHeight()
1403 local currentHeight = control:GetHeight()
1404
1405 if currentHeight ~= textheight then
1406 textControl:SetHeight(textHeight)
1407 control:SetHeight(textHeight)
1408 control.icon:SetDimensions(textHeight, textHeight)
1409 self:UpdateChildHeightsToRoot(node)
1410 end
1411
1412 local categoryColor = ZO_ColorDef:New(unpack(self.svCurrent.fontSettings.categories.color))
1413 ZO_SelectableLabel_SetNormalColor(textControl, categoryColor)
1414
1415 control.icon:SetTexture(open and openTexture or closedTexture)
1416 control.iconHighlight:SetTexture(open and overOpenTexture or overClosedTexture)
1417
1418 textControl:SetSelected(open)
1419 end
1420
1421 local function CategoryNodeEquality(left, right)
1422 return left.name == right.name
1423 end
1424 navigationTree:AddTemplate("QuestTrackerCategoryNode", CategoryNodeSetup, nil, CategoryNodeEquality, 40, 0)
1425 --============ End Category Node Code ========================================--
1426
1427 --============ Quest Node Code ================================================--
1428 -- Shared code function for quest node setup & select
1429 -- Handles showing/hiding the quest selected or instance icon
1430 local function SetupQuestIcon(questNodeControl, nodeData, selected)
1431 local questNode = questNodeControl.node
1432 local tree = questNode.tree
1433 local curQuestNode = tree.selectedNode
1434 local icon = GetControl(questNodeControl, "Icon")
1435
1436 icon.selected = selected
1437
1438 if selected then
1439 icon:SetTexture("EsoUI/Art/Journal/journal_Quest_Selected.dds")
1440 icon:SetAlpha(1.00)
1441 icon:SetHidden(false)
1442
1443 else
1444 icon:SetTexture(QUEST_JOURNAL_KEYBOARD:GetIconTexture(nodeData.displayType))
1445 icon.tooltipText = QUEST_JOURNAL_KEYBOARD:GetTooltipText(nodeData.displayType)
1446
1447 if nodeData.displayType == INSTANCE_DISPLAY_TYPE_NONE then
1448 icon:SetHidden(true)
1449 else
1450 icon:SetAlpha(0.50)
1451 icon:SetHidden(true) -- should be false ... need to find changes in ESO source since DB DLC patch. <------------------------------------------------------
1452 end
1453 end
1454 end
1455
1456 local function QuestNodeSetup(questNode, questNodeControl, nodeData, open, userRequested)
1457 local questName = nodeData.name
1458 local fontString = self:GetQuestFontString()
1459 local textHeight = questNodeControl:GetTextHeight()
1460 local currentHeight = questNodeControl:GetHeight()
1461 local tree = self.navigationTree
1462 local selectedNode = tree.selectedNode
1463 local selected = false
1464
1465 if self.svCurrent.showQuestLevel then
1466 questName = zo_strformat("[<<1>>] <<2>>", nodeData.level, questName)
1467 end
1468
1469 --xxxxxx
1470 questNodeControl.con = GetCon(nodeData.level)
1471 questNodeControl.questIndex = nodeData.questIndex
1472 questNodeControl:SetFont(fontString)
1473 questNodeControl:SetText(questName)
1474
1475
1476 questNode.label = questNodeControl
1477
1478 -- if theres a problem with this, check the global UI scale
1479 local textWidth = questNodeControl:GetTextWidth() + TEXT_LABEL_PADDING
1480 questNode.textWidth = textWidth
1481 questNode.totalControlWidth = textWidth
1482
1483 -- if theres a problem with this, check the global UI scale
1484 if currentHeight ~= textheight then
1485 questNodeControl:SetHeight(textHeight)
1486 self:UpdateChildHeightsToRoot(questNode)
1487 questNodeControl.icon:SetDimensions(textHeight, textHeight)
1488 end
1489
1490 if selectedNode and questNode == selectedNode then
1491 selected = true
1492 end
1493
1494 questNodeControl:SetSelected(selected)
1495 SetupQuestIcon(questNodeControl, nodeData, selected)
1496
1497 -- Used so we don't need to know if the control is selected or not, it
1498 -- will refresh the correct color or set the default color, must be done after GetCon(...)
1499 questNodeControl:RefreshTextColor()
1500 end
1501
1502 -- Handles closing nodes for node exclusitivity when a node is deselected, only called from
1503 -- QuestNodeOnSelected. Made a seperate function for simplicity only.
1504 local function DeselectQuestNode(questNode)
1505 local tree = questNode.tree
1506
1507 -- If tree is exclusive it will handle closing nodes on its own
1508 if not tree.exclusive then
1509 local nodeExclusitivity = self.svCurrent.nodeExclusitivity
1510
1511 -- If exclusive quest nodes, close the curQuestNode
1512 if nodeExclusitivity.questNodes then
1513 tree:SetNodeOpen(questNode, false, USER_REQUESTED_OPEN)
1514 end
1515
1516 -- If exclusive category nodes & new quest is in a different category, close the current category node
1517 if nodeExclusitivity.categoryNodes then
1518 local questNodeParentNode = questNode.parentNode
1519 tree:SetNodeOpen(questNodeParentNode, false, USER_REQUESTED_OPEN)
1520 end
1521 end
1522 end
1523
1524 -- The tree doesn't actually fire this because it has children...the game does not allow selecting nodes unless
1525 -- they are leafs. I'm just defining it here with the others, and I will fire it manually myself through the node:OnSelected()
1526 --QUEST_JOURNAL_KEYBOARD:FireCallbacks("QuestSelected", data.questIndex) -- This is nothing, just a reminder about something
1527 local function QuestNodeOnSelected(questNodeControl, nodeData, selected, reselectingDuringRebuild)
1528 local questNode = questNodeControl.node
1529 local tree = questNode.tree
1530 local curQuestNode = tree.selectedNode
1531 local icon = GetControl(questNodeControl, "Icon")
1532
1533 if selected then
1534 if curQuestNode and questNode ~= curQuestNode then
1535 tree:ClearSelectedNode() -- calls :OnUnselected()
1536 end
1537
1538 -- SetNodeOpen forces a call to questNode setup which deselects the node & hides the icon
1539 -- so we must do this before setting the icon, icon.selected, or control:SetSelected
1540 tree.selectedNode = questNode
1541 tree:SetNodeOpen(questNode, true, USER_REQUESTED_OPEN)
1542
1543 else
1544 DeselectQuestNode(questNode)
1545 end
1546
1547 -- must be done last, see comment above SetNodeOpen
1548 questNodeControl:SetSelected(selected)
1549 SetupQuestIcon(questNodeControl, nodeData, selected)
1550 end
1551
1552 local function QuestNodeEquality(left, right)
1553 return left.name == right.name
1554 end
1555 -- navigationTree:AddTemplate("QuestTrackerQuestNode", QuestNodeSetup, QuestNodeOnSelected, QuestNodeEquality)
1556 -- ChildIndent & ChildSpacing are for the children "of this node" not for when this node is a child !
1557 navigationTree:AddTemplate("QuestTrackerQuestNode", QuestNodeSetup, QuestNodeOnSelected, QuestNodeEquality, 15, 0)
1558 --============ End Quest Node Code ============================================--
1559
1560 --============ Condition Node Code ============================================--
1561 local function TreeConditionSetup(conditionNode, conditionNodeControl, data, open)
1562 local fontString = self:GetConditionFontString()
1563
1564 conditionNode.label = conditionNodeControl
1565
1566 conditionNodeControl:SetFont(fontString)
1567 conditionNodeControl:SetColor(unpack(self.svCurrent.fontSettings.conditions.color))
1568 conditionNodeControl:SetText(data.conditionText)
1569
1570 -- if theres a problem with this, check the global UI scale
1571 local textWidth = conditionNodeControl:GetTextWidth() + TEXT_LABEL_PADDING
1572 conditionNode.textWidth = textWidth
1573 conditionNode.totalControlWidth = textWidth
1574
1575 -- if theres a problem with this, check the global UI scale
1576 local textHeight = conditionNodeControl:GetTextHeight()
1577 local currentHeight = conditionNodeControl:GetHeight()
1578
1579 if currentHeight ~= textheight then
1580 conditionNodeControl:SetHeight(textHeight)
1581 self:UpdateChildHeightsToRoot(conditionNode)
1582 end
1583 end
1584 navigationTree:AddTemplate("QuestTrackerConditionNode", TreeConditionSetup)
1585 --============ End Condition Node Code ========================================--
1586
1587 -- true means only one can be open at a time AND you can't click to close it. You have to open another to get it to close. Just left as a reminder: navigationTree:SetExclusive(true/false)...but don't do (below) here. Or a node wont be selected yet & the exclusive path wont get set correctly.
1588 --self:UpdateTreeExclusitivity()
1589
1590 navigationTree:SetOpenAnimation("ZO_TreeOpenAnimation")
1591
1592 return navigationTree
1593end
1594
1595--================================================================--
1596--================================================================--
1597--============ TREE RELEASE NODE CODE ============================--
1598--================================================================--
1599--================================================================--
1600function QuestTracker:ReleaseConditionNode(conditionNode)
1601 -- hide its highlight if it has it
1602 self:HideNodeSelectionHighlight(conditionNode)
1603
1604 -- Release any animations it has
1605 self:ReleaseOpenAnimation(conditionNode)
1606
1607 -- Get the objectPool for conditions & release the condition Node
1608 local conditionObjectPool = self.navigationTree.templateInfo["QuestTrackerConditionNode"].objectPool
1609 self:ReleaseNodeFromPool(conditionNode, conditionObjectPool)
1610end
1611
1612function QuestTracker:ReleaseQuestNode(questNode)
1613 local tree = self.navigationTree
1614 local selectedNode = tree.selectedNode
1615 local siblingsTable = questNode.parentNode.children
1616 local questIndex = questNode.data.questIndex
1617 local categoryNode = questNode.parentNode
1618 local next = next
1619
1620 -- Remove the quest node reference from the questIndexToTreeNode table
1621 tree.questIndexToTreeNode[questIndex] = nil
1622
1623 if self:AreTreeNodesEqual(questNode, selectedNode) then
1624 tree.selectedNode = nil
1625 end
1626
1627 -- Reanchor around the node to be removed
1628 self:AnchorPreviousNodeToNextNode(questNode)
1629
1630 -- release all of the condition nodes
1631 self:ReleaseAllQuestConditionNodes(questNode)
1632
1633 -- release all node objects including the node control, animations, child container, exc...
1634 local questObjectPool = tree.templateInfo["QuestTrackerQuestNode"].objectPool
1635 self:ReleaseNodeObjects(questNode, questObjectPool)
1636
1637 -- If the siblingsTable is empty, there are no more quests under this category
1638 -- then, release the category node.
1639 if next(siblingsTable) == nil then
1640 self:ReleaseCategoryNode(categoryNode)
1641 end
1642end
1643
1644function QuestTracker:ReleaseChildContainer(treeNode)
1645 local containerControlName = treeNode.childContainer:GetName()
1646 local containerObjectPool = self.navigationTree.childContainerPool
1647 local activeContainerObjects = containerObjectPool.m_Active
1648
1649 for objKey,obj in pairs(activeContainerObjects) do
1650 if containerControlName == obj:GetName() then
1651 containerObjectPool:ReleaseObject(objKey)
1652 end
1653 end
1654
1655 self:UpdateChildHeightsToRoot(treeNode)
1656end
1657
1658function QuestTracker:ReleaseNodeFromPool(treeNode, objectPool)
1659 local activeCategoryObjects = objectPool.m_Active
1660 local CategoryNodeControlName = treeNode.control:GetName()
1661 local parentNode = treeNode.parentNode
1662
1663 for objKey,obj in pairs(activeCategoryObjects) do
1664 if CategoryNodeControlName == obj:GetName() then
1665 objectPool:ReleaseObject(objKey)
1666 end
1667 end
1668
1669 self:UpdateChildHeightsToRoot(parentNode)
1670end
1671
1672function QuestTracker:HideNodeSelectionHighlight(treeNode)
1673 if(treeNode.selectionHighlight) then
1674 treeNode.selectionHighlight:SetHidden(true)
1675 end
1676end
1677
1678function QuestTracker:ReleaseOpenAnimation(treeNode)
1679 self.navigationTree.openAnimationPool:ReleaseObject(treeNode)
1680end
1681
1682function QuestTracker:ReleaseNodeObjects(treeNode, nodeObjectPool)
1683 -- Get the parentNode.children table index for the node to be removed
1684 local treeNodeTableIndex = self:GetNodeTableIndex(treeNode)
1685 local siblingTable = treeNode.parentNode.children
1686
1687 -- release the nodes child container
1688 self:ReleaseChildContainer(treeNode)
1689
1690 self:HideNodeSelectionHighlight(treeNode)
1691 self:ReleaseOpenAnimation(treeNode)
1692
1693 -- Release the category node itself
1694 self:ReleaseNodeFromPool(treeNode, nodeObjectPool)
1695
1696 -- This is done here because the node referenced in this table, at this index,
1697 -- is no longer a valid node, we just released all of its objects
1698 -- Remove the node from the treeNode.parentNode.children table
1699 table.remove(siblingTable, treeNodeTableIndex)
1700
1701 self:UpdateChildHeightsToRoot(treeNode)
1702end
1703
1704function QuestTracker:ReleaseCategoryNode(categoryNode)
1705 local tree = self.navigationTree
1706 local rootNode = tree.rootNode
1707 local rootChildren = rootNode.children
1708
1709 -- Reanchor around the node to be removed
1710 self:AnchorPreviousNodeToNextNode(categoryNode)
1711
1712 -- release all of the quest nodes
1713 self:ReleaseAllCategoryQuestNodes(categoryNode)
1714
1715 -- Release all node objects, for the category node
1716 local categorytObjectPool = tree.templateInfo["QuestTrackerCategoryNode"].objectPool
1717 self:ReleaseNodeObjects(categoryNode, categorytObjectPool)
1718
1719 self:UpdateChildHeightsToRoot(rootNode)
1720end
1721
1722-- release all of the quest nodes,
1723function QuestTracker:ReleaseAllCategoryQuestNodes(categoryNode)
1724 local categoryChildren = categoryNode.children
1725
1726 -- children can be nil if no quests, so check it first
1727 if type(categoryChildren) == "table" then
1728 for k,questNode in pairs(categoryChildren) do
1729 self:ReleaseQuestNode(questNode)
1730 end
1731 end
1732 -- nil the child table & update heights to root
1733 categoryNode.children = nil
1734 self:UpdateChildHeightsToRoot(categoryNode)
1735end
1736
1737-- release all of the condition nodes, can be nil if no conditions
1738function QuestTracker:ReleaseAllQuestConditionNodes(questNode)
1739 local questConditions = questNode.children
1740
1741 -- children can be nil if no quests, so check it first
1742 if type(questConditions) == "table" then
1743 for k,conditionNode in pairs(questConditions) do
1744 self:ReleaseConditionNode(conditionNode)
1745 end
1746 end
1747 -- nil the child table & update heights to root
1748 questNode.children = nil
1749 self:UpdateChildHeightsToRoot(questNode)
1750end
1751--============ END TREE RELEASE NODE CODE ============================--
1752
1753
1754--========================================================--
1755--================= XML CODE/Functions =================--
1756--========================================================--
1757
1758--================================================================--
1759--==================== XML: Main Window Code ====================--
1760--================================================================--
1761local function ResetAnchorPosition(self)
1762 local left = self:GetLeft()
1763 local top = self:GetTop()
1764 self:ClearAnchors()
1765 self:SetAnchor(TOPLEFT, nil, TOPLEFT, left, top)
1766end
1767
1768local function QuestTracker_On_ResizeStop(self)
1769 QUESTTRACKER.svCurrent.mainWindow.width = self:GetWidth()
1770 QUESTTRACKER.svCurrent.mainWindow.height = self:GetHeight()
1771
1772 QUESTTRACKER.questTreeWin:SetDimensionConstraints(CONSTRAINT_WIDTH, CONSTRAINT_HEIGHT, 0, 0)
1773end
1774
1775local function QuestTracker_On_ResizeStart(self)
1776 local currentWidth = self:GetWidth()
1777 local currentHeight = self:GetHeight()
1778
1779 local autoSizeHeight = QUESTTRACKER.svCurrent.mainWindow.autoWindowSizeHeight
1780 local autoSizeWidth = QUESTTRACKER.svCurrent.mainWindow.autoWindowSizeWidth
1781
1782 local minWidth = autoSizeWidth and currentWidth or CONSTRAINT_WIDTH
1783 local maxWidth = autoSizeWidth and currentWidth or 0
1784 local minHeight = autoSizeHeight and currentHeight or CONSTRAINT_HEIGHT
1785 local maxHeight = autoSizeHeight and currentHeight or 0
1786
1787 QUESTTRACKER.questTreeWin:SetDimensionConstraints(minWidth, minHeight, maxWidth, maxHeight)
1788end
1789
1790local function QuestTracker_On_MoveStop(self)
1791 QUESTTRACKER.svCurrent.mainWindow.offsetX = self:GetLeft()
1792 QUESTTRACKER.svCurrent.mainWindow.offsetY = self:GetTop()
1793 ResetAnchorPosition(self)
1794end
1795
1796function QuestTracker_QuestTree_OnInitialized(self)
1797 self:SetHandler("OnResizeStart", QuestTracker_On_ResizeStart)
1798 self:SetHandler("OnResizeStop", QuestTracker_On_ResizeStop)
1799 self:SetHandler("OnMoveStop", QuestTracker_On_MoveStop)
1800end
1801
1802function QuestTracker:SetResizeHandleSize(autoResize)
1803 if autoResize then
1804 self.questTreeWin:SetResizeHandleSize(0)
1805 return
1806 end
1807 self.questTreeWin:SetResizeHandleSize(6)
1808end
1809
1810--================================================================--
1811--=================== XML: Category Node Code ===================--
1812--================================================================--
1813local function CategoryNode_OnMouseUp(self, button, upInside)
1814 if not upInside then return end
1815 ZO_TreeHeader_OnMouseUp(self, upInside)
1816
1817 -- we only have to worry about closing category nodes when "Categories Only" exclusitivity is turned on.
1818 -- other code handles closing them when exclusive is set to "All"
1819 -- When a quest is selected by forceAssist, the questNode
1820 -- :OnSelected() [QuestNodeOnSelected() -> DeselectQuestNode()]
1821 -- handles closing category nodes for "Categories Only" exclusitivity
1822 if not QUESTTRACKER.svCurrent.nodeExclusitivity.categoryNodes then return end
1823
1824 local tree = QUESTTRACKER.navigationTree
1825 local rootChildren = tree.rootNode.children
1826 local clickedNode = self.node
1827
1828 for _, categoryNode in pairs(rootChildren) do
1829 if categoryNode.open and not QUESTTRACKER:AreTreeNodesEqual(clickedNode, categoryNode) then
1830 tree:SetNodeOpen(categoryNode, false, USER_REQUESTED_OPEN)
1831 end
1832 end
1833end
1834
1835function QuestTracker_CategoryNode_OnInitialized(self)
1836 self.icon = self:GetNamedChild("Icon")
1837 self.iconHighlight = self.icon:GetNamedChild("Highlight")
1838 self.text = self:GetNamedChild("Text")
1839
1840 -- do not try to change this & use SetHandler !!
1841 self.OnMouseUp = CategoryNode_OnMouseUp
1842end
1843
1844--=================================================================--
1845--===================== XML: Quest Node Code =====================--
1846--=================================================================--
1847-- Used for special override of con color in quest nodes
1848-- ZO_SelectableLabel_OnInitialized(self, QuestTracker_QuestNode_GetTextColor), instead of:
1849-- ZO_SelectableLabel_OnInitialized(self, ZO_QuestJournalNavigationEntry_GetTextColor)
1850function QuestTracker_QuestNode_GetTextColor(self)
1851 if self.selected then
1852 return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED)
1853 elseif self.mouseover then
1854 return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_HIGHLIGHT)
1855 elseif QUESTTRACKER and QUESTTRACKER.svCurrent.overrideConColors then
1856 return unpack(QUESTTRACKER.svCurrent.fontSettings.quests.color)
1857 else
1858 return GetColorForCon(self.con)
1859 end
1860end
1861
1862local function QuestNode_OnMouseUp(self, button, upInside)
1863 if not upInside then return end
1864
1865 if button == MOUSE_BUTTON_INDEX_LEFT then
1866 local questIndex = self.node.data.questIndex
1867
1868 ZO_TreeHeader_OnMouseUp(self, upInside)
1869
1870 -- We don't need to fire self.node:OnSelected() it will cause a double call to OnSelected()
1871 -- Update the journal panel & force assist (which will fire the assist callback & call node:OnSelected())
1872 QUEST_JOURNAL_KEYBOARD:FocusQuestWithIndex(questIndex)
1873 FOCUSED_QUEST_TRACKER:ForceAssist(questIndex)
1874
1875 elseif button == MOUSE_BUTTON_INDEX_RIGHT then
1876 ClearMenu()
1877 AddCustomMenuItem("Share Quest", function()
1878 local questIndex = self.node.data.questIndex
1879 ShareQuest(questIndex)
1880 end)
1881 AddCustomMenuItem("Show On Map", function()
1882 local questIndex = self.node.data.questIndex
1883 ZO_WorldMap_ShowQuestOnMap(questIndex)
1884 end)
1885 AddCustomMenuItem("Abandon Quest", function()
1886 local questIndex = self.node.data.questIndex
1887 AbandonQuest(questIndex)
1888 end)
1889 ShowMenu()
1890 end
1891end
1892
1893local function QuestNode_OnMouseEnter(self)
1894 if not QUESTTRACKER.svCurrent.tooltips.show then return end
1895 if QUESTTRACKER.WINDOW_FRAGMENT:IsHidden() then return end
1896
1897 local questIndex = self.node.data.questIndex
1898 QUESTTRACKER:ShowQuestTooltip(questIndex)
1899end
1900
1901local function QuestNode_OnMouseExit(self)
1902 -- This is just to let you know, don't do this. Its not necessary.
1903 -- OnMouseEnter calls ShowQuestTooltip, which unregisters there, so by the time OnMouseExit gets called
1904 -- this update has already been unregistered.
1905 --EVENT_MANAGER:UnregisterForUpdate("QuestTrackerClearAutoTooltip")
1906 ClearTooltip(InformationTooltip)
1907end
1908
1909function QuestTracker_QuestNode_OnInitialized(self)
1910 self.icon = self:GetNamedChild("Icon")
1911 self.iconHighlight = self.icon:GetNamedChild("Highlight")
1912 self.text = self:GetNamedChild("Text")
1913
1914 -- do not try to change this & use SetHandler !!
1915 self.OnMouseUp = QuestNode_OnMouseUp
1916 self.OnMouseEnter = QuestNode_OnMouseEnter
1917 self.OnMouseExit = QuestNode_OnMouseExit
1918end
1919
1920--================================================================--
1921--=================== XML: Lock/Unlock Buttons ===================--
1922--================================================================--
1923function QuestTracker_LockButton_OnMouseUp(self, button, upInside)
1924 if not upInside then return end
1925
1926 QUESTTRACKER:SetLockState(false)
1927end
1928
1929function QuestTracker_UnlockButton_OnMouseUp(self, button, upInside)
1930 if not upInside then return end
1931
1932 QUESTTRACKER:SetLockState(true)
1933end
1934
1935-------------------------------------------------------------------
1936-- OnAddOnLoaded --
1937-------------------------------------------------------------------
1938local function OnAddOnLoaded(event, addonName)
1939 if addonName == ADDON_NAME then
1940 QUESTTRACKER = QuestTracker:New()
1941 -- Since QuestTracker_QuestNode_GetTextColor(...) is called from xml on initialization
1942 -- We must refresh the tree in case they have overridden the quest con colors
1943 -- to get it to update the quest con colors
1944 QUESTTRACKER.navigationTree:RefreshVisible()
1945 end
1946end
1947
1948---------------------------------------------------------------------
1949-- Register Events --
1950---------------------------------------------------------------------
1951EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED, OnAddOnLoaded)
1952
1953---------------------------------------------------------------------
1954-- Slash Commands --
1955---------------------------------------------------------------------
1956--SLASH_COMMANDS["/QuestTracker"] = QuestTracker_ToggleMainWindow
1957
1958--[[
1959SLASH_COMMANDS["/qto"] = function()
1960 if QUESTTRACKER.svCurrent.nodeExclusitivity.currentSetting ~= "None" then
1961 local darkOrange = "FFA500"
1962 local msg = zo_strformat("|c<<1>><<2>>:|r <<3>>", darkOrange, "QUESTTRACKER", "AutoClose must be turned OFF for open nodes to work")
1963 d(msg)
1964 return
1965 end
1966 QUESTTRACKER:OpenAllQuestNodes()
1967end
1968--]]
1969
1970-- Toggle window visible
1971SLASH_COMMANDS["/qth"] = QuestTracker_ToggleWindow
1972
1973-- Toggle Quests open/close
1974SLASH_COMMANDS["/qta"] = function()
1975--
1976 if QUESTTRACKER.svCurrent.nodeExclusitivity.currentSetting ~= "None" then
1977 local darkOrange = "FFA500"
1978 local msg = zo_strformat("|c<<1>><<2>>:|r <<3>>", darkOrange, "QUESTTRACKER", "AutoClose must be turned OFF for open nodes to work")
1979 d(msg)
1980 return
1981 else
1982--]]
1983 if QUESTTRACKER.svCurrent.autoOpenNodes then
1984 QUESTTRACKER.svCurrent.autoOpenNodes = false
1985 QUESTTRACKER:CloseAllQuestNodes()
1986 else
1987 QUESTTRACKER.svCurrent.autoOpenNodes = true
1988 QUESTTRACKER:OpenAllQuestNodes()
1989 end
1990 end
1991end
1992
1993-- Toggle lock/unlock window
1994SLASH_COMMANDS["/qtl"] = function()
1995 local lock = false
1996 if QUESTTRACKER.svCurrent.mainWindow.locked then
1997 QUESTTRACKER.svCurrent.mainWindow.locked = false
1998 lock = false
1999 else QUESTTRACKER.svCurrent.mainWindow.locked = true
2000 lock = true
2001 end
2002 QuestTracker:SetLockState(lock)
2003end
2004
2005-- Open all Quests in selected category and collapse all others.
2006SLASH_COMMANDS["/qts"] = function()
2007 QuestTracker:CloseAllCategoryNodes()
2008 QUESTTRACKER:OpenSelectedCategoryQuestNodes()
2009 QUESTTRACKER.navigationTree:RefreshVisible()
2010end
2011
2012-- Help Menu
2013SLASH_COMMANDS["/qt"] = function(text)
2014 if not text or text == "" or text == "help" or text == "?" then
2015 d(colorRavalox.."[QuestTracker]"..colorYellow.." Accepted Commands:")
2016 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt"..colorSoftYellow.." << shows this help")
2017 --d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt list"..colorSoftYellow.." << lists all tracked quests")
2018 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt help"..colorSoftYellow.." << shows help")
2019 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt settings"..colorSoftYellow.." << shows QuestTracker settings menu")
2020 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/questtracker"..colorSoftYellow.." << shows QuestTracker settings menu")
2021 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qth"..colorSoftYellow.." << hide QuestTracker UI toggle")
2022 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qta"..colorSoftYellow.." << Toggle open/close all quest nodes")
2023 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt1"..colorSoftYellow.." << Toggle lock/unlock QuestTracker window")
2024 d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qts"..colorSoftYellow.." << opens all quests in current category")
2025 --d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt help abandon"..colorSoftYellow.." << shows abandon quest help")
2026 --d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt help share"..colorSoftYellow.." << shows share quest help")
2027 --d(colorRavalox.."[QuestTracker]"..colorCMDBlue.."/qt help track"..colorSoftYellow.." << shows track quest help")
2028 --d(colorRavalox.."[QuestTracker]"..colorSoftYellow.." To EDIT White and Black lists, please edit your /SavedVariables/MQTuestTools.lua file.")
2029 return
2030 end
2031
2032 if text == "settings" then
2033 local LAM2 = LibStub("LibAddonMenu-2.0")
2034 LAM2:OpenToPanel(QUESTTRACKER.addonPanel)
2035 end
2036
2037 --[[
2038 -- Slash commands to possibly support from Wykkyd's Version
2039 self:SlashCommand("qta", _addon.Abandon) --Abandon a quest by index # will show index list if # omitted
2040 self:SlashCommand("qtbl", _addon.BlackList) --not sure
2041 self:SlashCommand("qts", _addon.Share) --share a quest by index # will show index list if # omitted
2042 self:SlashCommand("qtwl", _addon.WhiteList) --not sure
2043 self:SlashCommand("qtt", _addon.Track) --focus a specific quest (by index #) qtt with no # will list index list
2044 --]]
2045end