1477 lines
48 KiB
Lua
1477 lines
48 KiB
Lua
|
-- ------------------------------------------------------------------------------ --
|
||
|
-- TradeSkillMaster --
|
||
|
-- https://tradeskillmaster.com --
|
||
|
-- All Rights Reserved - Detailed license information included with addon. --
|
||
|
-- ------------------------------------------------------------------------------ --
|
||
|
|
||
|
local _, TSM = ...
|
||
|
local L = TSM.Include("Locale").GetTable()
|
||
|
local TableRow = TSM.Include("LibTSMClass").DefineClass("TableRow")
|
||
|
local Table = TSM.Include("Util.Table")
|
||
|
local Math = TSM.Include("Util.Math")
|
||
|
local Wow = TSM.Include("Util.Wow")
|
||
|
local Theme = TSM.Include("Util.Theme")
|
||
|
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
|
||
|
local ItemInfo = TSM.Include("Service.ItemInfo")
|
||
|
local Tooltip = TSM.Include("UI.Tooltip")
|
||
|
TSM.UI.Util.TableRow = TableRow
|
||
|
local private = {
|
||
|
rowFrameLookup = {},
|
||
|
layoutTemp = {},
|
||
|
colIdsTemp = {},
|
||
|
}
|
||
|
local FLAG_WIDTH = 6
|
||
|
local FLAG_SPACING = 2
|
||
|
local ICON_SPACING = 4
|
||
|
local MIN_TEXT_WIDTH = 12
|
||
|
local RESIZER_WIDTH = 4
|
||
|
local INDENT_WIDTH = 8
|
||
|
local HEADER_LINE_WIDTH = 2
|
||
|
local MORE_COL_WIDTH = 8
|
||
|
local FULL_TEXT_TOOLTIP_DELAY_S = 1
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- TableRow - Public Class Methods
|
||
|
-- ============================================================================
|
||
|
|
||
|
function TableRow.__init(self)
|
||
|
self._scrollingTable = nil
|
||
|
self._tableInfo = nil
|
||
|
self._rowData = nil
|
||
|
self._texts = {}
|
||
|
self._icons = {}
|
||
|
self._rotatingIcons = {}
|
||
|
self._buttons = {}
|
||
|
self._recycled = {
|
||
|
buttons = {},
|
||
|
texts = {},
|
||
|
icons = {},
|
||
|
rotatingIcons = {},
|
||
|
}
|
||
|
self._sortId = nil
|
||
|
self._sortAscending = true
|
||
|
self._state = nil
|
||
|
|
||
|
local frame = CreateFrame("Button", nil, nil, nil)
|
||
|
frame:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
|
self._frame = frame
|
||
|
private.rowFrameLookup[frame] = self
|
||
|
|
||
|
frame.background = frame:CreateTexture(nil, "BACKGROUND")
|
||
|
frame.background:SetAllPoints()
|
||
|
|
||
|
frame.highlight = frame:CreateTexture(nil, "ARTWORK", -1)
|
||
|
frame.highlight:SetAllPoints()
|
||
|
frame.highlight:Hide()
|
||
|
|
||
|
frame.sortBackground = frame:CreateTexture(nil, "ARTWORK", -2)
|
||
|
frame.sortBackground:Hide()
|
||
|
|
||
|
frame.sortFlag = frame:CreateTexture(nil, "ARTWORK", -1)
|
||
|
frame.sortFlag:SetHeight(3)
|
||
|
frame.sortFlag:Hide()
|
||
|
end
|
||
|
|
||
|
function TableRow.Acquire(self, scrollingTable, isHeader)
|
||
|
self._scrollingTable = scrollingTable
|
||
|
self._tableInfo = self._scrollingTable._tableInfo
|
||
|
|
||
|
self._frame:SetParent(isHeader and self._scrollingTable._hContent or self._scrollingTable._content)
|
||
|
self._frame:SetHitRectInsets(0, 0, 0, 0)
|
||
|
self._frame:Show()
|
||
|
self._frame.highlight:Hide()
|
||
|
self._frame.sortBackground:Hide()
|
||
|
self._frame.sortFlag:Hide()
|
||
|
|
||
|
if isHeader then
|
||
|
self:_CreateHeaderRowCols()
|
||
|
self._frame:SetPoint("TOPLEFT", 0, -HEADER_LINE_WIDTH)
|
||
|
self._frame:SetPoint("TOPRIGHT", 0, -HEADER_LINE_WIDTH)
|
||
|
self:_LayoutHeaderRow()
|
||
|
else
|
||
|
self:_CreateDataRowCols()
|
||
|
ScriptWrapper.Set(self._frame, "OnEnter", private.RowOnEnter, self)
|
||
|
ScriptWrapper.Set(self._frame, "OnLeave", private.RowOnLeave, self)
|
||
|
ScriptWrapper.Set(self._frame, "OnClick", private.RowOnClick, self)
|
||
|
if scrollingTable._rightClickToggle then
|
||
|
ScriptWrapper.Set(self._frame, "OnMouseDown", private.RowOnMouseDown, self)
|
||
|
else
|
||
|
ScriptWrapper.Clear(self._frame, "OnMouseDown")
|
||
|
end
|
||
|
self:_LayoutDataRow()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow.Release(self)
|
||
|
self._frame:Hide()
|
||
|
for _, text in pairs(self._texts) do
|
||
|
text:Hide()
|
||
|
text:ClearAllPoints()
|
||
|
text:SetWidth(0)
|
||
|
text:SetHeight(0)
|
||
|
text:SetTextColor(1, 1, 1, 1)
|
||
|
tinsert(self._recycled.texts, text)
|
||
|
end
|
||
|
wipe(self._texts)
|
||
|
for _, icon in pairs(self._icons) do
|
||
|
icon:Hide()
|
||
|
icon:SetDrawLayer("ARTWORK", 0)
|
||
|
icon:SetTexture(nil)
|
||
|
icon:SetTexCoord(0, 0, 0, 1, 1, 0, 1, 1)
|
||
|
icon:SetColorTexture(0, 0, 0, 0)
|
||
|
icon:SetVertexColor(1, 1, 1, 1)
|
||
|
icon:ClearAllPoints()
|
||
|
icon:SetWidth(0)
|
||
|
icon:SetHeight(0)
|
||
|
tinsert(self._recycled.icons, icon)
|
||
|
end
|
||
|
wipe(self._icons)
|
||
|
for _, icon in pairs(self._rotatingIcons) do
|
||
|
icon.ag:Stop()
|
||
|
icon:Hide()
|
||
|
icon:SetDrawLayer("ARTWORK", 0)
|
||
|
icon:SetTexture(nil)
|
||
|
icon:SetTexCoord(0, 0, 0, 1, 1, 0, 1, 1)
|
||
|
icon:SetColorTexture(0, 0, 0, 0)
|
||
|
icon:SetVertexColor(1, 1, 1, 1)
|
||
|
icon:ClearAllPoints()
|
||
|
icon:SetWidth(0)
|
||
|
icon:SetHeight(0)
|
||
|
tinsert(self._recycled.rotatingIcons, icon)
|
||
|
end
|
||
|
wipe(self._rotatingIcons)
|
||
|
for _, button in pairs(self._buttons) do
|
||
|
if button.isShowingTooltip then
|
||
|
Tooltip.Hide()
|
||
|
button.isShowingTooltip = nil
|
||
|
end
|
||
|
button:Hide()
|
||
|
button:SetMouseClickEnabled(true)
|
||
|
button:RegisterForDrag(nil)
|
||
|
button:SetResizable(false)
|
||
|
button:SetMovable(false)
|
||
|
ScriptWrapper.Clear(button, "OnEnter")
|
||
|
ScriptWrapper.Clear(button, "OnLeave")
|
||
|
ScriptWrapper.Clear(button, "OnClick")
|
||
|
ScriptWrapper.Clear(button, "OnMouseDown")
|
||
|
ScriptWrapper.Clear(button, "OnMouseUp")
|
||
|
ScriptWrapper.Clear(button, "OnUpdate")
|
||
|
button:SetParent(nil)
|
||
|
button:ClearAllPoints()
|
||
|
button:SetWidth(0)
|
||
|
button:SetHeight(0)
|
||
|
tinsert(self._recycled.buttons, button)
|
||
|
end
|
||
|
wipe(self._buttons)
|
||
|
|
||
|
self._scrollingTable = nil
|
||
|
self._tableInfo = nil
|
||
|
self._rowData = nil
|
||
|
self._state = nil
|
||
|
self._frame:SetParent(nil)
|
||
|
self._frame:ClearAllPoints()
|
||
|
ScriptWrapper.Clear(self._frame, "OnEnter")
|
||
|
ScriptWrapper.Clear(self._frame, "OnLeave")
|
||
|
ScriptWrapper.Clear(self._frame, "OnClick")
|
||
|
end
|
||
|
|
||
|
function TableRow.SetData(self, data)
|
||
|
for _, col in self._tableInfo:_ColIterator() do
|
||
|
local id = col:_GetId()
|
||
|
self._texts[id]:SetText(col:_GetText(data))
|
||
|
if col:_GetIconSize() then
|
||
|
local button = self._buttons["_icon_"..id]
|
||
|
local texture = col:_GetIcon(data, button and button:IsMouseOver())
|
||
|
if type(texture) == "string" and TSM.UI.TexturePacks.IsValid(texture) then
|
||
|
TSM.UI.TexturePacks.SetTexture(self._icons[id], texture)
|
||
|
else
|
||
|
self._icons[id]:SetTexture(texture)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
self._rowData = data
|
||
|
self:_LayoutDataRow()
|
||
|
end
|
||
|
|
||
|
function TableRow.SetHeaderData(self)
|
||
|
if self._scrollingTable._headerHidden then
|
||
|
return
|
||
|
end
|
||
|
for _, col in self._tableInfo:_ColIterator() do
|
||
|
if not col:_GetTitleIcon() then
|
||
|
self._texts[col:_GetId()]:SetText(col:_GetTitle())
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow.GetData(self)
|
||
|
return self._rowData
|
||
|
end
|
||
|
|
||
|
function TableRow.ClearData(self)
|
||
|
self._rowData = nil
|
||
|
end
|
||
|
|
||
|
function TableRow.SetHeight(self, height)
|
||
|
for _, text in pairs(self._texts) do
|
||
|
text:SetHeight(height)
|
||
|
end
|
||
|
for _, btn in pairs(self._buttons) do
|
||
|
btn:SetHeight(height)
|
||
|
end
|
||
|
for _, col in ipairs(self._tableInfo:_GetCols()) do
|
||
|
local id = col:_GetId()
|
||
|
local flag = self._icons["_flag_"..id]
|
||
|
if flag then
|
||
|
flag:SetHeight(height - FLAG_SPACING * 2)
|
||
|
end
|
||
|
end
|
||
|
self._frame:SetHeight(height)
|
||
|
end
|
||
|
|
||
|
function TableRow.SetBackgroundColor(self, color)
|
||
|
self._frame.background:SetColorTexture(color:GetFractionalRGBA())
|
||
|
end
|
||
|
|
||
|
function TableRow.SetTextColor(self, color)
|
||
|
for _, col in ipairs(self._tableInfo:_GetCols()) do
|
||
|
local id = col:_GetId()
|
||
|
local text = self._texts[id]
|
||
|
if text then
|
||
|
text:SetTextColor(color:GetFractionalRGBA())
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow.SetVisible(self, visible)
|
||
|
if visible == self._frame:IsVisible() then
|
||
|
return
|
||
|
end
|
||
|
if visible then
|
||
|
self._frame:Show()
|
||
|
self._frame.highlight:Hide()
|
||
|
else
|
||
|
self._frame:Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow.IsVisible(self)
|
||
|
return self._frame:IsVisible()
|
||
|
end
|
||
|
|
||
|
function TableRow.SetHighlightState(self, state, noLayout)
|
||
|
self._state = state
|
||
|
local highlightTint, shouldLayoutActionIcons = nil, false
|
||
|
if state == "selectedHover" then
|
||
|
highlightTint = "+SELECTED_HOVER"
|
||
|
elseif state == "selected" then
|
||
|
highlightTint = "+SELECTED"
|
||
|
elseif state == "hover" then
|
||
|
highlightTint = self._scrollingTable._rowHoverEnabled and "+HOVER" or nil
|
||
|
shouldLayoutActionIcons = true
|
||
|
elseif state == nil then
|
||
|
shouldLayoutActionIcons = true
|
||
|
else
|
||
|
error("Invalid state: "..state)
|
||
|
end
|
||
|
if highlightTint then
|
||
|
local backgroundColor = self._scrollingTable._backgroundColor
|
||
|
self._frame.highlight:SetColorTexture(Theme.GetColor(backgroundColor):GetTint(highlightTint):GetFractionalRGBA())
|
||
|
self._frame.highlight:Show()
|
||
|
else
|
||
|
self._frame.highlight:Hide()
|
||
|
end
|
||
|
if not noLayout then
|
||
|
local shouldLayout = false
|
||
|
for _, col in self._tableInfo:_VisibleColIterator() do
|
||
|
if col:_HasFlag() or (shouldLayoutActionIcons and select(3, col:_GetActionIconInfo())) then
|
||
|
shouldLayout = true
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
if shouldLayout then
|
||
|
self:_LayoutDataRow()
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow.IsMouseOver(self)
|
||
|
return self._frame:IsMouseOver()
|
||
|
end
|
||
|
|
||
|
function TableRow.SetHitRectInsets(self, left, right, top, bottom)
|
||
|
for _, tooltipFrame in pairs(self._buttons) do
|
||
|
tooltipFrame:SetHitRectInsets(left, right, top, bottom)
|
||
|
end
|
||
|
self._frame:SetHitRectInsets(left, right, top, bottom)
|
||
|
end
|
||
|
|
||
|
function TableRow.SetSort(self, sortId, sortAscending)
|
||
|
if sortId == self._sortId and sortAscending == self._sortAscending then
|
||
|
return
|
||
|
end
|
||
|
self._sortId = sortId
|
||
|
self._sortAscending = sortAscending
|
||
|
self:_LayoutHeaderRow()
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- TableRow - Private Class Methods
|
||
|
-- ============================================================================
|
||
|
|
||
|
function TableRow._GetFontString(self)
|
||
|
local fontString = tremove(self._recycled.texts)
|
||
|
if not fontString then
|
||
|
fontString = self._frame:CreateFontString()
|
||
|
fontString:SetShadowColor(0, 0, 0, 0)
|
||
|
fontString:SetWordWrap(false)
|
||
|
end
|
||
|
fontString:Show()
|
||
|
return fontString
|
||
|
end
|
||
|
|
||
|
function TableRow._GetTexture(self)
|
||
|
local texture = tremove(self._recycled.icons)
|
||
|
if not texture then
|
||
|
texture = self._frame:CreateTexture()
|
||
|
end
|
||
|
texture:Show()
|
||
|
return texture
|
||
|
end
|
||
|
|
||
|
function TableRow._GetRotatingTexture(self)
|
||
|
local texture = tremove(self._recycled.rotatingIcons)
|
||
|
if not texture then
|
||
|
texture = self._frame:CreateTexture()
|
||
|
texture.ag = texture:CreateAnimationGroup()
|
||
|
local spin = texture.ag:CreateAnimation("Rotation")
|
||
|
spin:SetDuration(2)
|
||
|
spin:SetDegrees(360)
|
||
|
texture.ag:SetLooping("REPEAT")
|
||
|
end
|
||
|
texture:Show()
|
||
|
return texture
|
||
|
end
|
||
|
|
||
|
function TableRow._GetButton(self)
|
||
|
local button = tremove(self._recycled.buttons)
|
||
|
if not button then
|
||
|
button = CreateFrame("Button", nil, self._frame, nil)
|
||
|
end
|
||
|
button:SetParent(self._frame)
|
||
|
button:SetHitRectInsets(0, 0, 0, 0)
|
||
|
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
|
button:Show()
|
||
|
return button
|
||
|
end
|
||
|
|
||
|
function TableRow._GetSepTexture(self)
|
||
|
local sepTexture = self:_GetTexture()
|
||
|
sepTexture:SetDrawLayer("BORDER")
|
||
|
sepTexture:SetWidth(HEADER_LINE_WIDTH)
|
||
|
return sepTexture
|
||
|
end
|
||
|
|
||
|
function TableRow._CreateHeaderRowCols(self)
|
||
|
if self._scrollingTable._headerHidden then
|
||
|
return
|
||
|
end
|
||
|
if self._scrollingTable:_CanResizeCols() then
|
||
|
-- craete the "more" column
|
||
|
local button = self:_GetButton()
|
||
|
ScriptWrapper.Set(button, "OnClick", private.MoreColOnClick, self)
|
||
|
self._buttons._more = button
|
||
|
local moreIcon = self:_GetTexture()
|
||
|
moreIcon:SetDrawLayer("ARTWORK")
|
||
|
TSM.UI.TexturePacks.SetTextureAndSize(moreIcon, "iconPack.12x12/More/Vertical")
|
||
|
self._icons._more = moreIcon
|
||
|
self._icons._sep__more = self:_GetSepTexture()
|
||
|
end
|
||
|
|
||
|
for _, col in self._tableInfo:_ColIterator() do
|
||
|
local id = col:_GetId()
|
||
|
local button = self:_GetButton()
|
||
|
ScriptWrapper.Set(button, "OnClick", private.HeaderColOnClick)
|
||
|
ScriptWrapper.Set(button, "OnEnter", private.HeaderColOnEnter)
|
||
|
ScriptWrapper.Set(button, "OnLeave", private.HeaderColOnLeave)
|
||
|
button:SetResizable(true)
|
||
|
self._buttons[id] = button
|
||
|
if self._scrollingTable:_CanResizeCols() then
|
||
|
local resizerButton = self:_GetButton()
|
||
|
resizerButton:SetMovable(true)
|
||
|
ScriptWrapper.Set(resizerButton, "OnEnter", private.ResizerOnEnter)
|
||
|
ScriptWrapper.Set(resizerButton, "OnLeave", private.ResizerOnLeave)
|
||
|
ScriptWrapper.Set(resizerButton, "OnMouseDown", private.ResizerOnMouseDown)
|
||
|
ScriptWrapper.Set(resizerButton, "OnMouseUp", private.ResizerOnMouseUp)
|
||
|
ScriptWrapper.Set(resizerButton, "OnClick", private.ResizerOnClick)
|
||
|
self._buttons["_resizer_"..id] = resizerButton
|
||
|
local resizerHighlight = self:_GetTexture()
|
||
|
resizerHighlight:SetDrawLayer("ARTWORK")
|
||
|
resizerHighlight:SetPoint("TOPLEFT", resizerButton)
|
||
|
resizerHighlight:SetPoint("BOTTOMRIGHT", resizerButton)
|
||
|
resizerHighlight:SetColorTexture(Theme.GetColor("ACTIVE_BG+HOVER"):GetFractionalRGBA())
|
||
|
resizerHighlight:Hide()
|
||
|
self._icons["_resizer_"..id] = resizerHighlight
|
||
|
end
|
||
|
self._icons["_sep_"..id] = self:_GetSepTexture()
|
||
|
local iconTexture = col:_GetTitleIcon()
|
||
|
if iconTexture then
|
||
|
local icon = self:_GetTexture()
|
||
|
icon:SetDrawLayer("ARTWORK", 1)
|
||
|
TSM.UI.TexturePacks.SetTextureAndSize(icon, iconTexture)
|
||
|
self._icons[id] = icon
|
||
|
else
|
||
|
local text = self:_GetFontString()
|
||
|
text:SetFont(Theme.GetFont("BODY_BODY3_MEDIUM"):GetWowFont())
|
||
|
text:SetJustifyH("LEFT")
|
||
|
text:SetText(col:_GetTitle())
|
||
|
self._texts[id] = text
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow._CreateDataRowCols(self)
|
||
|
for _, col in self._tableInfo:_ColIterator() do
|
||
|
local id = col:_GetId()
|
||
|
local iconSize = col:_GetIconSize()
|
||
|
if iconSize then
|
||
|
local icon = self:_GetTexture()
|
||
|
icon:SetDrawLayer("ARTWORK", 1)
|
||
|
icon:SetWidth(iconSize)
|
||
|
icon:SetHeight(iconSize)
|
||
|
self._icons[id] = icon
|
||
|
|
||
|
if col:_IsIconHoverEnabled() then
|
||
|
local iconBtn = self:_GetButton()
|
||
|
iconBtn:SetAllPoints(icon)
|
||
|
ScriptWrapper.Set(iconBtn, "OnEnter", private.IconButtonOnEnter)
|
||
|
ScriptWrapper.Set(iconBtn, "OnLeave", private.IconButtonOnLeave)
|
||
|
ScriptWrapper.Set(iconBtn, "OnClick", private.IconButtonOnClick)
|
||
|
self._buttons["_icon_"..id] = iconBtn
|
||
|
end
|
||
|
end
|
||
|
-- need to create a text element even if there's no text, as it's used for the layout
|
||
|
local text = self:_GetFontString()
|
||
|
if col:_HasText() then
|
||
|
text:SetFont(col:_GetWowFont())
|
||
|
text:SetJustifyH(col:_GetJustifyH())
|
||
|
else
|
||
|
-- use an arbitrary default font since the text will be an empty string
|
||
|
text:SetFontObject(GameFontNormal)
|
||
|
end
|
||
|
self._texts[id] = text
|
||
|
if col:_HasTooltip() then
|
||
|
local tooltipFrame = self:_GetButton()
|
||
|
ScriptWrapper.Set(tooltipFrame, "OnEnter", private.TooltipFrameOnEnter)
|
||
|
ScriptWrapper.Set(tooltipFrame, "OnLeave", private.TooltipFrameOnLeave)
|
||
|
ScriptWrapper.Set(tooltipFrame, "OnClick", private.TooltipFrameOnClick)
|
||
|
if self._scrollingTable._rightClickToggle then
|
||
|
ScriptWrapper.Set(tooltipFrame, "OnMouseDown", private.RowOnMouseDown, self)
|
||
|
end
|
||
|
self._buttons[id] = tooltipFrame
|
||
|
end
|
||
|
if col:_HasFlag() then
|
||
|
-- add the flag texture
|
||
|
local flag = self:_GetTexture()
|
||
|
flag:SetDrawLayer("ARTWORK", 1)
|
||
|
flag:SetWidth(FLAG_WIDTH)
|
||
|
self._icons["_flag_"..id] = flag
|
||
|
end
|
||
|
if col:_HasExpander() then
|
||
|
-- add the expander texture
|
||
|
local expander = self:_GetTexture()
|
||
|
expander:SetDrawLayer("ARTWORK", 1)
|
||
|
self._icons["_expander_"..id] = expander
|
||
|
|
||
|
local expanderBtn = self:_GetButton()
|
||
|
expanderBtn:SetAllPoints(expander)
|
||
|
ScriptWrapper.SetPropagate(expanderBtn, "OnEnter")
|
||
|
ScriptWrapper.Set(expanderBtn, "OnLeave", private.ExpanderOnLeave, self)
|
||
|
ScriptWrapper.Set(expanderBtn, "OnClick", private.ExpanderOnClick, self)
|
||
|
self._buttons["_expander_"..id] = expanderBtn
|
||
|
end
|
||
|
if col:_HasCheck() then
|
||
|
-- add the check texture
|
||
|
local expander = self:_GetTexture()
|
||
|
expander:SetDrawLayer("ARTWORK", 1)
|
||
|
TSM.UI.TexturePacks.SetTextureAndSize(expander, "iconPack.14x14/Checkmark/Default")
|
||
|
self._icons["_check_"..id] = expander
|
||
|
end
|
||
|
if col:_HasBadge() then
|
||
|
local badgeText = self:_GetFontString()
|
||
|
badgeText:SetFont(Theme.GetFont("TABLE_TABLE1"):GetWowFont())
|
||
|
badgeText:SetTextColor(Theme.GetColor("INDICATOR"):GetFractionalRGBA())
|
||
|
badgeText:SetJustifyH("RIGHT")
|
||
|
badgeText:SetJustifyV("MIDDLE")
|
||
|
self._texts["_badge_"..id] = badgeText
|
||
|
end
|
||
|
-- add the action icons
|
||
|
local numActionIcons, actionIconSize = col:_GetActionIconInfo()
|
||
|
for i = 1, numActionIcons do
|
||
|
local icon = self:_GetRotatingTexture()
|
||
|
icon:SetDrawLayer("ARTWORK", 1)
|
||
|
icon:SetWidth(actionIconSize)
|
||
|
icon:SetHeight(actionIconSize)
|
||
|
self._rotatingIcons["_action"..i.."_"..id] = icon
|
||
|
|
||
|
local iconBtn = self:_GetButton()
|
||
|
iconBtn:SetAllPoints(icon)
|
||
|
ScriptWrapper.Set(iconBtn, "OnEnter", private.ActionIconButtonOnEnter)
|
||
|
ScriptWrapper.Set(iconBtn, "OnLeave", private.ActionIconButtonOnLeave)
|
||
|
ScriptWrapper.Set(iconBtn, "OnClick", private.ActionIconButtonOnClick)
|
||
|
self._buttons["_action"..i.."_"..id] = iconBtn
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow._LayoutHeaderRow(self)
|
||
|
if self._scrollingTable._headerHidden then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
-- hide any hidden cols
|
||
|
for _, col in self._tableInfo:_HiddenColIterator() do
|
||
|
local id = col:_GetId()
|
||
|
local button = self._buttons[id]
|
||
|
button:Hide()
|
||
|
local sepIcon = self._icons["_sep_"..id]
|
||
|
sepIcon:Hide()
|
||
|
|
||
|
if self._scrollingTable:_CanResizeCols() then
|
||
|
local resizerButton = self._buttons["_resizer_"..id]
|
||
|
resizerButton:Hide()
|
||
|
end
|
||
|
|
||
|
local iconTexture = col:_GetTitleIcon()
|
||
|
if iconTexture then
|
||
|
self._icons[id]:Hide()
|
||
|
else
|
||
|
self._texts[id]:Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local cols = self._tableInfo:_GetVisibleCols()
|
||
|
|
||
|
if self._scrollingTable:_CanResizeCols() then
|
||
|
-- layout the "more" column
|
||
|
local button = self._buttons._more
|
||
|
button:SetPoint("LEFT", Theme.GetColSpacing() / 2, 0)
|
||
|
button:SetWidth(MORE_COL_WIDTH)
|
||
|
local icon = self._icons._more
|
||
|
icon:SetPoint("CENTER", button)
|
||
|
local sepIcon = self._icons._sep__more
|
||
|
sepIcon:SetPoint("TOP", button, "TOPRIGHT", Theme.GetColSpacing() / 2, 0)
|
||
|
sepIcon:SetPoint("BOTTOM", button, "BOTTOMRIGHT", Theme.GetColSpacing() / 2, 0)
|
||
|
sepIcon:SetColorTexture(Theme.GetColor("ACTIVE_BG"):GetFractionalRGBA())
|
||
|
end
|
||
|
|
||
|
-- build buttons from the left until we get to the col without a width, then switch to building from the right
|
||
|
for i, col, isAscending in Table.InwardIterator(cols) do
|
||
|
local id = col:_GetId()
|
||
|
local button = self._buttons[id]
|
||
|
local leftButton = i > 1 and self._buttons[cols[i - 1]:_GetId()] or (self._scrollingTable:_CanResizeCols() and self._buttons._more) or nil
|
||
|
local rightButton = i < #cols and self._buttons[cols[i + 1]:_GetId()] or nil
|
||
|
button:Show()
|
||
|
button:ClearAllPoints()
|
||
|
|
||
|
if self._scrollingTable:_CanResizeCols() then
|
||
|
local resizerBtn = self._buttons["_resizer_"..id]
|
||
|
if self._scrollingTable:_IsColWidthLocked() then
|
||
|
resizerBtn:Disable()
|
||
|
resizerBtn:SetMovable(false)
|
||
|
resizerBtn:SetMouseClickEnabled(false)
|
||
|
else
|
||
|
resizerBtn:Enable()
|
||
|
resizerBtn:SetMovable(true)
|
||
|
resizerBtn:SetMouseClickEnabled(true)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local sepIcon = self._icons["_sep_"..id]
|
||
|
sepIcon:Show()
|
||
|
sepIcon:SetColorTexture(Theme.GetColor("ACTIVE_BG"):GetFractionalRGBA())
|
||
|
sepIcon:SetPoint("TOP", button, "TOPRIGHT", Theme.GetColSpacing() / 2, 0)
|
||
|
sepIcon:SetPoint("BOTTOM", button, "BOTTOMRIGHT", Theme.GetColSpacing() / 2, 0)
|
||
|
|
||
|
-- layout the button
|
||
|
if isAscending then
|
||
|
if leftButton then
|
||
|
button:SetPoint("LEFT", leftButton, "RIGHT", Theme.GetColSpacing(), 0)
|
||
|
else
|
||
|
button:SetPoint("LEFT", Theme.GetColSpacing() / 2, 0)
|
||
|
end
|
||
|
else
|
||
|
if rightButton then
|
||
|
button:SetPoint("RIGHT", rightButton, "LEFT", -Theme.GetColSpacing(), 0)
|
||
|
else
|
||
|
button:SetPoint("RIGHT", -Theme.GetColSpacing() / 2, 0)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if self._scrollingTable:_CanResizeCols() then
|
||
|
local iconSize = col:_GetIconSize()
|
||
|
local iconTexture = col:_GetTitleIcon()
|
||
|
button:SetWidth(self._scrollingTable:_GetColWidth(id))
|
||
|
|
||
|
-- the minimum width of the content is our minimum text width plus the size of the content icon
|
||
|
local minContentWidth = 0
|
||
|
if col:_HasText() then
|
||
|
minContentWidth = minContentWidth + MIN_TEXT_WIDTH
|
||
|
end
|
||
|
if iconSize then
|
||
|
minContentWidth = minContentWidth + iconSize + ICON_SPACING
|
||
|
end
|
||
|
if col:_HasFlag() then
|
||
|
minContentWidth = minContentWidth + FLAG_WIDTH
|
||
|
end
|
||
|
if col:_HasExpander() then
|
||
|
minContentWidth = minContentWidth + TSM.UI.TexturePacks.GetWidth("iconPack.12x12/Caret/Right") + ICON_SPACING
|
||
|
end
|
||
|
if col:_HasCheck() then
|
||
|
minContentWidth = minContentWidth + TSM.UI.TexturePacks.GetWidth("iconPack.14x14/Checkmark/Default") + ICON_SPACING
|
||
|
end
|
||
|
if col:_HasBadge() then
|
||
|
minContentWidth = minContentWidth + TSM.UI.TexturePacks.GetWidth("uiFrames.AuctionCounterTexture") + ICON_SPACING
|
||
|
end
|
||
|
-- the minimum header width is either our header icon width or the minimum text width
|
||
|
local minHeaderWidth = iconTexture and TSM.UI.TexturePacks.GetWidth(iconTexture) or MIN_TEXT_WIDTH
|
||
|
button:SetMinResize(max(minContentWidth, minHeaderWidth), 0)
|
||
|
|
||
|
-- layout the resizer button
|
||
|
local resizerButton = self._buttons["_resizer_"..id]
|
||
|
resizerButton:Show()
|
||
|
resizerButton:SetPoint("LEFT", button, "RIGHT", (Theme.GetColSpacing() - RESIZER_WIDTH) / 2, 0)
|
||
|
resizerButton:SetWidth(RESIZER_WIDTH)
|
||
|
resizerButton:SetHitRectInsets(-RESIZER_WIDTH / 2, -RESIZER_WIDTH / 2, 0, 0)
|
||
|
else
|
||
|
local width = col:_GetWidth()
|
||
|
if width then
|
||
|
-- don't currently support auto-width with a header
|
||
|
assert(width ~= true)
|
||
|
button:SetWidth(width)
|
||
|
else
|
||
|
-- we found the button which will expand to fill the extra width, so reverse the iterator direction (only once)
|
||
|
assert(isAscending)
|
||
|
Table.InwardIteratorReverse(cols)
|
||
|
if rightButton then
|
||
|
-- anchor the right of this button to the left of the next one
|
||
|
button:SetPoint("RIGHT", rightButton, "LEFT", -Theme.GetColSpacing(), 0)
|
||
|
else
|
||
|
-- this button is the last one, so anchor it to the right of our frame
|
||
|
button:SetPoint("RIGHT", -Theme.GetColSpacing() / 2, 0)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- update the text, icons, and sort icons
|
||
|
local sortBackground = self._frame.sortBackground
|
||
|
local sortFlag = self._frame.sortFlag
|
||
|
sortBackground:Hide()
|
||
|
sortBackground:ClearAllPoints()
|
||
|
sortFlag:Hide()
|
||
|
sortFlag:ClearAllPoints()
|
||
|
for _, col in ipairs(cols) do
|
||
|
local id = col:_GetId()
|
||
|
local button = self._buttons[id]
|
||
|
if self._sortId == id then
|
||
|
sortBackground:SetPoint("TOPLEFT", button, -Theme.GetColSpacing() / 2, 0)
|
||
|
sortBackground:SetPoint("BOTTOMRIGHT", button, Theme.GetColSpacing() / 2, 0)
|
||
|
sortBackground:SetColorTexture(Theme.GetColor("ACTIVE_BG"):GetFractionalRGBA())
|
||
|
sortBackground:Show()
|
||
|
sortFlag:SetPoint("TOPLEFT", button, -Theme.GetColSpacing() / 2, 2)
|
||
|
sortFlag:SetPoint("TOPRIGHT", button, Theme.GetColSpacing() / 2, 2)
|
||
|
sortFlag:SetColorTexture(Theme.GetColor(self._sortAscending and "INDICATOR" or "INDICATOR_ALT"):GetFractionalRGBA())
|
||
|
sortFlag:Show()
|
||
|
end
|
||
|
local iconTexture = col:_GetTitleIcon()
|
||
|
if iconTexture then
|
||
|
local icon = self._icons[id]
|
||
|
icon:Show()
|
||
|
icon:ClearAllPoints()
|
||
|
icon:SetPoint(col:_GetJustifyH(), button)
|
||
|
else
|
||
|
local text = self._texts[id]
|
||
|
text:Show()
|
||
|
text:ClearAllPoints()
|
||
|
text:SetAllPoints(button)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow._LayoutDataRow(self)
|
||
|
-- hide any hidden cols
|
||
|
for _, col in self._tableInfo:_HiddenColIterator() do
|
||
|
local id = col:_GetId()
|
||
|
local icon = self._icons[id]
|
||
|
|
||
|
local flag = self._icons["_flag_"..id]
|
||
|
if flag then
|
||
|
flag:Hide()
|
||
|
end
|
||
|
|
||
|
local expander = self._icons["_expander_"..id]
|
||
|
if expander then
|
||
|
expander:Hide()
|
||
|
local expanderButton = self._buttons["_expander_"..id]
|
||
|
expanderButton:Hide()
|
||
|
end
|
||
|
|
||
|
local check = self._icons["_check_"..id]
|
||
|
if check then
|
||
|
check:Hide()
|
||
|
end
|
||
|
|
||
|
if icon then
|
||
|
icon:Hide()
|
||
|
end
|
||
|
|
||
|
if col:_HasText() then
|
||
|
local text = self._texts[id]
|
||
|
text:Hide()
|
||
|
end
|
||
|
|
||
|
local badge = self._texts["_badge_"..id]
|
||
|
if badge then
|
||
|
badge:Hide()
|
||
|
end
|
||
|
|
||
|
local numActionIcons = col:_GetActionIconInfo()
|
||
|
for i = 1, numActionIcons do
|
||
|
local actionIconKey = "_action"..i.."_"..id
|
||
|
local actionIcon = self._rotatingIcons[actionIconKey]
|
||
|
local actionIconButton = self._buttons[actionIconKey]
|
||
|
actionIcon:Hide()
|
||
|
actionIconButton:Hide()
|
||
|
end
|
||
|
|
||
|
if col:_HasTooltip() then
|
||
|
local tooltipFrame = self._buttons[id]
|
||
|
tooltipFrame:Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local cols = self._tableInfo:_GetVisibleCols()
|
||
|
local canResize = self._scrollingTable:_CanResizeCols()
|
||
|
local data = self:GetData()
|
||
|
|
||
|
-- cache a list of the col ids
|
||
|
wipe(private.colIdsTemp)
|
||
|
for i, col in ipairs(cols) do
|
||
|
private.colIdsTemp[i] = col:_GetId()
|
||
|
end
|
||
|
|
||
|
-- build from the left until we get to the col without a width, then switch to building from the right
|
||
|
for i, col, isAscending in Table.InwardIterator(cols) do
|
||
|
local id = private.colIdsTemp[i]
|
||
|
local text = self._texts[id]
|
||
|
local flag = self._icons["_flag_"..id]
|
||
|
local expander = self._icons["_expander_"..id]
|
||
|
local check = self._icons["_check_"..id]
|
||
|
local badge = self._texts["_badge_"..id]
|
||
|
local icon = self._icons[id]
|
||
|
local width = canResize and self._scrollingTable:_GetColWidth(id) or col:_GetWidth()
|
||
|
local hasText = col:_HasText()
|
||
|
local textIndex = nil
|
||
|
local numActionIcons, actionIconSize, actionIconShowOnHover = col:_GetActionIconInfo()
|
||
|
local leftText = self:_GetDataLayoutRelativeFrame(i > 1 and private.colIdsTemp[i - 1], i > 1 and cols[i - 1], data, "LEFT")
|
||
|
local rightText = self:_GetDataLayoutRelativeFrame(i < #cols and private.colIdsTemp[i + 1], i < #cols and cols[i + 1], data, "RIGHT")
|
||
|
wipe(private.layoutTemp)
|
||
|
local extraWidth = 0
|
||
|
if not leftText and canResize then
|
||
|
extraWidth = MORE_COL_WIDTH + Theme.GetColSpacing()
|
||
|
private.LayoutTempInsertSpacing(MORE_COL_WIDTH + Theme.GetColSpacing())
|
||
|
end
|
||
|
|
||
|
if flag then
|
||
|
local visible, color = false, nil
|
||
|
if data then
|
||
|
visible, color = col:_GetFlagState(data, self:IsMouseOver())
|
||
|
end
|
||
|
if visible then
|
||
|
flag:Show()
|
||
|
flag:SetHeight(self._frame:GetHeight() - FLAG_SPACING * 2)
|
||
|
flag:SetColorTexture(color:GetFractionalRGBA())
|
||
|
private.LayoutTempInsertSpacing(-FLAG_SPACING)
|
||
|
private.LayoutTempInsertElementWithSpacing(flag, FLAG_SPACING)
|
||
|
else
|
||
|
flag:Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if expander then
|
||
|
expander:Show()
|
||
|
expander:ClearAllPoints()
|
||
|
local visible, expanded, indentLevel, indentWidth, expanderSpacing, largeCaretIcons = false, false, 0, nil, nil, false
|
||
|
if data then
|
||
|
visible, expanded, indentLevel, indentWidth, expanderSpacing, largeCaretIcons = col:_GetExpanderState(data)
|
||
|
end
|
||
|
expanderSpacing = expanderSpacing or ICON_SPACING
|
||
|
local expanderButton = self._buttons["_expander_"..id]
|
||
|
if indentWidth or indentLevel < 0 then
|
||
|
-- indent the expander itself
|
||
|
private.LayoutTempInsertSpacing(indentWidth or (abs(indentLevel) * INDENT_WIDTH))
|
||
|
end
|
||
|
local texture = expanded and (largeCaretIcons and "iconPack.14x14/Caret/Down" or "iconPack.12x12/Caret/Down") or (largeCaretIcons and "iconPack.14x14/Caret/Right" or "iconPack.12x12/Caret/Right")
|
||
|
local expanderWidth = TSM.UI.TexturePacks.GetWidth(texture)
|
||
|
-- check if there is only spacing before the expander and the expander can fit within the spacing
|
||
|
local firstLayoutElement = #private.layoutTemp == 1 and not leftText and private.layoutTemp[1] or nil
|
||
|
if type(firstLayoutElement) == "number" and Math.Round(expanderWidth + expanderSpacing) <= Math.Round(firstLayoutElement) then
|
||
|
private.layoutTemp[1] = private.layoutTemp[1] - expanderWidth - expanderSpacing
|
||
|
end
|
||
|
if visible then
|
||
|
TSM.UI.TexturePacks.SetTextureAndSize(expander, texture)
|
||
|
expander:Show()
|
||
|
expanderButton:Show()
|
||
|
private.LayoutTempInsertElementWithSpacing(expander, expanderSpacing)
|
||
|
else
|
||
|
expander:Hide()
|
||
|
ScriptWrapper.Clear(expanderButton, "OnLeave")
|
||
|
expanderButton:Hide()
|
||
|
ScriptWrapper.Set(expanderButton, "OnLeave", private.ExpanderOnLeave, self)
|
||
|
private.LayoutTempInsertSpacing(expanderWidth + expanderSpacing)
|
||
|
end
|
||
|
if not indentWidth and indentLevel > 0 then
|
||
|
-- indent the other elements after the expander
|
||
|
private.LayoutTempInsertSpacing(indentLevel * INDENT_WIDTH)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if check then
|
||
|
check:Show()
|
||
|
check:ClearAllPoints()
|
||
|
local visible = false
|
||
|
if data then
|
||
|
visible = col:_GetCheckState(data)
|
||
|
end
|
||
|
if visible then
|
||
|
local checkWidth = check:GetWidth()
|
||
|
-- check if there is only spacing before the check and the check can fit within the spacing
|
||
|
local firstLayoutElement = #private.layoutTemp == 1 and not leftText and private.layoutTemp[1] or nil
|
||
|
if type(firstLayoutElement) == "number" and Math.Round(checkWidth + ICON_SPACING) <= Math.Round(firstLayoutElement) then
|
||
|
private.layoutTemp[1] = private.layoutTemp[1] - checkWidth - ICON_SPACING
|
||
|
end
|
||
|
check:Show()
|
||
|
private.LayoutTempInsertElementWithSpacing(check, ICON_SPACING)
|
||
|
else
|
||
|
check:Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local iconTexture = icon and icon:GetTexture()
|
||
|
if iconTexture then
|
||
|
icon:Show()
|
||
|
icon:ClearAllPoints()
|
||
|
textIndex = #private.layoutTemp + 1
|
||
|
private.LayoutTempInsertElementWithSpacing(icon, ICON_SPACING)
|
||
|
end
|
||
|
|
||
|
if hasText then
|
||
|
text:Show()
|
||
|
text:ClearAllPoints()
|
||
|
textIndex = textIndex or #private.layoutTemp + 1
|
||
|
private.LayoutTempInsertElementWithSpacing(text, ICON_SPACING)
|
||
|
end
|
||
|
|
||
|
if badge then
|
||
|
badge:ClearAllPoints()
|
||
|
private.LayoutTempInsertElementWithSpacing(badge, ICON_SPACING)
|
||
|
local visible, value = false, nil
|
||
|
if data then
|
||
|
visible, value = col:_GetBadgeState(data)
|
||
|
end
|
||
|
if visible then
|
||
|
badge:SetText(value)
|
||
|
badge:Show()
|
||
|
else
|
||
|
badge:Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local hadVisibleRightActionIcon = false
|
||
|
for j = 1, numActionIcons do
|
||
|
local actionIconKey = "_action"..j.."_"..id
|
||
|
local actionIcon = self._rotatingIcons[actionIconKey]
|
||
|
local actionIconButton = self._buttons[actionIconKey]
|
||
|
actionIcon:ClearAllPoints()
|
||
|
actionIconButton:Show()
|
||
|
local visible, texture, isLeft = false, nil, false
|
||
|
if data and (not actionIconShowOnHover or self._state) then
|
||
|
local _, shouldRotate = nil, nil
|
||
|
visible, texture, isLeft, _, shouldRotate = col:_GetActionIcon(data, j, actionIconButton:IsMouseOver())
|
||
|
if shouldRotate then
|
||
|
actionIcon.ag:Play()
|
||
|
else
|
||
|
actionIcon.ag:Stop()
|
||
|
end
|
||
|
end
|
||
|
if visible then
|
||
|
hadVisibleRightActionIcon = hadVisibleRightActionIcon or not isLeft
|
||
|
if isLeft and textIndex then
|
||
|
-- check if there is only padding before the text, and if this icon can fit within that padding
|
||
|
local firstLayoutElement = textIndex == 2 and not leftText and private.layoutTemp[1] or nil
|
||
|
if textIndex == 2 and type(firstLayoutElement) == "number" and Math.Round(actionIconSize + ICON_SPACING) <= Math.Round(firstLayoutElement) then
|
||
|
private.layoutTemp[1] = private.layoutTemp[1] - actionIconSize - ICON_SPACING
|
||
|
end
|
||
|
private.LayoutTempInsertElementWithSpacing(actionIcon, ICON_SPACING, textIndex)
|
||
|
textIndex = textIndex + 2
|
||
|
else
|
||
|
private.LayoutTempInsertElementWithSpacing(actionIcon, ICON_SPACING)
|
||
|
end
|
||
|
actionIcon:Show()
|
||
|
actionIconButton:SetMouseClickEnabled(true)
|
||
|
if type(texture) == "string" and TSM.UI.TexturePacks.IsValid(texture) then
|
||
|
TSM.UI.TexturePacks.SetTexture(actionIcon, texture)
|
||
|
else
|
||
|
actionIcon:SetTexture(texture)
|
||
|
end
|
||
|
else
|
||
|
actionIcon:Hide()
|
||
|
actionIconButton:SetMouseClickEnabled(false)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local usedWidth = 0
|
||
|
local lastElement = text
|
||
|
if hasText then
|
||
|
local didText = false
|
||
|
local prevElement = nil
|
||
|
local currentSpacing = 0
|
||
|
local isInverted = false
|
||
|
local primaryText = (isAscending and leftText) or (not isAscending and rightText) or nil
|
||
|
local primarySide = isAscending and "LEFT" or "RIGHT"
|
||
|
local secondarySide = isAscending and "RIGHT" or "LEFT"
|
||
|
local spacingModifier = isAscending and 1 or -1
|
||
|
for j = (isAscending and 1 or #private.layoutTemp), (isAscending and #private.layoutTemp or 1), (isAscending and 1 or -1) do
|
||
|
local element = private.layoutTemp[j]
|
||
|
if type(element) == "number" then
|
||
|
currentSpacing = currentSpacing + element
|
||
|
else
|
||
|
if prevElement then
|
||
|
isInverted = isInverted or (prevElement == text and not width and numActionIcons > 0)
|
||
|
if isInverted then
|
||
|
assert(isAscending)
|
||
|
-- this is an icon to the right of the text and the text will need to expand, so invert the anchoring
|
||
|
prevElement:SetPoint("RIGHT", element, "LEFT", -currentSpacing, 0)
|
||
|
else
|
||
|
element:SetPoint(primarySide, prevElement, secondarySide, currentSpacing * spacingModifier, 0)
|
||
|
end
|
||
|
elseif primaryText then
|
||
|
element:SetPoint(primarySide, primaryText, secondarySide, (currentSpacing + Theme.GetColSpacing()) * spacingModifier, 0)
|
||
|
else
|
||
|
if element == text and not canResize then
|
||
|
currentSpacing = currentSpacing + Theme.GetColSpacing() / 2
|
||
|
end
|
||
|
element:SetPoint(primarySide, (currentSpacing + Theme.GetColSpacing() / 2) * spacingModifier, 0)
|
||
|
end
|
||
|
-- don't use up width for elements to the right of the text which aren't visible
|
||
|
if isAscending and (not didText or element:IsVisible()) then
|
||
|
-- the text will resize to fill any remaining width, so don't count it in the used width
|
||
|
if element ~= text then
|
||
|
usedWidth = usedWidth + element:GetWidth()
|
||
|
end
|
||
|
usedWidth = usedWidth + currentSpacing
|
||
|
end
|
||
|
prevElement = element
|
||
|
currentSpacing = 0
|
||
|
didText = didText or element == text
|
||
|
end
|
||
|
end
|
||
|
lastElement = prevElement
|
||
|
else
|
||
|
-- center the icon in the middle
|
||
|
-- TODO: support other combinations
|
||
|
assert(isAscending and icon and not badge and not expander)
|
||
|
if leftText then
|
||
|
text:SetPoint("LEFT", leftText, "RIGHT", Theme.GetColSpacing(), 0)
|
||
|
else
|
||
|
text:SetPoint("LEFT", Theme.GetColSpacing() / 2, 0)
|
||
|
end
|
||
|
icon:SetPoint("CENTER", text, extraWidth / 2, 0)
|
||
|
end
|
||
|
|
||
|
if col:_HasTooltip() then
|
||
|
local tooltipFrame = self._buttons[id]
|
||
|
tooltipFrame:Show()
|
||
|
tooltipFrame:SetPoint("LEFT", iconTexture and icon or text)
|
||
|
tooltipFrame:SetPoint("RIGHT", text)
|
||
|
end
|
||
|
|
||
|
if width then
|
||
|
if hasText then
|
||
|
if width == true then
|
||
|
-- auto-width
|
||
|
text:SetWidth(10000)
|
||
|
width = text:GetStringWidth()
|
||
|
elseif not rightText then
|
||
|
-- leave an extra COL_SPACING / 2 of margin on the right of the last col
|
||
|
extraWidth = extraWidth - Theme.GetColSpacing() / 2
|
||
|
end
|
||
|
text:SetWidth(width - usedWidth + extraWidth)
|
||
|
else
|
||
|
assert(width ~= true) -- auto-width requires the cell to have text
|
||
|
text:SetWidth(width + extraWidth)
|
||
|
end
|
||
|
else
|
||
|
-- we found the text which will expand to fill the extra width, so reverse the iterator direction (only once)
|
||
|
assert(isAscending and not canResize)
|
||
|
Table.InwardIteratorReverse(cols)
|
||
|
if rightText then
|
||
|
-- anchor the right of this the last element for this col to the left of the next one
|
||
|
lastElement:SetPoint("RIGHT", rightText, "LEFT", -Theme.GetColSpacing(), 0)
|
||
|
else
|
||
|
-- this col is the last one, so anchor it to the right of our frame
|
||
|
local spacing = Theme.GetColSpacing()
|
||
|
if hadVisibleRightActionIcon and not rightText then
|
||
|
-- a bit of extra spacing to the right of the last action icon
|
||
|
spacing = spacing + ICON_SPACING
|
||
|
end
|
||
|
lastElement:SetPoint("RIGHT", -spacing, 0)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow._GetDataLayoutRelativeFrame(self, id, col, data, side)
|
||
|
if not id then
|
||
|
return nil
|
||
|
end
|
||
|
assert(side == "LEFT" or side == "RIGHT")
|
||
|
local numActionIcons, _, actionIconShowOnHover = col:_GetActionIconInfo()
|
||
|
if data and (not actionIconShowOnHover or self._state) then
|
||
|
for i = (side == "RIGHT" and 1 or numActionIcons), (side == "RIGHT" and numActionIcons or 1), (side == "RIGHT" and 1 or -1) do
|
||
|
local actionIconKey = "_action"..i.."_"..id
|
||
|
local actionIcon = self._rotatingIcons[actionIconKey]
|
||
|
local actionIconButton = self._buttons[actionIconKey]
|
||
|
local visible, _, isLeft = col:_GetActionIcon(data, i, actionIconButton:IsMouseOver())
|
||
|
if visible and ((isLeft and side == "RIGHT") or (not isLeft and side == "LEFT")) then
|
||
|
return actionIcon
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
local badge = self._texts["_badge_"..id]
|
||
|
if side == "LEFT" and badge and badge:IsVisible() then
|
||
|
return badge
|
||
|
else
|
||
|
return self._texts[id]
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function TableRow._LookupIconByButton(self, button)
|
||
|
local key = Table.GetDistinctKey(self._buttons, button)
|
||
|
local id = strmatch(key, "^_icon_(.+)$")
|
||
|
local col = self._tableInfo:GetColById(id)
|
||
|
return col, self._icons[id]
|
||
|
end
|
||
|
|
||
|
function TableRow._LookupActionIconByButton(self, button)
|
||
|
local key = Table.GetDistinctKey(self._buttons, button)
|
||
|
local iconIndex, id = strmatch(key, "^_action(%d+)_(.+)$")
|
||
|
iconIndex = tonumber(iconIndex)
|
||
|
assert(iconIndex and id)
|
||
|
local col = self._tableInfo:GetColById(id)
|
||
|
return col, iconIndex, self._rotatingIcons[key]
|
||
|
end
|
||
|
|
||
|
function TableRow._LookupTooltipByFrame(self, frame)
|
||
|
local col = self._tableInfo:GetColById(Table.GetDistinctKey(self._buttons, frame))
|
||
|
if not col:_HasTooltip() then
|
||
|
return nil
|
||
|
end
|
||
|
local tooltip, noWrap, anchorFrame = col:_GetTooltip(self:GetData())
|
||
|
local linkingDisabled = col:_GetTooltipLinkingDisabled()
|
||
|
return tooltip, noWrap, anchorFrame, linkingDisabled
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- TableRow - Local Script Handlers
|
||
|
-- ============================================================================
|
||
|
|
||
|
function private.MenuDialogIterator(self, prevIndex)
|
||
|
if prevIndex == nil then
|
||
|
return "HIDE", L["Hide Columns"], private.MenuDialogHideColIterator
|
||
|
elseif prevIndex == "HIDE" then
|
||
|
return "LOCK", self._scrollingTable:_IsColWidthLocked() and L["Unlock Column Width"] or L["Lock Column Width"]
|
||
|
elseif prevIndex == "LOCK" then
|
||
|
return "RESET", L["Reset Table"]
|
||
|
else
|
||
|
return self._tableInfo:_MenuDialogIterator(prevIndex)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.GetMoreDialogColRowContent(col)
|
||
|
local color = Theme.GetColor(col:_IsHidden() and "TEXT+DISABLED" or "TEXT")
|
||
|
local titleText = col:_GetTitle()
|
||
|
if titleText then
|
||
|
return color:ColorText(titleText)
|
||
|
end
|
||
|
local titleIcon = col:_GetTitleIcon()
|
||
|
if titleIcon then
|
||
|
local textureKey = TSM.UI.TexturePacks.GetColoredKey(titleIcon, color)
|
||
|
return TSM.UI.TexturePacks.GetTextureLink(textureKey)
|
||
|
end
|
||
|
error("Unknown title")
|
||
|
end
|
||
|
|
||
|
function private.MenuDialogHideColIterator(self, prevIndex)
|
||
|
local foundPrevIndex = prevIndex == nil
|
||
|
for _, col in ipairs(self._tableInfo:_GetCols()) do
|
||
|
if foundPrevIndex and col:_CanHide() then
|
||
|
return col:_GetId(), private.GetMoreDialogColRowContent(col)
|
||
|
elseif col:_GetId() == prevIndex then
|
||
|
foundPrevIndex = true
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.MoreMenuDialogButtonOnClick(button, self, index1, index2, extra)
|
||
|
assert(not extra and index1)
|
||
|
if index1 == "HIDE" then
|
||
|
assert(index2)
|
||
|
local col = self._tableInfo:GetColById(index2)
|
||
|
assert(col:_CanHide())
|
||
|
self._scrollingTable:_ToggleColHide(index2)
|
||
|
-- update the button text
|
||
|
button:SetText(private.GetMoreDialogColRowContent(col))
|
||
|
:Draw()
|
||
|
elseif index1 == "LOCK" then
|
||
|
assert(not index2)
|
||
|
self._scrollingTable:GetBaseElement():HideDialog()
|
||
|
self._scrollingTable:_ToogleColWidthLocked()
|
||
|
elseif index1 == "RESET" then
|
||
|
assert(not index2)
|
||
|
self._scrollingTable:GetBaseElement():HideDialog()
|
||
|
self._scrollingTable:_ResetContext()
|
||
|
else
|
||
|
self._tableInfo:_HandleMenuButtonClick(index1, index2)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.MoreColOnClick(self, mouseButton)
|
||
|
self._scrollingTable:GetBaseElement():ShowMenuDialog(self._frame, private.MenuDialogIterator, self, private.MoreMenuDialogButtonOnClick)
|
||
|
end
|
||
|
|
||
|
function private.HeaderColOnClick(button, mouseButton)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
if mouseButton == "LeftButton" then
|
||
|
self._scrollingTable:_ToggleSort(Table.GetDistinctKey(self._buttons, button))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.HeaderColOnEnter(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local col = self._tableInfo:GetColById(Table.GetDistinctKey(self._buttons, button))
|
||
|
local tooltip = col:_GetHeaderTooltip()
|
||
|
if tooltip then
|
||
|
Tooltip.Show(button, tooltip)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.HeaderColOnLeave(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local col = self._tableInfo:GetColById(Table.GetDistinctKey(self._buttons, button))
|
||
|
if col:_GetHeaderTooltip() then
|
||
|
Tooltip.Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.RowOnMouseDown(self, button)
|
||
|
if button ~= "RightButton" then
|
||
|
return
|
||
|
end
|
||
|
private.RowOnClick(self, "LeftButton")
|
||
|
end
|
||
|
|
||
|
function private.RowOnClick(self, mouseButton)
|
||
|
if mouseButton == "LeftButton" and not self._scrollingTable._selectionDisabled then
|
||
|
self._scrollingTable:SetSelection(self:GetData())
|
||
|
end
|
||
|
if self._scrollingTable:_IsSelected(self:GetData()) then
|
||
|
self:SetHighlightState(self._scrollingTable._selectionDisabled and "selected" or "selectedHover")
|
||
|
else
|
||
|
self:SetHighlightState("hover")
|
||
|
end
|
||
|
self._scrollingTable:_HandleRowClick(self:GetData(), mouseButton)
|
||
|
end
|
||
|
|
||
|
function private.RowOnEnter(self)
|
||
|
if self._scrollingTable:_IsSelected(self:GetData()) then
|
||
|
self:SetHighlightState(self._scrollingTable._selectionDisabled and "selected" or "selectedHover")
|
||
|
else
|
||
|
self:SetHighlightState("hover")
|
||
|
end
|
||
|
if self._scrollingTable._rightClickToggle and IsMouseButtonDown("RightButton") then
|
||
|
private.RowOnClick(self, "LeftButton")
|
||
|
end
|
||
|
local cursor = self._tableInfo:_GetCursor()
|
||
|
if cursor then
|
||
|
SetCursor(cursor)
|
||
|
end
|
||
|
ScriptWrapper.Set(self._frame, "OnUpdate", private.RowOnUpdate, self)
|
||
|
end
|
||
|
|
||
|
function private.RowOnLeave(self)
|
||
|
for _, text in pairs(self._texts) do
|
||
|
if text._hoverStart then
|
||
|
Tooltip.Hide()
|
||
|
text._hoverStart = nil
|
||
|
end
|
||
|
end
|
||
|
ScriptWrapper.Clear(self._frame, "OnUpdate")
|
||
|
if self:IsVisible() then
|
||
|
if self._scrollingTable:_IsSelected(self:GetData()) then
|
||
|
self:SetHighlightState("selected")
|
||
|
else
|
||
|
self:SetHighlightState(nil)
|
||
|
end
|
||
|
end
|
||
|
if self._tableInfo:_GetCursor() then
|
||
|
ResetCursor()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.RowOnUpdate(self)
|
||
|
if not self._frame:IsMouseOver() then
|
||
|
private.RowOnLeave(self)
|
||
|
return
|
||
|
end
|
||
|
local tooltipText = nil
|
||
|
for _, tooltipFrame in pairs(self._buttons) do
|
||
|
if tooltipFrame:IsVisible() and tooltipFrame:IsMouseOver() then
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
for _, text in pairs(self._texts) do
|
||
|
if text:IsMouseOver() and text:GetWidth() + 0.5 < text:GetUnboundedStringWidth() then
|
||
|
text._hoverStart = text._hoverStart or GetTime()
|
||
|
tooltipText = text
|
||
|
else
|
||
|
text._hoverStart = nil
|
||
|
end
|
||
|
end
|
||
|
if not tooltipText or tooltipText:GetText() == "" or GetTime() - tooltipText._hoverStart < FULL_TEXT_TOOLTIP_DELAY_S then
|
||
|
Tooltip.Hide()
|
||
|
return
|
||
|
end
|
||
|
Tooltip.Show(tooltipText, tooltipText:GetText(), true)
|
||
|
end
|
||
|
|
||
|
function private.IconButtonOnEnter(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
self._frame:GetScript("OnEnter")(self._frame)
|
||
|
local col, icon = self:_LookupIconByButton(button)
|
||
|
local texture, tooltip = col:_GetIcon(self:GetData(), true)
|
||
|
if type(texture) == "string" and TSM.UI.TexturePacks.IsValid(texture) then
|
||
|
TSM.UI.TexturePacks.SetTexture(icon, texture)
|
||
|
else
|
||
|
icon:SetTexture(texture)
|
||
|
end
|
||
|
if tooltip then
|
||
|
Tooltip.Show(button, tooltip)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.IconButtonOnLeave(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
self._frame:GetScript("OnLeave")(self._frame)
|
||
|
local col, icon = self:_LookupIconByButton(button)
|
||
|
local texture, tooltip = col:_GetIcon(self:GetData(), false)
|
||
|
if type(texture) == "string" and TSM.UI.TexturePacks.IsValid(texture) then
|
||
|
TSM.UI.TexturePacks.SetTexture(icon, texture)
|
||
|
else
|
||
|
icon:SetTexture(texture)
|
||
|
end
|
||
|
if tooltip then
|
||
|
Tooltip.Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.IconButtonOnClick(button, mouseButton)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local col = self:_LookupIconByButton(button)
|
||
|
col:_OnIconClick(self:GetData(), mouseButton)
|
||
|
end
|
||
|
|
||
|
function private.ActionIconButtonOnEnter(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
self._frame:GetScript("OnEnter")(self._frame)
|
||
|
local col, iconIndex, icon = self:_LookupActionIconByButton(button)
|
||
|
local visible, texture, _, tooltip = col:_GetActionIcon(self:GetData(), iconIndex, true)
|
||
|
if not visible then
|
||
|
return
|
||
|
end
|
||
|
if tooltip then
|
||
|
Tooltip.Show(button, tooltip)
|
||
|
end
|
||
|
if type(texture) == "string" and TSM.UI.TexturePacks.IsValid(texture) then
|
||
|
TSM.UI.TexturePacks.SetTexture(icon, texture)
|
||
|
else
|
||
|
icon:SetTexture(texture)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.ActionIconButtonOnLeave(button)
|
||
|
if not button:IsVisible() then
|
||
|
-- ignore OnLeave if we just hid this button
|
||
|
Tooltip.Hide()
|
||
|
return
|
||
|
end
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
self._frame:GetScript("OnLeave")(self._frame)
|
||
|
local col, iconIndex, icon, tooltip = self:_LookupActionIconByButton(button)
|
||
|
local visible, texture = col:_GetActionIcon(self:GetData(), iconIndex, false)
|
||
|
if tooltip then
|
||
|
Tooltip.Hide()
|
||
|
end
|
||
|
if not visible then
|
||
|
return
|
||
|
end
|
||
|
if type(texture) == "string" and TSM.UI.TexturePacks.IsValid(texture) then
|
||
|
TSM.UI.TexturePacks.SetTexture(icon, texture)
|
||
|
else
|
||
|
icon:SetTexture(texture)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.ActionIconButtonOnClick(button, mouseButton)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local col, iconIndex = self:_LookupActionIconByButton(button)
|
||
|
col:_OnActionButtonClick(self:GetData(), iconIndex, mouseButton)
|
||
|
end
|
||
|
|
||
|
function private.TooltipFrameOnEnter(frame)
|
||
|
frame.isShowingTooltip = true
|
||
|
local self = private.rowFrameLookup[frame:GetParent()]
|
||
|
self._frame:GetScript("OnEnter")(self._frame)
|
||
|
local tooltip, noWrap, anchorFrame = self:_LookupTooltipByFrame(frame)
|
||
|
Tooltip.Show(anchorFrame and self._frame or frame, tooltip, noWrap)
|
||
|
end
|
||
|
|
||
|
function private.TooltipFrameOnLeave(frame)
|
||
|
frame.isShowingTooltip = nil
|
||
|
local self = private.rowFrameLookup[frame:GetParent()]
|
||
|
self._frame:GetScript("OnLeave")(self._frame)
|
||
|
Tooltip.Hide()
|
||
|
end
|
||
|
|
||
|
function private.TooltipFrameOnClick(frame, ...)
|
||
|
local self = private.rowFrameLookup[frame:GetParent()]
|
||
|
local tooltip, _, _, linkingDisabled = self:_LookupTooltipByFrame(frame)
|
||
|
if not linkingDisabled and (IsShiftKeyDown() or IsControlKeyDown()) then
|
||
|
local link = tooltip and ItemInfo.GetLink(tooltip)
|
||
|
if link then
|
||
|
if IsShiftKeyDown() then
|
||
|
Wow.SafeItemRef(link)
|
||
|
elseif IsControlKeyDown() then
|
||
|
DressUpItemLink(link)
|
||
|
end
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
self._frame:GetScript("OnClick")(self._frame, ...)
|
||
|
end
|
||
|
|
||
|
function private.ResizerOnEnter(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local id = Table.GetDistinctKey(self._buttons, button)
|
||
|
self._icons[id]:Show()
|
||
|
end
|
||
|
|
||
|
function private.ResizerOnLeave(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local id = Table.GetDistinctKey(self._buttons, button)
|
||
|
self._icons[id]:Hide()
|
||
|
end
|
||
|
|
||
|
function private.ResizerOnMouseDown(button, mouseButton)
|
||
|
if mouseButton ~= "LeftButton" then
|
||
|
return
|
||
|
end
|
||
|
ScriptWrapper.Set(button, "OnUpdate", private.ResizerOnUpdate)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local id = Table.GetDistinctKey(self._buttons, button)
|
||
|
local parentId = strmatch(id, "^_resizer_(.+)$")
|
||
|
self._buttons[parentId]:StartSizing("RIGHT")
|
||
|
self._icons[id]:SetPoint("TOPLEFT", self._buttons[parentId], "TOPLEFT", -Theme.GetColSpacing() / 2, 0)
|
||
|
end
|
||
|
|
||
|
function private.ResizerOnMouseUp(button, mouseButton)
|
||
|
if mouseButton ~= "LeftButton" then
|
||
|
return
|
||
|
end
|
||
|
ScriptWrapper.Clear(button, "OnUpdate")
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local id = Table.GetDistinctKey(self._buttons, button)
|
||
|
local parentId = strmatch(id, "^_resizer_(.+)$")
|
||
|
local parentButton = self._buttons[parentId]
|
||
|
parentButton:StopMovingOrSizing()
|
||
|
self:_LayoutHeaderRow()
|
||
|
self._scrollingTable:_SetColWidth(parentId, Math.Round(parentButton:GetWidth()), true)
|
||
|
self._icons[id]:SetPoint("TOPLEFT", button)
|
||
|
end
|
||
|
|
||
|
function private.ResizerOnClick(button, mouseButton)
|
||
|
if mouseButton ~= "RightButton" then
|
||
|
return
|
||
|
end
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local id = Table.GetDistinctKey(self._buttons, button)
|
||
|
local parentId = strmatch(id, "^_resizer_(.+)$")
|
||
|
self._scrollingTable:_ResetColWidth(parentId)
|
||
|
end
|
||
|
|
||
|
function private.ResizerOnUpdate(button)
|
||
|
local self = private.rowFrameLookup[button:GetParent()]
|
||
|
local id = Table.GetDistinctKey(self._buttons, button)
|
||
|
local parentId = strmatch(id, "^_resizer_(.+)$")
|
||
|
local parentButton = self._buttons[parentId]
|
||
|
self._scrollingTable:_SetColWidth(parentId, Math.Round(parentButton:GetWidth()))
|
||
|
end
|
||
|
|
||
|
function private.ExpanderOnLeave(self)
|
||
|
self._frame:GetScript("OnEnter")(self._frame)
|
||
|
end
|
||
|
|
||
|
function private.ExpanderOnClick(self, mouseButton, ...)
|
||
|
if mouseButton ~= "LeftButton" then
|
||
|
return
|
||
|
end
|
||
|
self._frame:GetScript("OnDoubleClick")(self._frame, mouseButton, ...)
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- Private Helper Functions
|
||
|
-- ============================================================================
|
||
|
|
||
|
function private.LayoutTempInsertSpacing(spacing)
|
||
|
assert(type(spacing) == "number")
|
||
|
local length = #private.layoutTemp
|
||
|
if type(private.layoutTemp[length]) == "number" then
|
||
|
-- add to the previous spacing
|
||
|
private.layoutTemp[length] = private.layoutTemp[length] + spacing
|
||
|
else
|
||
|
-- insert a new entry
|
||
|
private.layoutTemp[length + 1] = spacing
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function private.LayoutTempInsertElementWithSpacing(element, spacing, index)
|
||
|
assert(type(element) == "table" and type(spacing) == "number")
|
||
|
if index then
|
||
|
tinsert(private.layoutTemp, index, element)
|
||
|
tinsert(private.layoutTemp, index + 1, spacing)
|
||
|
else
|
||
|
local length = #private.layoutTemp
|
||
|
private.layoutTemp[length + 1] = element
|
||
|
private.layoutTemp[length + 2] = spacing
|
||
|
end
|
||
|
end
|