TradeSkillMaster/Core/UI/Elements/QueryScrollingTable.lua

259 lines
8.4 KiB
Lua
Raw Normal View History

2020-11-13 14:13:12 -05:00
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster --
-- https://tradeskillmaster.com --
-- All Rights Reserved - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
--- Query Scrolling Table UI ScrollingTable Class.
-- A query scrolling table contains a scrollable list of rows with a fixed set of columns. It is a subclass of the
-- @{ScrollingTable} class.
-- @classmod QueryScrollingTable
local _, TSM = ...
local QueryScrollingTable = TSM.Include("LibTSMClass").DefineClass("QueryScrollingTable", TSM.UI.ScrollingTable)
local TempTable = TSM.Include("Util.TempTable")
local Table = TSM.Include("Util.Table")
local UIElements = TSM.Include("UI.UIElements")
UIElements.Register(QueryScrollingTable)
TSM.UI.QueryScrollingTable = QueryScrollingTable
local private = {}
-- ============================================================================
-- Public Class Methods
-- ============================================================================
function QueryScrollingTable.__init(self)
self.__super:__init()
self._query = nil
self._sortCol = nil
self._sortAscending = nil
self._autoReleaseQuery = false
end
function QueryScrollingTable.Release(self)
if self._query then
self._query:SetUpdateCallback()
if self._autoReleaseQuery then
self._query:Release()
end
self._query = nil
end
self._sortCol = nil
self._sortAscending = nil
self._autoReleaseQuery = false
self.__super:Release()
end
--- Sets the @{DatabaseQuery} source for this table.
-- This query is used to populate the entries in the query scrolling table.
-- @tparam QueryScrollingTable self The query scrolling table object
-- @tparam DatabaseQuery query The query object
-- @tparam[opt=false] bool redraw Whether or not to redraw the scrolling table
-- @treturn QueryScrollingTable The query scrolling table object
function QueryScrollingTable.SetQuery(self, query, redraw)
if query == self._query and not redraw then
return self
end
if self._query then
self._query:SetUpdateCallback()
end
self._query = query
self._query:SetUpdateCallback(private.QueryUpdateCallback, self)
self:_UpdateSortFromQuery()
self:_ForceLastDataUpdate()
self:UpdateData(redraw)
return self
end
--- Sets whether or not the @{DatabaseQuery} is automatically released.
-- @tparam QueryScrollingTable self The query scrolling table object
-- @tparam bool autoRelease Whether or not to auto-release the query
-- @treturn QueryScrollingTable The query scrolling table object
function QueryScrollingTable.SetAutoReleaseQuery(self, autoRelease)
self._autoReleaseQuery = autoRelease
return self
end
--- Sets the selected record.
-- @tparam QueryScrollingTable self The query scrolling table object
-- @param selection The selected record or nil to clear the selection
-- @tparam[opt=false] bool redraw Whether or not to redraw the scrolling table
-- @treturn QueryScrollingTable The query scrolling table object
function QueryScrollingTable.SetSelection(self, selection, redraw)
if selection == self._selection then
return self
elseif selection and self._selectionValidator and not self:_selectionValidator(self._query:GetResultRowByUUID(selection)) then
return self
end
local index = nil
if selection then
index = Table.KeyByValue(self._data, selection)
assert(index)
end
self:_IgnoreLastDataUpdate()
self._selection = selection
if selection then
-- set the scroll so that the selection is visible if necessary
local rowHeight = self._rowHeight
local firstVisibleIndex = ceil(self._vScrollValue / rowHeight) + 1
local lastVisibleIndex = floor((self._vScrollValue + self:_GetDimension("HEIGHT")) / rowHeight)
if lastVisibleIndex > firstVisibleIndex and (index < firstVisibleIndex or index > lastVisibleIndex) then
self:_OnScrollValueChanged(min((index - 1) * rowHeight, self:_GetMaxScroll()))
end
end
for _, row in ipairs(self._rows) do
if not row:IsMouseOver() and row:IsVisible() and row:GetData() ~= selection then
row:SetHighlightState(nil)
elseif row:IsMouseOver() and row:IsVisible() then
row:SetHighlightState(row:GetData() == selection and "selectedHover" or "hover")
elseif row:IsVisible() and row:GetData() == selection then
row:SetHighlightState("selected")
end
end
if self._onSelectionChangedHandler then
self:_onSelectionChangedHandler()
end
if redraw then
self:Draw()
end
return self
end
--- Gets the currently selected row.
-- @tparam QueryScrollingTable self The scrolling table object
-- @return The selected row or nil if there's nothing selected
function QueryScrollingTable.GetSelection(self)
return self._selection and self._query:GetResultRowByUUID(self._selection) or nil
end
--- Registers a script handler.
-- @tparam QueryScrollingTable self The scrolling table object
-- @tparam string script The script to register for (supported scripts: `OnDataUpdated`, `OnSelectionChanged`, `OnRowClick`)
-- @tparam function handler The script handler which will be called with the scrolling table object followed by any
-- arguments to the script
-- @treturn QueryScrollingTable The scrolling table object
function QueryScrollingTable.SetScript(self, script, handler)
if script == "OnDataUpdated" then
self._onDataUpdated = handler
else
self.__super:SetScript(script, handler)
end
return self
end
function QueryScrollingTable.Draw(self)
self._query:SetUpdatesPaused(true)
if self._lastDataUpdate == nil then
self:_IgnoreLastDataUpdate()
end
self.__super:Draw()
self._header:SetSort(self._sortCol, self._sortAscending)
self._query:SetUpdatesPaused(false)
end
-- ============================================================================
-- Private Class Methods
-- ============================================================================
function QueryScrollingTable._CreateScrollingTableInfo(self)
return TSM.UI.Util.QueryScrollingTableInfo()
end
function QueryScrollingTable._UpdateSortFromQuery(self)
if self._tableInfo:_IsSortEnabled() then
local sortField, sortAscending = self._query:GetLastOrderBy()
if sortField then
self._sortCol = self._tableInfo:_GetIdBySortField(sortField)
self._sortAscending = sortAscending
else
self._sortCol = nil
self._sortAscending = nil
end
end
end
function QueryScrollingTable._UpdateData(self)
-- we need to fix up the data within the rows updated to avoid errors with trying to access old DatabaseQueryResultRows
local prevRowIndex = TempTable.Acquire()
local newRowData = TempTable.Acquire()
for i, row in ipairs(self._rows) do
if row:IsVisible() then
prevRowIndex[row:GetData()] = i
end
end
local prevSelection = self._selection
wipe(self._data)
self._selection = nil
for _, uuid in self._query:UUIDIterator() do
if uuid == prevSelection then
self._selection = uuid
end
if prevRowIndex[uuid] then
newRowData[prevRowIndex[uuid]] = uuid
end
tinsert(self._data, uuid)
end
for i, row in ipairs(self._rows) do
if row:IsVisible() then
if newRowData[i] then
row:SetData(newRowData[i])
else
row:ClearData()
end
end
end
TempTable.Release(prevRowIndex)
TempTable.Release(newRowData)
if prevSelection and not self._selection then
-- select the first row since we weren't able to find the previously-selected row
self:SetSelection(self._data[1])
end
if self._onDataUpdated then
self:_onDataUpdated()
end
end
function QueryScrollingTable._ToggleSort(self, id)
local sortField = self._tableInfo:_GetSortFieldById(id)
if not self._sortCol or not self._query or not sortField then
-- sorting disabled so ignore
return
end
if id == self._sortCol then
self._sortAscending = not self._sortAscending
else
self._sortCol = id
self._sortAscending = true
end
self._query:UpdateLastOrderBy(sortField, self._sortAscending)
self:_UpdateData()
self:Draw()
end
function QueryScrollingTable._HandleRowClick(self, uuid, mouseButton)
if self._onRowClickHandler then
self:_onRowClickHandler(self._query:GetResultRowByUUID(uuid), mouseButton)
end
end
-- ============================================================================
-- Private Helper Functions
-- ============================================================================
function private.QueryUpdateCallback(_, uuid, self)
self:_SetLastDataUpdate(uuid)
if not uuid then
self:_UpdateData()
end
self:Draw()
end