|
24 | 24 | -- f:AddChild(btn)
|
25 | 25 | -- @class file
|
26 | 26 | -- @name AceGUI-3.0
|
27 |
| --- @release $Id: AceGUI-3.0.lua 1102 2013-10-25 14:15:23Z nevcairiel $ |
28 |
| -local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 34 |
| 27 | +-- @release $Id: AceGUI-3.0.lua 1177 2018-06-25 12:12:48Z nevcairiel $ |
| 28 | +local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 36 |
29 | 29 | local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
|
30 | 30 |
|
31 | 31 | if not AceGUI then return end -- No upgrade needed
|
@@ -811,3 +811,221 @@ AceGUI:RegisterLayout("Flow",
|
811 | 811 | height = height + rowheight + 3
|
812 | 812 | safecall(content.obj.LayoutFinished, content.obj, nil, height)
|
813 | 813 | end)
|
| 814 | + |
| 815 | +-- Get alignment method and value. Possible alignment methods are a callback, a number, "start", "middle", "end", "fill" or "TOPLEFT", "BOTTOMRIGHT" etc. |
| 816 | +local GetCellAlign = function (dir, tableObj, colObj, cellObj, cell, child) |
| 817 | + local fn = cellObj and (cellObj["align" .. dir] or cellObj.align) |
| 818 | + or colObj and (colObj["align" .. dir] or colObj.align) |
| 819 | + or tableObj["align" .. dir] or tableObj.align |
| 820 | + or "CENTERLEFT" |
| 821 | + local child, cell, val = child or 0, cell or 0, nil |
| 822 | + |
| 823 | + if type(fn) == "string" then |
| 824 | + fn = fn:lower() |
| 825 | + fn = dir == "V" and (fn:sub(1, 3) == "top" and "start" or fn:sub(1, 6) == "bottom" and "end" or fn:sub(1, 6) == "center" and "middle") |
| 826 | + or dir == "H" and (fn:sub(-4) == "left" and "start" or fn:sub(-5) == "right" and "end" or fn:sub(-6) == "center" and "middle") |
| 827 | + or fn |
| 828 | + val = (fn == "start" or fn == "fill") and 0 or fn == "end" and cell - child or (cell - child) / 2 |
| 829 | + elseif type(fn) == "function" then |
| 830 | + val = fn(child or 0, cell, dir) |
| 831 | + else |
| 832 | + val = fn |
| 833 | + end |
| 834 | + |
| 835 | + return fn, max(0, min(val, cell)) |
| 836 | +end |
| 837 | + |
| 838 | +-- Get width or height for multiple cells combined |
| 839 | +local GetCellDimension = function (dir, laneDim, from, to, space) |
| 840 | + local dim = 0 |
| 841 | + for cell=from,to do |
| 842 | + dim = dim + (laneDim[cell] or 0) |
| 843 | + end |
| 844 | + return dim + max(0, to - from) * (space or 0) |
| 845 | +end |
| 846 | + |
| 847 | +--[[ Options |
| 848 | +============ |
| 849 | +Container: |
| 850 | + - columns ({col, col, ...}): Column settings. "col" can be a number (<= 0: content width, <1: rel. width, <10: weight, >=10: abs. width) or a table with column setting. |
| 851 | + - space, spaceH, spaceV: Overall, horizontal and vertical spacing between cells. |
| 852 | + - align, alignH, alignV: Overall, horizontal and vertical cell alignment. See GetCellAlign() for possible values. |
| 853 | +Columns: |
| 854 | + - width: Fixed column width (nil or <=0: content width, <1: rel. width, >=1: abs. width). |
| 855 | + - min or 1: Min width for content based width |
| 856 | + - max or 2: Max width for content based width |
| 857 | + - weight: Flexible column width. The leftover width after accounting for fixed-width columns is distributed to weighted columns according to their weights. |
| 858 | + - align, alignH, alignV: Overwrites the container setting for alignment. |
| 859 | +Cell: |
| 860 | + - colspan: Makes a cell span multiple columns. |
| 861 | + - rowspan: Makes a cell span multiple rows. |
| 862 | + - align, alignH, alignV: Overwrites the container and column setting for alignment. |
| 863 | +]] |
| 864 | +AceGUI:RegisterLayout("Table", |
| 865 | + function (content, children) |
| 866 | + local obj = content.obj |
| 867 | + obj:PauseLayout() |
| 868 | + |
| 869 | + local tableObj = obj:GetUserData("table") |
| 870 | + local cols = tableObj.columns |
| 871 | + local spaceH = tableObj.spaceH or tableObj.space or 0 |
| 872 | + local spaceV = tableObj.spaceV or tableObj.space or 0 |
| 873 | + local totalH = (content:GetWidth() or content.width or 0) - spaceH * (#cols - 1) |
| 874 | + |
| 875 | + -- We need to reuse these because layout events can come in very frequently |
| 876 | + local layoutCache = obj:GetUserData("layoutCache") |
| 877 | + if not layoutCache then |
| 878 | + layoutCache = {{}, {}, {}, {}, {}, {}} |
| 879 | + obj:SetUserData("layoutCache", layoutCache) |
| 880 | + end |
| 881 | + local t, laneH, laneV, rowspans, rowStart, colStart = unpack(layoutCache) |
| 882 | + |
| 883 | + -- Create the grid |
| 884 | + local n, slotFound = 0 |
| 885 | + for i,child in ipairs(children) do |
| 886 | + if child:IsShown() then |
| 887 | + repeat |
| 888 | + n = n + 1 |
| 889 | + local col = (n - 1) % #cols + 1 |
| 890 | + local row = ceil(n / #cols) |
| 891 | + local rowspan = rowspans[col] |
| 892 | + local cell = rowspan and rowspan.child or child |
| 893 | + local cellObj = cell:GetUserData("cell") |
| 894 | + slotFound = not rowspan |
| 895 | + |
| 896 | + -- Rowspan |
| 897 | + if not rowspan and cellObj and cellObj.rowspan then |
| 898 | + rowspan = {child = child, from = row, to = row + cellObj.rowspan - 1} |
| 899 | + rowspans[col] = rowspan |
| 900 | + end |
| 901 | + if rowspan and i == #children then |
| 902 | + rowspan.to = row |
| 903 | + end |
| 904 | + |
| 905 | + -- Colspan |
| 906 | + local colspan = max(0, min((cellObj and cellObj.colspan or 1) - 1, #cols - col)) |
| 907 | + n = n + colspan |
| 908 | + |
| 909 | + -- Place the cell |
| 910 | + if not rowspan or rowspan.to == row then |
| 911 | + t[n] = cell |
| 912 | + rowStart[cell] = rowspan and rowspan.from or row |
| 913 | + colStart[cell] = col |
| 914 | + |
| 915 | + if rowspan then |
| 916 | + rowspans[col] = nil |
| 917 | + end |
| 918 | + end |
| 919 | + until slotFound |
| 920 | + end |
| 921 | + end |
| 922 | + |
| 923 | + local rows = ceil(n / #cols) |
| 924 | + |
| 925 | + -- Determine fixed size cols and collect weights |
| 926 | + local extantH, totalWeight = totalH, 0 |
| 927 | + for col,colObj in ipairs(cols) do |
| 928 | + laneH[col] = 0 |
| 929 | + |
| 930 | + if type(colObj) == "number" then |
| 931 | + colObj = {[colObj >= 1 and colObj < 10 and "weight" or "width"] = colObj} |
| 932 | + cols[col] = colObj |
| 933 | + end |
| 934 | + |
| 935 | + if colObj.weight then |
| 936 | + -- Weight |
| 937 | + totalWeight = totalWeight + (colObj.weight or 1) |
| 938 | + else |
| 939 | + if not colObj.width or colObj.width <= 0 then |
| 940 | + -- Content width |
| 941 | + for row=1,rows do |
| 942 | + local child = t[(row - 1) * #cols + col] |
| 943 | + if child then |
| 944 | + local f = child.frame |
| 945 | + f:ClearAllPoints() |
| 946 | + local childH = f:GetWidth() or 0 |
| 947 | + |
| 948 | + laneH[col] = max(laneH[col], childH - GetCellDimension("H", laneH, colStart[child], col - 1, spaceH)) |
| 949 | + end |
| 950 | + end |
| 951 | + |
| 952 | + laneH[col] = max(colObj.min or colObj[1] or 0, min(laneH[col], colObj.max or colObj[2] or laneH[col])) |
| 953 | + else |
| 954 | + -- Rel./Abs. width |
| 955 | + laneH[col] = colObj.width < 1 and colObj.width * totalH or colObj.width |
| 956 | + end |
| 957 | + extantH = max(0, extantH - laneH[col]) |
| 958 | + end |
| 959 | + end |
| 960 | + |
| 961 | + -- Determine sizes based on weight |
| 962 | + local scale = totalWeight > 0 and extantH / totalWeight or 0 |
| 963 | + for col,colObj in pairs(cols) do |
| 964 | + if colObj.weight then |
| 965 | + laneH[col] = scale * colObj.weight |
| 966 | + end |
| 967 | + end |
| 968 | + |
| 969 | + -- Arrange children |
| 970 | + for row=1,rows do |
| 971 | + local rowV = 0 |
| 972 | + |
| 973 | + -- Horizontal placement and sizing |
| 974 | + for col=1,#cols do |
| 975 | + local child = t[(row - 1) * #cols + col] |
| 976 | + if child then |
| 977 | + local colObj = cols[colStart[child]] |
| 978 | + local cellObj = child:GetUserData("cell") |
| 979 | + local offsetH = GetCellDimension("H", laneH, 1, colStart[child] - 1, spaceH) + (colStart[child] == 1 and 0 or spaceH) |
| 980 | + local cellH = GetCellDimension("H", laneH, colStart[child], col, spaceH) |
| 981 | + |
| 982 | + local f = child.frame |
| 983 | + f:ClearAllPoints() |
| 984 | + local childH = f:GetWidth() or 0 |
| 985 | + |
| 986 | + local alignFn, align = GetCellAlign("H", tableObj, colObj, cellObj, cellH, childH) |
| 987 | + f:SetPoint("LEFT", content, offsetH + align, 0) |
| 988 | + if child:IsFullWidth() or alignFn == "fill" or childH > cellH then |
| 989 | + f:SetPoint("RIGHT", content, "LEFT", offsetH + align + cellH, 0) |
| 990 | + end |
| 991 | + |
| 992 | + if child.DoLayout then |
| 993 | + child:DoLayout() |
| 994 | + end |
| 995 | + |
| 996 | + rowV = max(rowV, (f:GetHeight() or 0) - GetCellDimension("V", laneV, rowStart[child], row - 1, spaceV)) |
| 997 | + end |
| 998 | + end |
| 999 | + |
| 1000 | + laneV[row] = rowV |
| 1001 | + |
| 1002 | + -- Vertical placement and sizing |
| 1003 | + for col=1,#cols do |
| 1004 | + local child = t[(row - 1) * #cols + col] |
| 1005 | + if child then |
| 1006 | + local colObj = cols[colStart[child]] |
| 1007 | + local cellObj = child:GetUserData("cell") |
| 1008 | + local offsetV = GetCellDimension("V", laneV, 1, rowStart[child] - 1, spaceV) + (rowStart[child] == 1 and 0 or spaceV) |
| 1009 | + local cellV = GetCellDimension("V", laneV, rowStart[child], row, spaceV) |
| 1010 | + |
| 1011 | + local f = child.frame |
| 1012 | + local childV = f:GetHeight() or 0 |
| 1013 | + |
| 1014 | + local alignFn, align = GetCellAlign("V", tableObj, colObj, cellObj, cellV, childV) |
| 1015 | + if child:IsFullHeight() or alignFn == "fill" then |
| 1016 | + f:SetHeight(cellV) |
| 1017 | + end |
| 1018 | + f:SetPoint("TOP", content, 0, -(offsetV + align)) |
| 1019 | + end |
| 1020 | + end |
| 1021 | + end |
| 1022 | + |
| 1023 | + -- Calculate total height |
| 1024 | + local totalV = GetCellDimension("V", laneV, 1, #laneV, spaceV) |
| 1025 | + |
| 1026 | + -- Cleanup |
| 1027 | + for _,v in pairs(layoutCache) do wipe(v) end |
| 1028 | + |
| 1029 | + safecall(obj.LayoutFinished, obj, nil, totalV) |
| 1030 | + obj:ResumeLayout() |
| 1031 | + end) |
0 commit comments