27 | function FlowLayoutElement:invalidateLayout(ignoreVisibility) |
28 | local totalWidth = 0 |
29 | local lineHeight = 0 |
30 | for _, element in pairs(self.elements) do |
31 | if self:getIsElementIncluded(element, ignoreVisibility) then |
32 | totalWidth = totalWidth + element.absSize[1] + element.margin[1] + element.margin[3] |
33 | lineHeight = math.max(lineHeight, element.absSize[2] + element.margin[2] + element.margin[4]) |
34 | end |
35 | end |
36 | |
37 | local posX = 0 |
38 | if self.alignmentX == FlowLayoutElement.ALIGN_CENTER then |
39 | posX = self.absSize[1]*0.5 - totalWidth*0.5 |
40 | elseif self.alignmentX == FlowLayoutElement.ALIGN_RIGHT then |
41 | posX = self.absSize[1] - totalWidth |
42 | end |
43 | |
44 | local currentX = posX |
45 | local currentLine = 0 |
46 | for currentIndex, element in ipairs(self.elements) do |
47 | if self:getIsElementIncluded(element, ignoreVisibility) then |
48 | local x = currentX + element.margin[1] |
49 | |
50 | -- Assume it goes on current line |
51 | element.line = currentLine |
52 | |
53 | -- Check wrapping but only on left alignment, because the math does not support the others |
54 | if ((x + element.absSize[1]) - self.absSize[1]) > 0.0001 and self.alignmentX == FlowLayoutElement.ALIGN_LEFT then |
55 | x = 0 |
56 | currentLine = currentLine + 1 |
57 | |
58 | -- Find where we can cut |
59 | local cutIndex = currentIndex -- left of N |
60 | for i = currentIndex, 1, -1 do |
61 | local testElement = self.elements[i] |
62 | if testElement.line ~= nil or i == currentIndex then |
63 | if not testElement.disallowFlowCut then |
64 | cutIndex = i |
65 | break |
66 | end |
67 | end |
68 | end |
69 | |
70 | for i = cutIndex, math.max(currentIndex - 1, 1) do -- skip currentIndex, we do that below |
71 | local moveElement = self.elements[i] |
72 | if moveElement.line ~= nil then |
73 | |
74 | if i ~= cutIndex then |
75 | x = x + moveElement.margin[1] |
76 | end |
77 | |
78 | moveElement:setPosition(x, nil) |
79 | moveElement.line = currentLine |
80 | |
81 | x = x + moveElement.absSize[1] + moveElement.margin[3] |
82 | end |
83 | end |
84 | |
85 | element.line = currentLine |
86 | |
87 | if cutIndex ~= currentIndex then |
88 | x = x + element.margin[1] |
89 | end |
90 | end |
91 | |
92 | element:setPosition(x, nil) |
93 | x = x + element.absSize[1] + element.margin[3] |
94 | |
95 | currentX = x |
96 | else |
97 | -- used to quickly check inclusion in next steps |
98 | element.line = nil |
99 | end |
100 | end |
101 | |
102 | local numLines = currentLine + 1 |
103 | local totalContentHeight = numLines * lineHeight |
104 | |
105 | -- Initial Y |
106 | local posY = 0 |
107 | if self.alignmentY == FlowLayoutElement.ALIGN_MIDDLE then |
108 | posY = self.absSize[2] * 0.5 - totalContentHeight * 0.5 |
109 | elseif self.alignmentY == FlowLayoutElement.ALIGN_TOP then |
110 | posY = self.absSize[2] - totalContentHeight |
111 | end |
112 | |
113 | for _, element in pairs(self.elements) do |
114 | if element.line ~= nil then |
115 | -- Inverted Y line as 0 is at bottom |
116 | local y = posY + (numLines - element.line - 1) * lineHeight |
117 | |
118 | if self.alignmentY == FlowLayoutElement.ALIGN_MIDDLE then |
119 | y = y + math.max(0, (lineHeight - element.absSize[2]) * 0.5) |
120 | elseif self.alignmentY == FlowLayoutElement.ALIGN_TOP then |
121 | y = y + math.max(0, lineHeight - element.absSize[2]) |
122 | end |
123 | |
124 | element:setPosition(nil, y) |
125 | end |
126 | end |
127 | end |