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.
468 lines
14 KiB
468 lines
14 KiB
|
5 years ago
|
-- ========================================================================= --
|
||
|
|
-- EskaTracker 2 --
|
||
|
|
-- https://www.curseforge.com/wow/addons/eskatracker-2 --
|
||
|
|
-- --
|
||
|
|
-- Repository: --
|
||
|
|
-- https://github.com/Skamer/EskaTracker2 --
|
||
|
|
-- --
|
||
|
|
-- ========================================================================= --
|
||
|
|
Syling "SylingTracker.Achievements.AchievementView" ""
|
||
|
|
-- ========================================================================= --
|
||
|
|
namespace "SLT"
|
||
|
|
-- ========================================================================= --
|
||
|
|
-- Iterator helper for ignoring the children are used for backdrop, and avoiding
|
||
|
|
-- they are taken as account for their parent height
|
||
|
|
IterateFrameChildren = Utils.IterateFrameChildren
|
||
|
|
-- ========================================================================= --
|
||
|
|
ShowContextMenu = API.ShowContextMenu
|
||
|
|
wipe = wipe
|
||
|
|
ValidateFlags = System.Toolset.validateflags
|
||
|
|
ResetStyles = Utils.ResetStyles
|
||
|
|
-- ========================================================================= --
|
||
|
|
__Recyclable__ "SylingTracker_AchievementView%d"
|
||
|
|
class "AchievementView" (function(_ENV)
|
||
|
|
inherit "Button" extend "IView"
|
||
|
|
|
||
|
|
__Flags__()
|
||
|
|
enum "Flags" {
|
||
|
|
NONE = 0,
|
||
|
|
HAS_OBJECTIVES = 1,
|
||
|
|
HAS_PROGRESS_BAR = 2
|
||
|
|
}
|
||
|
|
|
||
|
|
function OnViewUpdate(self, data)
|
||
|
|
local nameFS = self:GetChild("Name")
|
||
|
|
local descFS = self:GetChild("Description")
|
||
|
|
local iconBadge = self:GetChild("IconBadge")
|
||
|
|
|
||
|
|
-- Determines the flags
|
||
|
|
local flags = Flags.NONE
|
||
|
|
local hasProgressBar = false
|
||
|
|
local objectivesData = data.objectives
|
||
|
|
local firstObjectiveData
|
||
|
|
if objectivesData then
|
||
|
|
local firstObjectiveData = objectivesData[1]
|
||
|
|
if firstObjectiveData then
|
||
|
|
hasProgressBar = firstObjectiveData.hasProgressBar
|
||
|
|
end
|
||
|
|
|
||
|
|
if hasProgressBar then
|
||
|
|
flags = Flags.HAS_PROGRESS_BAR + Flags.HAS_OBJECTIVES
|
||
|
|
else
|
||
|
|
flags = Flags.HAS_OBJECTIVES
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if flags ~= self.Flags then
|
||
|
|
ResetStyles(self)
|
||
|
|
ResetStyles(nameFS)
|
||
|
|
ResetStyles(descFS)
|
||
|
|
|
||
|
|
-- Is the achievement has objectives
|
||
|
|
if ValidateFlags(Flags.HAS_OBJECTIVES, flags) then
|
||
|
|
self:AcquireObjectives()
|
||
|
|
else
|
||
|
|
self:ReleaseObjectives()
|
||
|
|
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 achievement name
|
||
|
|
Style[nameFS].text = data.name
|
||
|
|
|
||
|
|
-- Update the description
|
||
|
|
Style[descFS].text = data.description
|
||
|
|
|
||
|
|
-- Update the icon
|
||
|
|
Style[iconBadge].Icon.fileID = data.icon
|
||
|
|
|
||
|
|
-- Update the context menu
|
||
|
|
if data.achievementID then
|
||
|
|
self.OnClick = function()
|
||
|
|
ShowContextMenu("achievement", self, data.achievementID)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Update the objectives if needed
|
||
|
|
if objectivesData then
|
||
|
|
local objectivesView = self:AcquireObjectives()
|
||
|
|
objectivesView:UpdateView(objectivesData)
|
||
|
|
end
|
||
|
|
|
||
|
|
self.Flags = flags
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnAdjustHeight(self, useAnimation)
|
||
|
|
local maxOuterBottom
|
||
|
|
for childName, child in IterateFrameChildren(self) do
|
||
|
|
local outerBottom = child:GetBottom()
|
||
|
|
if outerBottom then
|
||
|
|
if not maxOuterBottom or maxOuterBottom > outerBottom then
|
||
|
|
maxOuterBottom = outerBottom
|
||
|
|
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 the objective list
|
||
|
|
self.__PreviousObjectivesName = objectives:GetName()
|
||
|
|
|
||
|
|
objectives:SetParent(self)
|
||
|
|
objectives:SetName("Objectives")
|
||
|
|
objectives:InstantApplyStyle()
|
||
|
|
|
||
|
|
-- if self.Objectives then
|
||
|
|
-- Style[objectives] = self.Objectives
|
||
|
|
-- end
|
||
|
|
|
||
|
|
-- 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
|
||
|
|
objectives:SetName(self.__PreviousObjectivesName)
|
||
|
|
self.__PreviousObjectivesName = nil
|
||
|
|
|
||
|
|
-- Unregister the events
|
||
|
|
objectives.OnSizeChanged = objectives.OnSizeChanged - self.OnObjectivesSizeChanged
|
||
|
|
|
||
|
|
objectives:Release()
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnRelease(self)
|
||
|
|
-- Release first the children
|
||
|
|
self:ReleaseObjectives()
|
||
|
|
|
||
|
|
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.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:Show()
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Properties --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
property "FlagsStyles" {
|
||
|
|
type = Table
|
||
|
|
}
|
||
|
|
|
||
|
|
property "Flags" {
|
||
|
|
type = AchievementView.Flags,
|
||
|
|
default = AchievementView.Flags.NONE
|
||
|
|
}
|
||
|
|
|
||
|
|
property "ObjectivesClass" {
|
||
|
|
type = ClassType,
|
||
|
|
default = ObjectiveListView
|
||
|
|
}
|
||
|
|
|
||
|
|
property "PaddingBottom" {
|
||
|
|
type = Number,
|
||
|
|
default = 5
|
||
|
|
}
|
||
|
|
|
||
|
|
property "Objectives" {
|
||
|
|
type = Table
|
||
|
|
}
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Constructors --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
__Template__ {
|
||
|
|
Name = SLTFontString,
|
||
|
|
Description = SLTFontString,
|
||
|
|
IconBadge = IconBadge
|
||
|
|
}
|
||
|
|
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)
|
||
|
|
|
||
|
|
self.OnObjectivesSizeChanged = function() self:AdjustHeight() end
|
||
|
|
|
||
|
|
self:SetClipsChildren(true)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
--- Manages the achievements, if your view may have various achievements, this
|
||
|
|
-- is advised using this class
|
||
|
|
__Recyclable__ "SylingTracker_AchievementListView%d"
|
||
|
|
class "AchievementListView" (function(_ENV)
|
||
|
|
inherit "Frame" extend "IView"
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Methods --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
function OnViewUpdate(self, data)
|
||
|
|
local achievementIndex = 0
|
||
|
|
|
||
|
|
-- Clear the current achievement id list
|
||
|
|
wipe(self.achievementsID)
|
||
|
|
|
||
|
|
local previousAchievement
|
||
|
|
for achievementID, achievementData in pairs(data) do
|
||
|
|
achievementIndex = achievementIndex + 1
|
||
|
|
|
||
|
|
local achievement = self:AcquireAchievement(achievementID)
|
||
|
|
|
||
|
|
-- NOTE: Don't put other anchor could modify the width (e.g, LEFT or RIGHT) as
|
||
|
|
-- it will trigger useless "OnSizeChanged" event, breaking animation stuff.
|
||
|
|
if achievementIndex > 1 then
|
||
|
|
achievement:SetPoint("TOP", previousAchievement, "BOTTOM", 0, -self.AchievementSpacing)
|
||
|
|
else
|
||
|
|
achievement:SetPoint("TOP")
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Update our achievement with data
|
||
|
|
achievement:UpdateView(achievementData, updater)
|
||
|
|
|
||
|
|
-- Build the current achievement id list
|
||
|
|
self.achievementsID[achievementID] = true
|
||
|
|
|
||
|
|
previousAchievement = achievement
|
||
|
|
end
|
||
|
|
|
||
|
|
self:ReleaseUnusedAchievements()
|
||
|
|
end
|
||
|
|
|
||
|
|
function AcquireAchievement(self, id)
|
||
|
|
local achievement = self.achievementsCache[id]
|
||
|
|
if not achievement then
|
||
|
|
achievement = AchievementView.Acquire()
|
||
|
|
achievement:SetParent(self)
|
||
|
|
achievement:SetPoint("LEFT")
|
||
|
|
achievement:SetPoint("RIGHT")
|
||
|
|
|
||
|
|
achievement.OnSizeChanged = achievement.OnSizeChanged + self.OnAchievementSizeChanged
|
||
|
|
|
||
|
|
self.achievementsCache[id] = achievement
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
|
||
|
|
return achievement
|
||
|
|
end
|
||
|
|
|
||
|
|
function ReleaseUnusedAchievements(self)
|
||
|
|
for achievementID, achievement in pairs(self.achievementsCache) do
|
||
|
|
if not self.achievementsID[achievementID] then
|
||
|
|
self.achievementsCache[achievementID] = nil
|
||
|
|
|
||
|
|
achievement.OnSizeChanged = achievement.OnSizeChanged - self.OnAchievementSizeChanged
|
||
|
|
|
||
|
|
achievement: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.AchievementSpacing * math.max(0, count-1)
|
||
|
|
|
||
|
|
if useAnimation then
|
||
|
|
self:SetAnimatedHeight(height)
|
||
|
|
else
|
||
|
|
self:SetHeight(height)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnRelease(self)
|
||
|
|
wipe(self.achievementsID)
|
||
|
|
self:ReleaseUnusedAchievements()
|
||
|
|
|
||
|
|
self:Hide()
|
||
|
|
self:ClearAllPoints()
|
||
|
|
self:SetParent()
|
||
|
|
self:CancelAdjustHeight()
|
||
|
|
self:CancelAnimatingHeight()
|
||
|
|
|
||
|
|
self:SetHeight(1)
|
||
|
|
|
||
|
|
ResetStyles(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
function OnAcquire(self)
|
||
|
|
-- Important ! We need the frame is instantly styled as this may affect
|
||
|
|
-- its height.
|
||
|
|
self:InstantApplyStyle()
|
||
|
|
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
self:AdjustHeight()
|
||
|
|
end
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- Properties --
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
property "AchievementSpacing" {
|
||
|
|
type = Number,
|
||
|
|
default = 10
|
||
|
|
}
|
||
|
|
-----------------------------------------------------------------------------
|
||
|
|
-- 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 achievement, to be reused.
|
||
|
|
-- use: self.achievementsCache[achievementID] = achievementObject
|
||
|
|
self.achievementsCache = setmetatable({}, { __mode = "v"} )
|
||
|
|
|
||
|
|
-- Get the current achievement id's list. Used internally to release the
|
||
|
|
-- unused achievements
|
||
|
|
-- use: self.achievementsID[achievementID] = true or nil
|
||
|
|
self.achievementsID = {}
|
||
|
|
|
||
|
|
self.OnAchievementSizeChanged = function() self:AdjustHeight() end
|
||
|
|
|
||
|
|
self:SetClipsChildren(true)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
-------------------------------------------------------------------------------
|
||
|
|
-- Styles --
|
||
|
|
-------------------------------------------------------------------------------
|
||
|
|
Style.UpdateSkin("Default", {
|
||
|
|
[AchievementView] = {
|
||
|
|
width = 300,
|
||
|
|
backdrop = {
|
||
|
|
bgFile = [[Interface\AddOns\SylingTracker\Media\Textures\LinearGradient]]
|
||
|
|
},
|
||
|
|
backdropColor = { r = 35/255, g = 40/255, b = 46/255, a = 0.73},
|
||
|
|
registerForClicks = { "RightButtonDown" },
|
||
|
|
|
||
|
|
Name = {
|
||
|
|
sharedMediaFont = FontType("DejaVuSansCondensed Bold", 10),
|
||
|
|
height = 26,
|
||
|
|
location = {
|
||
|
|
Anchor("TOP"),
|
||
|
|
Anchor("LEFT"),
|
||
|
|
Anchor("RIGHT")
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
IconBadge = {
|
||
|
|
height = 46,
|
||
|
|
width = 46,
|
||
|
|
location = {
|
||
|
|
Anchor("TOPLEFT", 5, -5, "Name", "BOTTOMLEFT")
|
||
|
|
},
|
||
|
|
Icon = {
|
||
|
|
texCoords = RectType(0.07, 0.93, 0.07, 0.93)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
Description = {
|
||
|
|
height = 46,
|
||
|
|
sharedMediaFont = FontType("PT Sans Bold", 11),
|
||
|
|
textColor = Color(1, 1, 1),
|
||
|
|
justifyH = "LEFT",
|
||
|
|
justifyV = "TOP",
|
||
|
|
location = {
|
||
|
|
Anchor("TOP", 0, -5, "Name", "BOTTOM"),
|
||
|
|
Anchor("LEFT", 5, 0, "IconBadge", "RIGHT"),
|
||
|
|
Anchor("RIGHT")
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
FlagsStyles = {
|
||
|
|
[AchievementView.Flags.HAS_OBJECTIVES] = {
|
||
|
|
Objectives = {
|
||
|
|
spacing = 5,
|
||
|
|
location = {
|
||
|
|
Anchor("TOP", 0, -10, "IconBadge", "BOTTOM"),
|
||
|
|
Anchor("LEFT"),
|
||
|
|
Anchor("RIGHT")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
[AchievementView.Flags.HAS_OBJECTIVES + AchievementView.Flags.HAS_PROGRESS_BAR] = {
|
||
|
|
Description = {
|
||
|
|
visible = false
|
||
|
|
},
|
||
|
|
|
||
|
|
Objectives = {
|
||
|
|
spacing = 5,
|
||
|
|
location = {
|
||
|
|
Anchor("TOP", 0, -5, "Name", "BOTTOM"),
|
||
|
|
Anchor("LEFT", 5, 0, "IconBadge", "RIGHT"),
|
||
|
|
Anchor("RIGHT", -5, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|