You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
498 lines
14 KiB
498 lines
14 KiB
|
5 years ago
|
-- ========================================================================= --
|
||
|
|
-- SylingTracker --
|
||
|
|
-- https://www.curseforge.com/wow/addons/sylingtracker --
|
||
|
|
-- --
|
||
|
|
-- Repository: --
|
||
|
|
-- https://github.com/Skamer/SylingTracker --
|
||
|
|
-- --
|
||
|
|
-- ========================================================================= --
|
||
|
|
Syling "SylingTracker.Tasks.Task" ""
|
||
|
|
-- ========================================================================= --
|
||
|
|
namespace "SLT"
|
||
|
|
-- ========================================================================= --
|
||
|
|
export {
|
||
|
|
-- Iterator helper for ignoring the children are used for backdrop, and avoiding
|
||
|
|
-- they are taken as account for their parent height
|
||
|
|
IterateFrameChildren = Utils.IterateFrameChildren,
|
||
|
|
|
||
|
|
ResetStyles = Utils.ResetStyles,
|
||
|
|
ShowContextMenu = API.ShowContextMenu,
|
||
|
|
ValidateFlags = System.Toolset.validateflags,
|
||
|
|
|
||
|
|
GameTooltip = GameTooltip
|
||
|
|
}
|
||
|
|
-- ========================================================================= --
|
||
|
|
__Recyclable__ "SylingTracker_TaskView%d"
|
||
|
|
class "TaskView" (function(_ENV)
|
||
|
|
inherit "Button" extend "IView"
|
||
|
|
|
||
|
|
__Flags__()
|
||
|
|
enum "Flags" {
|
||
|
|
NONE = 0,
|
||
|
|
HAS_OBJECTIVES = 1,
|
||
|
|
HAS_ITEM = 2
|
||
|
|
}
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Methods --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
function OnViewUpdate(self, data, updater)
|
||
|
|
local header = self:GetChild("Header")
|
||
|
|
local objectives = self:GetChild("Objectives")
|
||
|
|
local nameFS = header:GetChild("Name")
|
||
|
|
|
||
|
|
-- Determines the flags
|
||
|
|
local flags = Flags.NONE
|
||
|
|
if data.objectives then
|
||
|
|
flags = flags + Flags.HAS_OBJECTIVES
|
||
|
|
end
|
||
|
|
|
||
|
|
if data.item then
|
||
|
|
flags = flags + Flags.HAS_ITEM
|
||
|
|
end
|
||
|
|
|
||
|
|
if flags ~= self.Flags then
|
||
|
|
ResetStyles(self)
|
||
|
|
ResetStyles(header)
|
||
|
|
ResetStyles(nameFS)
|
||
|
|
|
||
|
|
-- Is the task has objectives
|
||
|
|
if ValidateFlags(Flags.HAS_OBJECTIVES, flags) then
|
||
|
|
self:AcquireObjectives()
|
||
|
|
else
|
||
|
|
self:ReleaseObjectives()
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Is the task has an item quest
|
||
|
|
if ValidateFlags(Flags.HAS_ITEM, flags) then
|
||
|
|
self:AcquireItemBadge()
|
||
|
|
else
|
||
|
|
self:ReleaseItemBadge()
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Styling stuff
|
||
|
|
if flags ~= Flags.NONE then
|
||
|
|
local styles = self.FlagsStyles and self.FlagsStyles[flags]
|
||
|
|
if styles then
|
||
|
|
Style[self] = styles
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Update the context menu if exists
|
||
|
|
if self.ContextMenuID and data.questID then
|
||
|
|
self.OnClick = function(_, mouseButton)
|
||
|
|
if mouseButton == "RightButton" then
|
||
|
|
ShowContextMenu(self.ContextMenuID, self, data.questID)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Update the task name
|
||
|
|
Style[nameFS].text = data.name
|
||
|
|
|
||
|
|
-- Update the objectives if needed
|
||
|
|
local objectivesData = data.objectives
|
||
|
|
if objectivesData then
|
||
|
|
local objectivesView = self:AcquireObjectives()
|
||
|
|
objectivesView:UpdateView(objectivesData)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Update the item if needed
|
||
|
|
local itemData = data.item
|
||
|
|
if itemData then
|
||
|
|
local itemBadge = self:AcquireItemBadge()
|
||
|
|
Style[itemBadge].Icon.fileID = itemData.texture
|
||
|
|
|
||
|
|
if itemData.link then
|
||
|
|
itemBadge.OnLeave = function() GameTooltip:Hide() end
|
||
|
|
itemBadge.OnEnter = function()
|
||
|
|
GameTooltip:SetOwner(itemBadge, "ANCHOR_LEFT")
|
||
|
|
GameTooltip:SetHyperlink(itemData.link)
|
||
|
|
GameTooltip:Show()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self.Flags = flags
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnAdjustHeight(self, useAnimation)
|
||
|
|
local maxOuterBottom
|
||
|
|
for childName, child in IterateFrameChildren(self) do
|
||
|
|
|
||
|
|
local outerBottom = child:GetBottom()
|
||
|
|
local outerTop = child:GetTop()
|
||
|
|
if outerBottom then
|
||
|
|
if not maxOuterBottom or maxOuterBottom > outerBottom then
|
||
|
|
maxOuterBottom = outerBottom
|
||
|
|
maxChild = child
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if maxOuterBottom then
|
||
|
|
local computeHeight = (self:GetTop() - maxOuterBottom) + self.PaddingBottom
|
||
|
|
if useAnimation then
|
||
|
|
self:SetAnimatedHeight(computeHeight)
|
||
|
|
else
|
||
|
|
self:SetHeight(computeHeight)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function AcquireObjectives(self)
|
||
|
|
local objectives = self:GetChild("Objectives")
|
||
|
|
if not objectives then
|
||
|
|
objectives = ObjectiveListView.Acquire()
|
||
|
|
|
||
|
|
-- We need to keep the old name when we'll release it.
|
||
|
|
self.__PreviousObjectivesName = objectives:GetName()
|
||
|
|
|
||
|
|
objectives:SetParent(self)
|
||
|
|
objectives:SetName("Objectives")
|
||
|
|
objectives:InstantApplyStyle()
|
||
|
|
|
||
|
|
-- Register the events
|
||
|
|
objectives.OnSizeChanged = objectives.OnSizeChanged + self.OnObjectivesSizeChanged
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
|
||
|
|
return objectives
|
||
|
|
end
|
||
|
|
|
||
|
|
function ReleaseObjectives(self)
|
||
|
|
local objectives = self:GetChild("Objectives")
|
||
|
|
if objectives then
|
||
|
|
-- Give its old name (generated by the recycle system)
|
||
|
|
objectives:SetName(self.__PreviousObjectivesName)
|
||
|
|
self.__PreviousObjectivesName = nil
|
||
|
|
|
||
|
|
-- Unregister the events
|
||
|
|
objectives.OnSizeChanged = objectives.OnSizeChanged - self.OnObjectivesSizeChanged
|
||
|
|
|
||
|
|
-- It's better to release it after the event has been unregistered for avoiding
|
||
|
|
-- useless call
|
||
|
|
objectives:Release()
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function AcquireItemBadge(self)
|
||
|
|
local itemBadge = self:GetChild("Item")
|
||
|
|
if not itemBadge then
|
||
|
|
itemBadge = IconBadge.Acquire()
|
||
|
|
self.__PreviousItemBadgeName = itemBadge:GetName()
|
||
|
|
|
||
|
|
itemBadge:SetParent(self)
|
||
|
|
itemBadge:SetName("Item")
|
||
|
|
itemBadge:InstantApplyStyle()
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
|
||
|
|
return itemBadge
|
||
|
|
end
|
||
|
|
|
||
|
|
function ReleaseItemBadge(self)
|
||
|
|
local itemBadge = self:GetChild("Item")
|
||
|
|
if itemBadge then
|
||
|
|
itemBadge:SetName(self.__PreviousItemBadgeName)
|
||
|
|
self.__PreviousItemBadgeName = nil
|
||
|
|
|
||
|
|
itemBadge.OnLeave = nil
|
||
|
|
itemBadge.OnEnter = nil
|
||
|
|
|
||
|
|
itemBadge:Release()
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnRelease(self)
|
||
|
|
-- Release first the children
|
||
|
|
self:ReleaseObjectives()
|
||
|
|
self:ReleaseItemBadge()
|
||
|
|
|
||
|
|
self:Hide()
|
||
|
|
self:ClearAllPoints()
|
||
|
|
self:SetParent()
|
||
|
|
|
||
|
|
-- "CancelAdjustHeight" and "CancelAnimatingHeight" wiil cancel the pending
|
||
|
|
-- computing stuff for height, so they not prevent "SetHeight" here doing
|
||
|
|
-- its stuff.
|
||
|
|
self:CancelAdjustHeight()
|
||
|
|
self:CancelAnimatingHeight()
|
||
|
|
self:SetHeight(1)
|
||
|
|
|
||
|
|
-- Reset the class properties
|
||
|
|
self.Type = nil
|
||
|
|
self.Flags = nil
|
||
|
|
|
||
|
|
-- Will Remove all custom styles properties, so the next time the object will
|
||
|
|
-- be used, this one will be in a clean state
|
||
|
|
ResetStyles(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnAcquire(self)
|
||
|
|
-- Important ! We need the frame is instantly styled as this may affect
|
||
|
|
-- its height.
|
||
|
|
self:InstantApplyStyle()
|
||
|
|
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
|
||
|
|
self:Show()
|
||
|
|
end
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Properties --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
property "PaddingBottom" {
|
||
|
|
type = Number,
|
||
|
|
default = 5
|
||
|
|
}
|
||
|
|
|
||
|
|
property "ObjectivesClass" {
|
||
|
|
type = ClassType,
|
||
|
|
default = ObjectiveListView
|
||
|
|
}
|
||
|
|
|
||
|
|
property "Flags" {
|
||
|
|
type = TaskView.Flags,
|
||
|
|
default = TaskView.Flags.NONE
|
||
|
|
}
|
||
|
|
|
||
|
|
property "FlagsStyles" {
|
||
|
|
type = Table,
|
||
|
|
}
|
||
|
|
|
||
|
|
property "ContextMenuID" {
|
||
|
|
type = String,
|
||
|
|
default = "task"
|
||
|
|
}
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Constructors --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
__Template__{
|
||
|
|
Header = Frame,
|
||
|
|
{
|
||
|
|
Header = {
|
||
|
|
Name = SLTFontString
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function __ctor(self)
|
||
|
|
-- Important! As the frame ajusts its height depending of its children height
|
||
|
|
-- we need to set its height when contructed for the event "OnSizechanged" of
|
||
|
|
-- its children is triggered.
|
||
|
|
self:SetHeight(1)
|
||
|
|
|
||
|
|
self.OnObjectivesSizeChanged = function() self:AdjustHeight() end
|
||
|
|
|
||
|
|
self:SetClipsChildren(true)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
__Recyclable__ "SylingTracker_TaskListView%d"
|
||
|
|
class "TaskListView" (function(_ENV)
|
||
|
|
inherit "Frame" extend "IView"
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Methods --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
function OnViewUpdate(self, data, updater)
|
||
|
|
local questIndex = 0
|
||
|
|
wipe(self.questsID)
|
||
|
|
|
||
|
|
local previousQuest
|
||
|
|
for _, questData in pairs(data) do
|
||
|
|
questIndex = questIndex + 1
|
||
|
|
|
||
|
|
local questID = questData.questID
|
||
|
|
|
||
|
|
|
||
|
|
local quest = self:AcquireQuest(questID)
|
||
|
|
|
||
|
|
if questIndex > 1 then
|
||
|
|
quest:SetPoint("TOP", previousQuest, "BOTTOM", 0, -self.TasksSpacing)
|
||
|
|
elseif questIndex == 1 then
|
||
|
|
quest:SetPoint("TOP")
|
||
|
|
end
|
||
|
|
quest:Show()
|
||
|
|
quest:UpdateView(questData, updater)
|
||
|
|
|
||
|
|
previousQuest = quest
|
||
|
|
|
||
|
|
self.questsID[questID] = true
|
||
|
|
end
|
||
|
|
|
||
|
|
self:ReleaseUnusedQuests()
|
||
|
|
end
|
||
|
|
|
||
|
|
function AcquireQuest(self, id)
|
||
|
|
local quest = self.questsCache[id]
|
||
|
|
if not quest then
|
||
|
|
quest = TaskView.Acquire()
|
||
|
|
quest:SetParent(self)
|
||
|
|
quest:SetPoint("LEFT")
|
||
|
|
quest:SetPoint("RIGHT")
|
||
|
|
|
||
|
|
quest.OnSizeChanged = quest.OnSizeChanged + self.OnTaskSizeChanged
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
|
||
|
|
self.questsCache[id] = quest
|
||
|
|
end
|
||
|
|
|
||
|
|
return quest
|
||
|
|
end
|
||
|
|
|
||
|
|
function ReleaseUnusedQuests(self)
|
||
|
|
for questID, quest in pairs(self.questsCache) do
|
||
|
|
if not self.questsID[questID] then
|
||
|
|
self.questsCache[questID] = nil
|
||
|
|
|
||
|
|
quest.OnSizeChanged = quest.OnSizeChanged - self.OnTaskSizeChanged
|
||
|
|
quest:Release()
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnAdjustHeight(self, useAnimation)
|
||
|
|
local height = 0
|
||
|
|
local count = 0
|
||
|
|
for _, child in IterateFrameChildren(self) do
|
||
|
|
height = height + child:GetHeight()
|
||
|
|
|
||
|
|
count = count + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
height = height + self.TasksSpacing * math.max(0, count-1)
|
||
|
|
|
||
|
|
if useAnimation then
|
||
|
|
self:SetAnimatedHeight(height)
|
||
|
|
else
|
||
|
|
self:SetHeight(height)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnRelease(self)
|
||
|
|
wipe(self.questsID)
|
||
|
|
self:ReleaseUnusedQuests()
|
||
|
|
|
||
|
|
self:ClearAllPoints()
|
||
|
|
self:SetParent()
|
||
|
|
self:Hide()
|
||
|
|
self:CancelAdjustHeight()
|
||
|
|
self:CancelAnimatingHeight()
|
||
|
|
|
||
|
|
self:SetHeight(1)
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnAcquire(self)
|
||
|
|
self:Show()
|
||
|
|
-- Important ! We need the frame is instantly styled as this may affect
|
||
|
|
-- its height.
|
||
|
|
-- self:InstantApplyStyle()
|
||
|
|
end
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Properties --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
property "TasksSpacing" {
|
||
|
|
type = Number,
|
||
|
|
default = 5
|
||
|
|
}
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Constructors --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
function __ctor(self)
|
||
|
|
-- -- Important ! We need the frame is instantly styled as this may affect
|
||
|
|
-- -- its height.
|
||
|
|
-- self:InstantApplyStyle()
|
||
|
|
|
||
|
|
-- Important! As the frame ajusts its height depending of its children height
|
||
|
|
-- we need to set its height when contructed for the event "OnSizechanged" of
|
||
|
|
-- its children is triggered.
|
||
|
|
self:SetHeight(1) -- !important
|
||
|
|
|
||
|
|
-- Keep in the cache the bonus quest, to be reused.
|
||
|
|
-- use: self.questsCache[questID] = questObject
|
||
|
|
self.questsCache = setmetatable({}, { __mode = "v"})
|
||
|
|
|
||
|
|
-- Get the current bonus quest id's list. Used internally to release the
|
||
|
|
-- unused bonus quests
|
||
|
|
-- use: self.questsID[questID] = true or nil
|
||
|
|
self.questsID = {}
|
||
|
|
|
||
|
|
self.OnTaskSizeChanged = function() self:AdjustHeight() end
|
||
|
|
|
||
|
|
|
||
|
|
self:SetClipsChildren(true)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
-- ========================================================================= --
|
||
|
|
-- Styles --
|
||
|
|
-- ========================================================================= --
|
||
|
|
Style.UpdateSkin("Default", {
|
||
|
|
[TaskView] = {
|
||
|
|
backdrop = {
|
||
|
|
bgFile = [[Interface\AddOns\SylingTracker\Media\Textures\LinearGradient]]
|
||
|
|
},
|
||
|
|
backdropColor = { r = 35/255, g = 40/255, b = 46/255, a = 0.73},
|
||
|
|
registerForClicks = { "RightButtonDown" },
|
||
|
|
|
||
|
|
-- Header Child
|
||
|
|
Header = {
|
||
|
|
height = 24,
|
||
|
|
location = {
|
||
|
|
Anchor("TOPLEFT"),
|
||
|
|
Anchor("TOPRIGHT")
|
||
|
|
},
|
||
|
|
|
||
|
|
-- Header/Name child
|
||
|
|
Name = {
|
||
|
|
setAllPoints = true,
|
||
|
|
sharedMediaFont = FontType("DejaVuSansCondensed Bold", 10),
|
||
|
|
textColor = Color(1, 106/255, 0)
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
FlagsStyles = {
|
||
|
|
[TaskView.Flags.HAS_OBJECTIVES] = {
|
||
|
|
Objectives = {
|
||
|
|
spacing = 5,
|
||
|
|
location = {
|
||
|
|
Anchor("TOP", 0, -4, "Header", "BOTTOM"),
|
||
|
|
Anchor("LEFT"),
|
||
|
|
Anchor("RIGHT")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
[TaskView.Flags.HAS_OBJECTIVES + TaskView.Flags.HAS_ITEM] = {
|
||
|
|
Item = {
|
||
|
|
height = 28,
|
||
|
|
width = 28,
|
||
|
|
location = {
|
||
|
|
Anchor("TOPLEFT", 4, -4, "Header", "BOTTOMLEFT")
|
||
|
|
},
|
||
|
|
|
||
|
|
Icon = {
|
||
|
|
texCoords = RectType(0.07, 0.93, 0.07, 0.93)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
Objectives = {
|
||
|
|
spacing = 5,
|
||
|
|
location = {
|
||
|
|
Anchor("TOP", 2, -4, "Header", "BOTTOM"),
|
||
|
|
Anchor("LEFT", 2, 0, "Item", "RIGHT"),
|
||
|
|
Anchor("RIGHT")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|