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.
233 lines
8.2 KiB
233 lines
8.2 KiB
local _, addon = ...
|
|
|
|
--[[ namespace:CreateFrame(_..._)
|
|
A wrapper for [`CreateFrame`](https://warcraft.wiki.gg/wiki/API_CreateFrame), mixed in with `namespace.eventMixin`.
|
|
--]]
|
|
function addon:CreateFrame(...)
|
|
return Mixin(CreateFrame(...), addon.eventMixin)
|
|
end
|
|
|
|
local KEY_DIRECTION_CVAR = 'ActionButtonUseKeyDown'
|
|
|
|
local function updateKeyDirection(self)
|
|
if C_CVar.GetCVarBool(KEY_DIRECTION_CVAR) then
|
|
self:RegisterForClicks('AnyDown')
|
|
else
|
|
self:RegisterForClicks('AnyUp')
|
|
end
|
|
end
|
|
|
|
local function onCVarUpdate(self, cvar)
|
|
if cvar == KEY_DIRECTION_CVAR then
|
|
addon:Defer(updateKeyDirection, self)
|
|
end
|
|
end
|
|
|
|
--[[ namespace:CreateButton(...)
|
|
A wrapper for `namespace:CreateFrame(...)`, but will handle key direction preferences of the client.
|
|
Use this specifically to create clickable buttons.
|
|
--]]
|
|
function addon:CreateButton(...)
|
|
local button = addon:CreateFrame(...)
|
|
button:RegisterEvent('CVAR_UPDATE', onCVarUpdate)
|
|
|
|
-- the CVar doesn't trigger during login, so we'll have to trigger the handlers ourselves
|
|
onCVarUpdate(button, KEY_DIRECTION_CVAR)
|
|
|
|
return button
|
|
end
|
|
|
|
do -- scrollbox
|
|
local function defaultSort(a, b)
|
|
-- convert to string first so we can sort mixed types
|
|
return tostring(a) > tostring(b)
|
|
end
|
|
|
|
local function initialize(scroll)
|
|
if scroll._provider then
|
|
return
|
|
end
|
|
|
|
-- TODO: assertions
|
|
|
|
local provider = CreateDataProvider()
|
|
provider:SetSortComparator(scroll._sort or defaultSort, true)
|
|
|
|
local view
|
|
if scroll.kind == 'list' then
|
|
view = CreateScrollBoxListLinearView(scroll._insetTop, scroll._insetBottom, scroll._insetLeft, scroll._insetRight, scroll._spacingHorizontal)
|
|
elseif scroll.kind == 'grid' then
|
|
local width = scroll:GetWidth() - scroll.bar:GetWidth() - (scroll._insetLeft or 0) - (scroll._insetRight or 0)
|
|
local stride = math.floor((width - (scroll._spacingHorizontal or 0)) / (scroll._elementWidth + (scroll._spacingHorizontal or 0)))
|
|
view = CreateScrollBoxListGridView(stride, scroll._insetTop, scroll._insetBottom, scroll._insetLeft, scroll._insetRight, scroll._spacingHorizontal, scroll._spacingVertical)
|
|
view:SetStrideExtent(scroll._elementWidth)
|
|
end
|
|
|
|
view:SetDataProvider(provider)
|
|
view:SetElementExtent(scroll._elementHeight)
|
|
view:SetElementInitializer(scroll._elementType, function(element, data)
|
|
if scroll._elementWidth and scroll.kind == 'grid' then
|
|
element:SetWidth(scroll._elementWidth)
|
|
end
|
|
if scroll._elementHeight then
|
|
element:SetHeight(scroll._elementHeight)
|
|
end
|
|
|
|
if not element._initialized then
|
|
element._initialized = true
|
|
|
|
if scroll._scripts then
|
|
for script, callback in next, scroll._scripts do
|
|
element:SetScript(script, callback)
|
|
|
|
if script == 'OnEnter' and not scroll._scripts.OnLeave then
|
|
element:SetScript('OnLeave', GameTooltip_Hide)
|
|
end
|
|
end
|
|
end
|
|
|
|
if scroll._onLoad then
|
|
local successful, err = pcall(scroll._onLoad, element)
|
|
if not successful then
|
|
error(err)
|
|
end
|
|
end
|
|
end
|
|
|
|
element.data = data
|
|
|
|
if scroll._onUpdate then
|
|
local successful, err = pcall(scroll._onUpdate, element, data)
|
|
if not successful then
|
|
error(err)
|
|
end
|
|
end
|
|
end)
|
|
|
|
ScrollUtil.InitScrollBoxListWithScrollBar(scroll, scroll.bar, view)
|
|
ScrollUtil.AddManagedScrollBarVisibilityBehavior(scroll, scroll.bar) -- auto-hide the scroll bar
|
|
|
|
scroll._provider = provider
|
|
end
|
|
|
|
local scrollMixin = {}
|
|
function scrollMixin:SetInsets(top, bottom, left, right)
|
|
self._insetTop = top
|
|
self._insetBottom = bottom
|
|
self._insetLeft = left
|
|
self._insetRight = right
|
|
end
|
|
function scrollMixin:SetElementType(kind)
|
|
self._elementType = kind
|
|
end
|
|
function scrollMixin:SetElementHeight(height)
|
|
self._elementHeight = height
|
|
end
|
|
function scrollMixin:SetElementWidth(width)
|
|
self._elementWidth = width
|
|
end
|
|
function scrollMixin:SetElementSize(width, height)
|
|
self:SetElementWidth(width)
|
|
self:SetElementHeight(height or width)
|
|
end
|
|
function scrollMixin:SetElementSpacing(horizontal, vertical)
|
|
self._spacingHorizontal = horizontal
|
|
self._spacingVertical = vertical or horizontal
|
|
end
|
|
function scrollMixin:SetElementSortingMethod(callback)
|
|
self._sort = callback
|
|
end
|
|
function scrollMixin:SetElementOnLoad(callback)
|
|
self._onLoad = callback
|
|
end
|
|
function scrollMixin:SetElementOnScript(script, callback)
|
|
self._scripts = self._scripts or {}
|
|
self._scripts[script] = callback
|
|
end
|
|
function scrollMixin:SetElementOnUpdate(callback)
|
|
self._onUpdate = callback
|
|
end
|
|
function scrollMixin:AddData(...)
|
|
initialize(self)
|
|
self._provider:Insert(...)
|
|
end
|
|
function scrollMixin:AddDataByKeys(data)
|
|
for key, value in next, data do
|
|
if value then -- must be truthy
|
|
self:AddData(key)
|
|
end
|
|
end
|
|
end
|
|
function scrollMixin:RemoveData(...)
|
|
self._provider:Remove(...)
|
|
end
|
|
function scrollMixin:ResetData()
|
|
self._provider:Flush()
|
|
end
|
|
|
|
local function createScrollWidget(parent, kind)
|
|
local box = CreateFrame('Frame', nil, parent, 'WowScrollBoxList')
|
|
box:SetPoint('TOPLEFT')
|
|
box:SetPoint('BOTTOMRIGHT', -8, 0) -- offset to not overlap scrollbar
|
|
box.kind = kind
|
|
|
|
local bar = CreateFrame('EventFrame', nil, parent, 'MinimalScrollBar')
|
|
bar:SetPoint('TOPLEFT', box, 'TOPRIGHT')
|
|
bar:SetPoint('BOTTOMLEFT', box, 'BOTTOMRIGHT')
|
|
box.bar = bar
|
|
|
|
return Mixin(box, scrollMixin)
|
|
end
|
|
|
|
--[[ namespace:CreateScrollList(_parent_)
|
|
Creates and returns a scroll box with scroll bar and a data provider in a list representation.
|
|
It gets automatically sized to fill the space of the parent.
|
|
|
|
It provides the following methods, and is initialized whenever data is provided, so do that last.
|
|
|
|
* `list:SetInsets([top], [bottom], [left], [right])` - sets scroll box insets (all optional)
|
|
* `list:SetElementType(kind)` - sets the element type or template (required)
|
|
* `list:SetElementHeight(height)` - sets the element height (required)
|
|
* `list:SetElementSpacing(spacing)` - sets the spacing between elements (optional)
|
|
* `list:SetElementSortingMethod(callback)` - sets the sort method for element data (optional)
|
|
* `list:SetElementOnLoad(callback)` - sets the OnLoad method for each element (optional)
|
|
* the callback signature is `(element)`
|
|
* `list:SetElementOnUpdate(callback)` - sets the callback for element data updates (optional)
|
|
* the callback signature is `(element, data)`
|
|
* `list:SetElementOnScript(script, callback)` - sets the script handler for an element (optional)
|
|
* `list:AddData(...)`
|
|
* `list:AddDataByKeys(table)`
|
|
* `list:RemoveData(...)`
|
|
* `list:ResetData()`
|
|
--]]
|
|
function addon:CreateScrollList(parent)
|
|
return createScrollWidget(parent, 'list')
|
|
end
|
|
|
|
--[[ namespace:CreateScrollGrid(_parent_)
|
|
Creates and returns a scroll box with scroll bar and a data provider in a grid representation.
|
|
It gets automatically sized to fill the space of the parent.
|
|
|
|
It provides the following methods, and is initialized whenever data is provided, so do that last.
|
|
|
|
* `grid:SetInsets([top], [bottom], [left], [right])` - sets scroll box insets (all optional)
|
|
* `grid:SetElementType(kind)` - sets the element type or template (required)
|
|
* `grid:SetElementHeight(height)` - sets the element height (required)
|
|
* `grid:SetElementWidth(width)` - sets the element width (required)
|
|
* `grid:SetElementSize(width[, height])` - sets the element width and height, shorthand for the two above, height falls back to width if not provided
|
|
* `grid:SetElementSpacing(horizontal[, vertical])` - sets the spacing between elements, vertical falls back to horizontal if not provided (optional)
|
|
* `grid:SetElementSortingMethod(callback)` - sets the sort method for element data (optional)
|
|
* `grid:SetElementOnLoad(callback)` - sets the OnLoad method for each element (optional)
|
|
* the callback signature is `(element)`
|
|
* `grid:SetElementOnUpdate(callback)` - sets the callback for element data updates (optional)
|
|
* the callback signature is `(element, data)`
|
|
* `grid:SetElementOnScript(script, callback)` - sets the script handler for an element (optional)
|
|
* `grid:AddData(...)`
|
|
* `grid:AddDataByKeys(table)`
|
|
* `grid:RemoveData(...)`
|
|
* `grid:ResetData()`
|
|
--]]
|
|
function addon:CreateScrollGrid(parent)
|
|
return createScrollWidget(parent, 'grid')
|
|
end
|
|
end
|
|
|