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.
348 lines
10 KiB
348 lines
10 KiB
-- ========================================================================= --
|
|
-- SylingTracker --
|
|
-- https://www.curseforge.com/wow/addons/sylingtracker --
|
|
-- --
|
|
-- Repository: --
|
|
-- https://github.com/Skamer/SylingTracker --
|
|
-- --
|
|
-- ========================================================================= --
|
|
Syling "SylingTracker.UI.ContextMenu" ""
|
|
-- ========================================================================= --
|
|
namespace "SLT"
|
|
-- ========================================================================= --
|
|
|
|
enum "ContextMenuItemType" {
|
|
"Action",
|
|
"Separator"
|
|
}
|
|
|
|
struct "ContextMenuPatternItemInfo" (function(_ENV)
|
|
member "id" { type = Number + String }
|
|
member "text" { type = String, default = "" }
|
|
member "handler" { type = Function }
|
|
member "order" { tpye= Number, default = 100 }
|
|
member "icon" { type = String + Table }
|
|
member "type" { type = ContextMenuItemType }
|
|
member "disabled" { type = Boolean + Function, default = false }
|
|
member "isShown" { type = Boolean + Function, default = true }
|
|
end)
|
|
|
|
|
|
--- Contains the info relative to a context menu to build
|
|
class "ContextMenuPattern" (function(_ENV)
|
|
-----------------------------------------------------------------------------
|
|
-- Methods --
|
|
-----------------------------------------------------------------------------
|
|
__Arguments__{ ContextMenuPatternItemInfo }
|
|
function AddAction(self, info)
|
|
info.type = "Action"
|
|
self.Items:Insert(info)
|
|
end
|
|
|
|
__Arguments__ { Number }
|
|
function AddSeparator(self, order)
|
|
local info = ContextMenuPatternItemInfo()
|
|
info.order = order
|
|
info.type = "Separator"
|
|
self.Items:Insert(info)
|
|
end
|
|
|
|
__Iterator__()
|
|
function IterateItems(self, args)
|
|
local yield = coroutine.yield
|
|
|
|
local count = 0
|
|
for index, itemInfo in self.Items:Sort("a,b=>a.order<b.order"):GetIterator() do
|
|
local isShown
|
|
if type(itemInfo.isShown) == "function" then
|
|
isShown = itemInfo.isShown(unpack(args))
|
|
else
|
|
isShown = itemInfo.isShown
|
|
end
|
|
|
|
if isShown then
|
|
count = count + 1
|
|
yield(count, itemInfo)
|
|
end
|
|
end
|
|
end
|
|
-----------------------------------------------------------------------------
|
|
-- Properties --
|
|
-----------------------------------------------------------------------------
|
|
property "Items" {
|
|
default = function() return List() end
|
|
}
|
|
end)
|
|
|
|
class "ContextMenuAction" (function(_ENV)
|
|
inherit "Button"
|
|
|
|
_Recycler = Recycle(ContextMenuAction, "SylingTracker_ContextMenuAction%d")
|
|
-----------------------------------------------------------------------------
|
|
-- Methods --
|
|
-----------------------------------------------------------------------------
|
|
function Release(self)
|
|
self:Hide()
|
|
self:SetParent()
|
|
self:ClearAllPoints()
|
|
|
|
_Recycler(self)
|
|
end
|
|
|
|
__Static__() function Acquire()
|
|
local obj = _Recycler()
|
|
obj:Show()
|
|
|
|
return obj
|
|
end
|
|
-----------------------------------------------------------------------------
|
|
-- Constructors --
|
|
-----------------------------------------------------------------------------
|
|
__Template__{
|
|
Icon = Texture,
|
|
Text = SLTFontString
|
|
}
|
|
function __ctor(self) self:InstantApplyStyle() end
|
|
|
|
end)
|
|
|
|
class "ContextMenuSeparator" (function(_ENV)
|
|
inherit "Frame"
|
|
|
|
_Recycler = Recycle(ContextMenuSeparator, "SylingTracker_ContextMenuSeparator%d")
|
|
-----------------------------------------------------------------------------
|
|
-- Methods --
|
|
-----------------------------------------------------------------------------
|
|
function Release(self)
|
|
self:Hide()
|
|
self:SetParent()
|
|
self:ClearAllPoints()
|
|
|
|
_Recycler(self)
|
|
end
|
|
|
|
__Static__() function Acquire()
|
|
local obj = _Recycler()
|
|
obj:Show()
|
|
|
|
return obj
|
|
end
|
|
end)
|
|
|
|
|
|
class "ContextMenu" (function(_ENV)
|
|
inherit "Frame"
|
|
|
|
_ItemObjects = {
|
|
[ContextMenuItemType.Action] = setmetatable({}, { __mode = "v"}),
|
|
[ContextMenuItemType.Separator] = setmetatable({}, { __mode = "v"})
|
|
}
|
|
|
|
function AcquireItem(self, type, index)
|
|
|
|
local obj = _ItemObjects[type][index]
|
|
if not obj then
|
|
if type == ContextMenuItemType.Separator then
|
|
obj = ContextMenuSeparator.Acquire()
|
|
else
|
|
obj = ContextMenuAction.Acquire()
|
|
end
|
|
end
|
|
|
|
_ItemObjects[type][index] = obj
|
|
|
|
obj:SetParent(self)
|
|
obj:Show()
|
|
|
|
return obj
|
|
end
|
|
|
|
function ReleaseUnusedItems(self, type, releaseFromIndex)
|
|
local objects = _ItemObjects[type]
|
|
for index, obj in pairs(objects) do
|
|
if index > releaseFromIndex then
|
|
obj:Release()
|
|
objects[index] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
end)
|
|
|
|
Style.UpdateSkin("Default", {
|
|
[ContextMenu] = {
|
|
width = 175,
|
|
backdrop = {
|
|
bgFile = [[Interface\AddOns\SylingTracker\Media\Textures\LinearGradient]]
|
|
},
|
|
backdropColor = { r = 0, g = 0, b = 0, a = 0.6},
|
|
hitRectInsets = {
|
|
top = -30,
|
|
left = -30,
|
|
bottom = -30,
|
|
right = -30
|
|
}
|
|
},
|
|
[ContextMenuAction] = {
|
|
height = 24,
|
|
Icon = {
|
|
size = Size(16, 16),
|
|
atlas = AtlasType("communities-icon-redx"),
|
|
location = {
|
|
Anchor("TOPLEFT", 4, -4)
|
|
}
|
|
},
|
|
Text = {
|
|
location = {
|
|
Anchor("TOP"),
|
|
Anchor("LEFT", 24, 0),
|
|
Anchor("RIGHT"),
|
|
Anchor("BOTTOM")
|
|
},
|
|
-- font = FontType([[Interface\AddOns\EskaTracker2\Media\Fonts\PTSans-Narrow-Bold.ttf]], 13),
|
|
sharedMediaFont = FontType("PT Sans Narrow Bold", 13),
|
|
textColor = Color(0.8, 0.8, 0.8),
|
|
justifyH = "LEFT",
|
|
},
|
|
HighlightTexture = {
|
|
file = [[Interface\AddOns\SylingTracker\Media\Textures\LinearGradient]],
|
|
vertexColor = { r = 0, g = 148/255, b = 1, a = 0.35},
|
|
setAllPoints = true,
|
|
},
|
|
|
|
},
|
|
[ContextMenuSeparator] = {
|
|
height = 2,
|
|
backdrop = {
|
|
bgFile = [[Interface\AddOns\SylingTracker\Media\Textures\LinearGradient]]
|
|
},
|
|
backdropColor = {r = 1 , g = 1, b = 1, a = 0.15}
|
|
}
|
|
})
|
|
|
|
|
|
_ContextMenu = ContextMenu("SylingTracker_ContextMenu", UIParent)
|
|
-- _ContextMenu:SetPoint("CENTER", 0, -200)
|
|
|
|
_ContextMenuArrow = Arrow.Acquire()
|
|
_ContextMenuArrow:SetParent(UIParent)
|
|
-- _ContextMenuArrow.Orientation = "RIGHT"
|
|
-- _ContextMenu:SetPoint("TOPRIGHT", _ContextMenuArrow, "LEFT", 5, 20)
|
|
|
|
_ContextMenuArrow:Hide()
|
|
_ContextMenu:Hide()
|
|
|
|
|
|
|
|
_ContextMenuPatterns = {}
|
|
|
|
|
|
|
|
|
|
class "API" (function(_ENV)
|
|
__Static__() function CloseContextMenu()
|
|
_ContextMenu:Hide()
|
|
_ContextMenuArrow:Hide()
|
|
_ContextMenu.OnUpdate = nil
|
|
end
|
|
|
|
__Static__() function ShowContextMenu(patternID, frameToAnchor, ...)
|
|
local pattern = _ContextMenuPatterns[patternID]
|
|
|
|
if not pattern then
|
|
return
|
|
end
|
|
|
|
|
|
local args = { ... }
|
|
|
|
local counts = {
|
|
[ContextMenuItemType.Action] = 0,
|
|
[ContextMenuItemType.Separator] = 0,
|
|
}
|
|
|
|
local height = 0
|
|
|
|
local previousItem
|
|
for index, itemInfo in pattern:IterateItems(args) do
|
|
local i = counts[itemInfo.type] + 1
|
|
counts[itemInfo.type] = i
|
|
local item = _ContextMenu:AcquireItem(itemInfo.type, i)
|
|
item:ClearAllPoints()
|
|
item:SetParent(_ContextMenu)
|
|
|
|
if index == 1 then
|
|
item:SetPoint("TOP")
|
|
item:SetPoint("LEFT")
|
|
item:SetPoint("RIGHT")
|
|
else
|
|
item:SetPoint("TOP", previousItem, "BOTTOM")
|
|
item:SetPoint("LEFT")
|
|
item:SetPoint("RIGHT")
|
|
end
|
|
|
|
if itemInfo.type == ContextMenuItemType.Action then
|
|
if itemInfo.handler then
|
|
item.OnClick = function()
|
|
itemInfo.handler(unpack(args))
|
|
CloseContextMenu()
|
|
end
|
|
end
|
|
|
|
Style[item].Text.text = itemInfo.text
|
|
|
|
local iconType = type(itemInfo.icon)
|
|
if iconType == "string" then
|
|
Style[item].Icon.file = itemInfo.icon
|
|
elseif iconType == "table" then
|
|
Style[item].Icon = itemInfo.icon
|
|
end
|
|
end
|
|
item:InstantApplyStyle()
|
|
|
|
height = height + item:GetHeight()
|
|
|
|
previousItem = item
|
|
end
|
|
|
|
_ContextMenu:SetHeight(height)
|
|
|
|
_ContextMenuArrow:ClearAllPoints()
|
|
_ContextMenu:ClearAllPoints()
|
|
|
|
-- Check the best side
|
|
if frameToAnchor:GetRight() < (GetScreenWidth() / 2) then
|
|
_ContextMenuArrow.Orientation = "LEFT"
|
|
_ContextMenu:SetPoint("TOPLEFT", _ContextMenuArrow, "RIGHT", -5, 20)
|
|
_ContextMenuArrow:SetPoint("LEFT", frameToAnchor, "RIGHT")
|
|
else
|
|
_ContextMenuArrow.Orientation = "RIGHT"
|
|
_ContextMenu:SetPoint("TOPRIGHT", _ContextMenuArrow, "LEFT", 5, 20)
|
|
_ContextMenuArrow:SetPoint("RIGHT", frameToAnchor, "LEFT")
|
|
end
|
|
|
|
_ContextMenuArrow:Show()
|
|
_ContextMenu:Show()
|
|
|
|
_ContextMenu.OnLeave = function(f)
|
|
if not f:IsMouseOver() then
|
|
CloseContextMenu()
|
|
end
|
|
end
|
|
|
|
|
|
-- Release the items unused
|
|
for type, count in pairs(counts) do
|
|
_ContextMenu:ReleaseUnusedItems(type, count)
|
|
end
|
|
end
|
|
|
|
__Static__() function RegisterContextMenuPattern(patternID, pattern)
|
|
_ContextMenuPatterns[patternID] = pattern
|
|
end
|
|
|
|
__Static__() function GetContextMenuPattern(patternID)
|
|
return _ContextMenuPatterns[pattern]
|
|
end
|
|
end)
|