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.

180 lines
5.9 KiB

--- MSA-AceGUI-3.0 - modified GUI layout
--- Based on AceGUI "Flow" layout with some modifications. Used by MSA-AceConfigDialog-3.0.
--- Because I hate stupid basic containers without margin!
---
--- Marouan Sabbagh <mar.sabbagh@gmail.com>
local AceGUI = LibStub("AceGUI-3.0")
-- Lua API
local math_max = math.max
local xpcall = xpcall
local width_multiplier = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE and 184 or 170 -- MSA
local margin_left = 16
--------------
-- Internal --
--------------
local function errorhandler(err)
return geterrorhandler()(err)
end
local function safecall(func, ...)
if func then
return xpcall(func, errorhandler, ...)
end
end
local layoutrecursionblock = nil
local function safelayoutcall(object, func, ...)
layoutrecursionblock = true
object[func](object, ...)
layoutrecursionblock = nil
end
--------------
-- External --
--------------
AceGUI:RegisterLayout("MSA-Flow",
function(content, children)
if layoutrecursionblock then return end
--used height so far
local height = 0
--width used in the current row
local usedwidth = 0
--height of the current row
local rowheight = 0
local rowoffset = 0
local width = content.width or content:GetWidth() or 0
--control at the start of the row
local rowstart
local rowstartoffset
local isfullheight
local frameoffset
local lastframeoffset
local oversize
for i = 1, #children do
local child = children[i]
oversize = nil
local frame = child.frame
local frameheight = frame.height or frame:GetHeight() or 0
local framewidth = frame.width or frame:GetWidth() or 0
lastframeoffset = frameoffset
-- HACK: Why did we set a frameoffset of (frameheight / 2) ?
-- That was moving all widgets half the widgets size down, is that intended?
-- Actually, it seems to be neccessary for many cases, we'll leave it in for now.
-- If widgets seem to anchor weirdly with this, provide a valid alignoffset for them.
-- TODO: Investigate moar!
frameoffset = (child.alignoffset or (frameheight / 2)) + 3 -- MSA
if child.width == "relative" then
framewidth = width * child.relWidth
end
frame:Show()
frame:ClearAllPoints()
if i == 1 then
-- anchor the first control to the top left
frame:SetPoint("TOPLEFT", content)
rowheight = frameheight
rowoffset = frameoffset
rowstart = frame
rowstartoffset = frameoffset
usedwidth = framewidth
if usedwidth > width then
oversize = true
end
else
-- if there isn't available width for the control start a new row
-- if a control is "fill" it will be on a row of its own full width
if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
if isfullheight then
-- a previous row has already filled the entire height, there's nothing we can usefully do anymore
-- (maybe error/warn about this?)
break
end
--anchor the previous row, we will now know its height and offset
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 2)) -- MSA
height = height + rowheight + 6 -- MSA
--save this as the rowstart so we can anchor it after the row is complete and we have the max height and offset of controls in it
rowstart = frame
rowstartoffset = frameoffset
rowheight = frameheight
rowoffset = frameoffset
usedwidth = framewidth
if usedwidth > width then
oversize = true
end
-- put the control on the current row, adding it to the width and checking if the height needs to be increased
else
--handles cases where the new height is higher than either control because of the offsets
--math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
--offset is always the larger of the two offsets
rowoffset = math_max(rowoffset, frameoffset)
rowheight = math_max(rowheight, rowoffset + (frameheight / 2))
frame:SetPoint("TOPLEFT", children[i-1].frame, "TOPRIGHT", margin_left, frameoffset - lastframeoffset) -- MSA
usedwidth = framewidth + usedwidth + margin_left -- MSA
end
end
-- MSA
if framewidth == (width_multiplier * 2) then -- double
safelayoutcall(child, "SetWidth", framewidth + margin_left)
usedwidth = usedwidth + margin_left
elseif framewidth == (width_multiplier * 1.5) then -- normal+half
safelayoutcall(child, "SetWidth", framewidth + (margin_left / 2))
usedwidth = usedwidth + (margin_left / 2)
elseif framewidth == (width_multiplier / 2) then -- half
safelayoutcall(child, "SetWidth", framewidth - (margin_left / 2))
usedwidth = usedwidth - (margin_left / 2)
end
if child.width == "fill" then
safelayoutcall(child, "SetWidth", width)
frame:SetPoint("RIGHT", content)
usedwidth = 0
rowstart = frame
if child.DoLayout then
child:DoLayout()
end
rowheight = frame.height or frame:GetHeight() or 0
rowoffset = child.alignoffset or (rowheight / 2)
rowstartoffset = rowoffset
elseif child.width == "relative" then
safelayoutcall(child, "SetWidth", width * child.relWidth)
if child.DoLayout then
child:DoLayout()
end
elseif oversize then
if width > 1 then
frame:SetPoint("RIGHT", content)
end
end
if child.height == "fill" then
frame:SetPoint("BOTTOM", content)
isfullheight = true
end
end
--anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
if isfullheight then
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -height)
elseif rowstart then
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
end
height = height + rowheight + 3
safecall(content.obj.LayoutFinished, content.obj, nil, height)
end)