Skip to content

Commit

Permalink
Smooth Drawing (#696)
Browse files Browse the repository at this point in the history
* Bags now sort and update smoother than ever, with little to no frame skip in all cases.
  • Loading branch information
Cidan authored Sep 12, 2024
1 parent 16840cd commit fde068c
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 273 deletions.
14 changes: 13 additions & 1 deletion data/slots.lua
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,19 @@ end

---@return ItemData[], ItemData[], ItemData[]
function SlotInfo:GetChangeset()
return self.addedItems, self.removedItems, self.updatedItems
local added = {}
local removed = {}
local updated = {}
for _, item in pairs(self.addedItems) do
table.insert(added, item)
end
for _, item in pairs(self.removedItems) do
table.insert(removed, item)
end
for _, item in pairs(self.updatedItems) do
table.insert(updated, item)
end
return added, removed, updated
end

---@param ctx Context
Expand Down
40 changes: 23 additions & 17 deletions frames/bag.lua
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ local tabs = addon:GetModule('Tabs')
---@field menuList MenuList[]
---@field toRelease Item[]
---@field toReleaseSections Section[]
---@field views table<BagView, View>
---@field views table<BagView, View[]>
---@field loaded boolean
---@field windowGrouping WindowGrouping
---@field sideAnchor Frame
Expand Down Expand Up @@ -300,23 +300,20 @@ end
---@param slotInfo SlotInfo
---@param callback fun()
function bagFrame.bagProto:Draw(ctx, slotInfo, callback)
local view = self.views[database:GetBagView(self.kind)]
local viewList = self.views[database:GetBagView(self.kind)]
local updateView = viewList[1] == self.currentView and viewList[2] or viewList[1]
local previousView = self.currentView

if view == nil then
assert(view, "No view found for bag view: "..database:GetBagView(self.kind))
return
end

if self.currentView and self.currentView:GetBagView() ~= view:GetBagView() then
self.currentView:Wipe(ctx)
self.currentView:GetContent():Hide()
end
--if self.currentView and self.currentView:GetBagView() ~= updateView:GetBagView() then
-- self.currentView:Wipe(ctx)
-- self.currentView:GetContent():Hide()
--end

debug:StartProfile('Bag Render %d', self.kind)
view:Render(ctx, self, slotInfo, function()
updateView:Render(ctx, self, slotInfo, function()
debug:EndProfile('Bag Render %d', self.kind)
view:GetContent():Show()
self.currentView = view
updateView:GetContent():Show()
self.currentView = updateView
self.frame:SetScale(database:GetBagSizeInfo(self.kind, database:GetBagView(self.kind)).scale / 100)
local text = searchBox:GetText()
if text ~= "" and text ~= nil then
Expand All @@ -329,7 +326,16 @@ function bagFrame.bagProto:Draw(ctx, slotInfo, callback)
end
events:SendMessage(ctx, 'bag/RedrawIcons', self)
events:SendMessage(ctx, 'bag/Rendered', self, slotInfo)
callback()
if previousView then
previousView:GetContent():Hide()
if previousView:GetBagView() == updateView:GetBagView() then
previousView:Render(ctx, self, slotInfo, callback)
else
callback()
end
else
callback()
end
end)
end

Expand Down Expand Up @@ -551,8 +557,8 @@ function bagFrame:Create(ctx, kind)
--end)

b.views = {
[const.BAG_VIEW.SECTION_GRID] = views:NewGrid(f, b.kind),
[const.BAG_VIEW.SECTION_ALL_BAGS] = views:NewBagView(f, b.kind),
[const.BAG_VIEW.SECTION_GRID] = {views:NewGrid(f, b.kind), views:NewGrid(f, b.kind)},
[const.BAG_VIEW.SECTION_ALL_BAGS] = {views:NewBagView(f, b.kind), views:NewBagView(f, b.kind)},
}

-- Register the bag frame so that window positions are saved.
Expand Down
5 changes: 5 additions & 0 deletions frames/section.lua
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ function sectionProto:ReleaseAllCells(ctx)
end
end

---@return Cell[]|Item[]|Section[]|any[]
function sectionProto:GetCellList()
return self.content.cells
end

function sectionProto:Wipe()
self.content:Wipe()
self.frame:Hide()
Expand Down
183 changes: 107 additions & 76 deletions views/bagview.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,37 @@ local database = addon:GetModule('Database')
---@class Sort: AceModule
local sort = addon:GetModule('Sort')

---@class Async: AceModule
local async = addon:GetModule('Async')

---@class Localization: AceModule
local L = addon:GetModule('Localization')

---@param view View
---@param ctx Context
local function Wipe(view, ctx)
local function Wipe(view, _)
view.content:Wipe()
view.itemCount = 0
--for _, section in pairs(view.sections) do
-- section:ReleaseAllCells(ctx)
-- section:Release(ctx)
--end
--wipe(view.sections)
--wipe(view.itemsByBagAndSlot)
end

---@param ctx Context
---@param view View
local function WipeSections(ctx, view)
debug:StartProfile('Bag View Sections Wipe')
for _, section in pairs(view.sections) do
section:ReleaseAllCells(ctx)
async:RawBatch(ctx, 10, section:GetCellList(), function(bctx, cell)
cell:Release(bctx)
end)
section:Release(ctx)
end
wipe(view.sections)
wipe(view.itemsByBagAndSlot)
debug:EndProfile('Bag View Sections Wipe')
end

---@param bagid number
Expand Down Expand Up @@ -139,85 +156,99 @@ local function BagView(view, ctx, bag, slotInfo, callback)

local added, removed, changed = slotInfo:GetChangeset()

for _, item in pairs(removed) do
ClearButton(ctx, view, item)
end

for _, item in pairs(added) do
CreateButton(ctx, view, item)
end

for _, item in pairs(changed) do
UpdateButton(ctx, view, item.slotkey)
end

for bagid, emptyBagData in pairs(slotInfo.emptySlotByBagAndSlot) do
for slotid, data in pairs(emptyBagData) do
local slotkey = view:GetSlotKey(data)
if C_Container.GetBagName(bagid) ~= nil then
local itemButton = view.itemsByBagAndSlot[slotkey] --[[@as Item]]
if itemButton == nil then
itemButton = itemFrame:Create(ctx)
view.itemsByBagAndSlot[slotkey] = itemButton
async:Chain(ctx, nil,
function(ectx)
if ectx:GetBool('wipe') then
debug:StartProfile('Wipe Loop')
view:Wipe(ectx)
WipeSections(ectx, view)
debug:EndProfile('Wipe Loop')
end
end,
function(ectx)
async:RawBatch(ectx, 15, removed, function(bctx, item)
ClearButton(bctx, view, item)
end)
end,
function(ectx)
async:RawBatch(ectx, 15, added, function(bctx, item)
CreateButton(bctx, view, item)
end)
end,
function(ectx)
async:RawBatch(ectx, 15, changed, function(bctx, item)
UpdateButton(bctx, view, item.slotkey)
end)
end,
function(ectx)
for bagid, emptyBagData in pairs(slotInfo.emptySlotByBagAndSlot) do
for slotid, data in pairs(emptyBagData) do
local slotkey = view:GetSlotKey(data)
if C_Container.GetBagName(bagid) ~= nil then
local itemButton = view.itemsByBagAndSlot[slotkey] --[[@as Item]]
if itemButton == nil then
itemButton = itemFrame:Create(ectx)
view.itemsByBagAndSlot[slotkey] = itemButton
end
itemButton:SetFreeSlots(ectx, bagid, slotid, -1)
local section = view:GetOrCreateSection(ectx, GetBagName(bagid))
section:AddCell(slotkey, itemButton)
end
itemButton:SetFreeSlots(ctx, bagid, slotid, -1)
local section = view:GetOrCreateSection(ctx, GetBagName(bagid))
section:AddCell(slotkey, itemButton)
end
end
end

for _, item in pairs(view.itemsByBagAndSlot) do
item:UpdateCount(ctx)
end
for _, item in pairs(view.itemsByBagAndSlot) do
item:UpdateCount(ectx)
end

for sectionName, section in pairs(view:GetAllSections()) do
if section:GetCellCount() == 0 then
debug:Log("RemoveSection", "Removed because empty", sectionName)
view:RemoveSection(sectionName)
section:ReleaseAllCells(ctx)
section:Release(ctx)
else
debug:Log("KeepSection", "Section kept because not empty", sectionName)
section:SetMaxCellWidth(sizeInfo.itemsPerRow)
section:Draw(bag.kind, database:GetBagView(bag.kind), true)
for sectionName, section in pairs(view:GetAllSections()) do
if section:GetCellCount() == 0 then
debug:Log("RemoveSection", "Removed because empty", sectionName)
view:RemoveSection(sectionName)
section:ReleaseAllCells(ectx)
section:Release(ectx)
else
debug:Log("KeepSection", "Section kept because not empty", sectionName)
section:SetMaxCellWidth(sizeInfo.itemsPerRow)
section:Draw(bag.kind, database:GetBagView(bag.kind), true)
end
end
end
view.content.maxCellWidth = sizeInfo.columnCount
-- Sort the sections.
view.content:Sort(function(a, b)
return sort.SortSectionsAlphabetically(view.kind, a, b)
end)
debug:StartProfile('Content Draw Stage')
local w, h = view.content:Draw({
cells = view.content.cells,
maxWidthPerRow = ((37 + 4) * sizeInfo.itemsPerRow) + 16,
columns = sizeInfo.columnCount,
})
debug:EndProfile('Content Draw Stage')
-- Reposition the content frame if the recent items section is empty.
if w < 160 then
w = 160
end
if bag.tabs and w < bag.tabs.width then
w = bag.tabs.width
end
if h == 0 then
h = 40
end
if database:GetInBagSearch() then
h = h + 20
end
view.content:HideScrollBar()
--TODO(lobato): Implement SafeSetSize that prevents the window from being larger
-- than the screen space.
bag.frame:SetWidth(w + const.OFFSETS.BAG_LEFT_INSET + -const.OFFSETS.BAG_RIGHT_INSET)
local bagHeight = h +
const.OFFSETS.BAG_BOTTOM_INSET + -const.OFFSETS.BAG_TOP_INSET +
const.OFFSETS.BOTTOM_BAR_HEIGHT + const.OFFSETS.BOTTOM_BAR_BOTTOM_INSET
bag.frame:SetHeight(bagHeight)
UpdateViewSize(view)
callback()
view.content.maxCellWidth = sizeInfo.columnCount
-- Sort the sections.
view.content:Sort(function(a, b)
return sort.SortSectionsAlphabetically(view.kind, a, b)
end)
debug:StartProfile('Content Draw Stage')
local w, h = view.content:Draw({
cells = view.content.cells,
maxWidthPerRow = ((37 + 4) * sizeInfo.itemsPerRow) + 16,
columns = sizeInfo.columnCount,
})
debug:EndProfile('Content Draw Stage')
-- Reposition the content frame if the recent items section is empty.
if w < 160 then
w = 160
end
if bag.tabs and w < bag.tabs.width then
w = bag.tabs.width
end
if h == 0 then
h = 40
end
if database:GetInBagSearch() then
h = h + 20
end
view.content:HideScrollBar()
--TODO(lobato): Implement SafeSetSize that prevents the window from being larger
-- than the screen space.
bag.frame:SetWidth(w + const.OFFSETS.BAG_LEFT_INSET + -const.OFFSETS.BAG_RIGHT_INSET)
local bagHeight = h +
const.OFFSETS.BAG_BOTTOM_INSET + -const.OFFSETS.BAG_TOP_INSET +
const.OFFSETS.BOTTOM_BAR_HEIGHT + const.OFFSETS.BOTTOM_BAR_BOTTOM_INSET
bag.frame:SetHeight(bagHeight)
UpdateViewSize(view)
end, callback)

end

---@param parent Frame
Expand Down
Loading

0 comments on commit fde068c

Please sign in to comment.