Skip to content

Commit cee0116

Browse files
authored
Merge pull request #109 from megagrump/cleanup
reduce GC churn
2 parents 75df0cd + 54b676d commit cee0116

File tree

4 files changed

+371
-343
lines changed

4 files changed

+371
-343
lines changed

Internal/Core/IdCache.lua

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--[[
2+
3+
MIT License
4+
5+
Copyright (c) 2019-2021 Love2D Community <love2d.org>
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.
24+
25+
--]]
26+
27+
local IdCache = {}
28+
IdCache.__index = IdCache
29+
30+
function IdCache:get(parentId, id)
31+
local pId = self._ids[parentId]
32+
local resultId = pId and pId[id]
33+
34+
if resultId then return resultId end
35+
36+
resultId = ("%s.%s"):format(parentId, id)
37+
if pId then
38+
pId[id] = resultId
39+
else
40+
self._ids[parentId] = { [id] = resultId }
41+
end
42+
43+
return resultId
44+
end
45+
46+
return function()
47+
return setmetatable({
48+
_ids = {}
49+
}, IdCache)
50+
end

Internal/UI/Button.lua

+132-139
Original file line numberDiff line numberDiff line change
@@ -41,212 +41,205 @@ local Window = require(SLAB_PATH .. '.Internal.UI.Window')
4141

4242
local Button = {}
4343

44-
local Pad = 10.0
45-
local MinWidth = 75.0
46-
local Radius = 8.0
47-
local ClickedId = nil
48-
49-
function Button.Begin(Label, Options)
50-
local StatHandle = Stats.Begin('Button', 'Slab')
51-
52-
Options = Options == nil and {} or Options
53-
Options.Tooltip = Options.Tooltip == nil and "" or Options.Tooltip
54-
Options.Rounding = Options.Rounding == nil and Style.ButtonRounding or Options.Rounding
55-
Options.Invisible = Options.Invisible == nil and false or Options.Invisible
56-
Options.W = Options.W == nil and nil or Options.W
57-
Options.H = Options.H == nil and nil or Options.H
58-
Options.Disabled = Options.Disabled == nil and false or Options.Disabled
59-
Options.Image = Options.Image or nil
60-
Options.Color = Options.Color or Style.ButtonColor
61-
Options.HoverColor = Options.HoverColor or Style.ButtonHoveredColor
62-
Options.PressColor = Options.PressColor or Style.ButtonPressedColor
63-
Options.PadX = Options.PadX or Pad * 2.0
64-
Options.PadY = Options.PadY or Pad * 0.5
65-
Options.VLines = Options.VLines or 1
66-
67-
local Id = Window.GetItemId(Label)
68-
local W, H = Button.GetSize(Label)
69-
H = H * Options.VLines
70-
local LabelW = Style.Font:getWidth(Label)
71-
local FontHeight = Style.Font:getHeight() * Options.VLines
72-
local TextColor = Options.Disabled and Style.ButtonDisabledTextColor or nil
44+
local PAD = 10.0
45+
local MINWIDTH = 75.0
46+
local RADIUS = 8.0
47+
local EMPTY = {}
48+
local IGNORE = { Ignore = true }
49+
50+
local clickedId = nil
51+
local labelColor = {}
52+
53+
function Button.Begin(label, options)
54+
local statHandle = Stats.Begin('Button', 'Slab')
55+
56+
options = options or EMPTY
57+
local width, height = options.W, options.H
58+
local disabled = options.Disabled
59+
local image = options.Image
60+
local color = options.Color or Style.ButtonColor
61+
local hoverColor = options.HoverColor or Style.ButtonHoveredColor
62+
local pressColor = options.PressColor or Style.ButtonPressedColor
63+
local padX = options.PadX or PAD * 2.0
64+
local padY = options.PadY or PAD * 0.5
65+
local vLines = options.VLines or 1
66+
67+
local id = Window.GetItemId(label)
68+
local w, h = Button.GetSize(label)
69+
h = h * vLines
7370

7471
-- If a valid image was specified, then adjust the button size to match the requested image size. Also takes into account any sub UVs.
75-
local ImageW, ImageH = W, H
76-
if Options.Image ~= nil then
77-
local Object = Options.Image.Image and Options.Image.Image or Options.Image.Path
78-
ImageW, ImageH = Image.GetSize(Object)
72+
local imageW, imageH = w, h
73+
if image ~= nil then
74+
imageW, imageH = Image.GetSize(image.Image or image.Path)
7975

80-
ImageW = Options.Image.SubW or ImageW
81-
ImageH = Options.Image.SubH or ImageH
76+
imageW = image.SubW or imageW
77+
imageH = image.SubH or imageH
8278

83-
ImageW = Options.W or ImageW
84-
ImageH = Options.H or ImageH
79+
imageW = width or imageW
80+
imageH = height or imageH
8581

86-
Options.Image.W = ImageW
87-
Options.Image.H = ImageH
82+
image.W = imageW
83+
image.H = imageH
8884

89-
if ImageW > 0 and ImageH > 0 then
90-
W = ImageW + Options.PadX
91-
H = ImageH + Options.PadY
85+
if imageW > 0 and imageH > 0 then
86+
w = imageW + padX
87+
h = imageH + padY
9288
end
9389
end
9490

95-
W = Options.W or W
96-
H = Options.H or H
91+
w, h = LayoutManager.ComputeSize(width or w, height or h)
92+
LayoutManager.AddControl(w, h, 'Button')
9793

98-
W, H = LayoutManager.ComputeSize(W, H)
99-
LayoutManager.AddControl(W, H, 'Button')
94+
local x, y = Cursor.GetPosition()
10095

101-
local X, Y = Cursor.GetPosition()
96+
local result = false
10297

103-
local Result = false
104-
local Color = Options.Color
98+
do
99+
local mouseX, mouseY = Window.GetMousePosition()
100+
if not Window.IsObstructedAtMouse() and x <= mouseX and mouseX <= x + w and y <= mouseY and mouseY <= y + h then
101+
Tooltip.Begin(options.Tooltip or "")
102+
Window.SetHotItem(id)
105103

106-
local MouseX, MouseY = Window.GetMousePosition()
107-
if not Window.IsObstructedAtMouse() and X <= MouseX and MouseX <= X + W and Y <= MouseY and MouseY <= Y + H then
108-
Tooltip.Begin(Options.Tooltip)
109-
Window.SetHotItem(Id)
104+
if not disabled then
105+
if not Utility.IsMobile() then
106+
color = hoverColor
107+
end
110108

111-
if not Options.Disabled then
112-
if not Utility.IsMobile() then
113-
Color = Options.HoverColor
114-
end
109+
if clickedId == id then
110+
color = pressColor
111+
end
115112

116-
if ClickedId == Id then
117-
Color = Options.PressColor
118-
end
113+
if Mouse.IsClicked(1) then
114+
clickedId = id
115+
end
119116

120-
if Mouse.IsClicked(1) then
121-
ClickedId = Id
122-
end
123-
124-
if Mouse.IsReleased(1) and ClickedId == Id then
125-
Result = true
126-
ClickedId = nil
117+
if Mouse.IsReleased(1) and clickedId == id then
118+
result = true
119+
clickedId = nil
120+
end
127121
end
128122
end
129123
end
130124

131-
local LabelX = X + (W * 0.5) - (LabelW * 0.5)
132-
133-
if not Options.Invisible then
125+
if not options.Invisible then
134126
-- Draw the background.
135-
DrawCommands.Rectangle('fill', X, Y, W, H, Color, Options.Rounding)
127+
DrawCommands.Rectangle('fill', x, y, w, h, color, options.Rounding or Style.ButtonRounding)
136128

137129
-- Draw the label or image. The layout of this control was already computed above. Ignore when adding sub-controls
138130
-- such as text or an image.
139-
local CursorX, CursorY = Cursor.GetPosition()
140-
LayoutManager.Begin('Ignore', {Ignore = true})
141-
if Options.Image ~= nil then
142-
Cursor.SetX(X + W * 0.5 - ImageW * 0.5)
143-
Cursor.SetY(Y + H * 0.5 - ImageH * 0.5)
144-
Image.Begin(Id .. '_Image', Options.Image)
131+
local cursorX, cursorY = Cursor.GetPosition()
132+
LayoutManager.Begin('Ignore', IGNORE)
133+
if image ~= nil then
134+
Cursor.SetX(x + w * 0.5 - imageW * 0.5)
135+
Cursor.SetY(y + h * 0.5 - imageH * 0.5)
136+
Image.Begin(id .. '_Image', image)
145137
else
146-
Cursor.SetX(floor(LabelX))
147-
Cursor.SetY(floor(Y + (H * 0.5) - (FontHeight * 0.5)))
148-
Text.Begin(Label, {Color = TextColor})
138+
local labelX = x + (w * 0.5) - (Style.Font:getWidth(label) * 0.5)
139+
local fontHeight = Style.Font:getHeight() * vLines
140+
Cursor.SetX(floor(labelX))
141+
Cursor.SetY(floor(y + (h * 0.5) - (fontHeight * 0.5)))
142+
labelColor.color = disabled and Style.ButtonDisabledTextColor or nil
143+
Text.Begin(label, LabelColor)
149144
end
150145
LayoutManager.End()
151146

152-
Cursor.SetPosition(CursorX, CursorY)
147+
Cursor.SetPosition(cursorX, cursorY)
153148
end
154149

155-
Cursor.SetItemBounds(X, Y, W, H)
156-
Cursor.AdvanceY(H)
150+
Cursor.SetItemBounds(x, y, w, h)
151+
Cursor.AdvanceY(h)
157152

158-
Window.AddItem(X, Y, W, H, Id)
153+
Window.AddItem(x, y, w, h, id)
159154

160-
Stats.End(StatHandle)
155+
Stats.End(statHandle)
161156

162-
return Result
157+
return result
163158
end
164159

165-
function Button.BeginRadio(Label, Options)
166-
local StatHandle = Stats.Begin('RadioButton', 'Slab')
160+
function Button.BeginRadio(label, options)
161+
local statHandle = Stats.Begin('RadioButton', 'Slab')
167162

168-
Label = Label == nil and "" or Label
163+
label = label or ""
169164

170-
Options = Options == nil and {} or Options
171-
Options.Index = Options.Index == nil and 0 or Options.Index
172-
Options.SelectedIndex = Options.SelectedIndex == nil and 0 or Options.SelectedIndex
173-
Options.Tooltip = Options.Tooltip == nil and "" or Options.Tooltip
165+
options = options or EMPTY
166+
local index = options.index or 0
167+
local selectedIndex = options.SelectedIndex or 0
174168

175-
local Result = false
176-
local Id = Window.GetItemId(Label)
177-
local W, H = Radius * 2.0, Radius * 2.0
178-
local IsObstructed = Window.IsObstructedAtMouse()
179-
local Color = Style.ButtonColor
180-
local MouseX, MouseY = Window.GetMousePosition()
169+
local result = false
170+
local id = Window.GetItemId(label)
171+
local w, h = RADIUS * 2.0, RADIUS * 2.0
172+
local isObstructed = Window.IsObstructedAtMouse()
173+
local color = Style.ButtonColor
174+
local mouseX, mouseY = Window.GetMousePosition()
181175

182-
if Label ~= "" then
183-
local TextW, TextH = Text.GetSize(Label)
184-
W = W + Cursor.PadX() + TextW
185-
H = max(H, TextH)
176+
if label ~= "" then
177+
local TextW, TextH = Text.GetSize(label)
178+
w = w + Cursor.PadX() + TextW
179+
h = max(h, TextH)
186180
end
187181

188-
LayoutManager.AddControl(W, H, 'Radio')
182+
LayoutManager.AddControl(w, h, 'Radio')
189183

190-
local X, Y = Cursor.GetPosition()
191-
local CenterX, CenterY = X + Radius, Y + Radius
192-
local DX = MouseX - CenterX
193-
local DY = MouseY - CenterY
194-
local HoveredButton = not IsObstructed and (DX * DX) + (DY * DY) <= Radius * Radius
195-
if HoveredButton then
196-
Color = Style.ButtonHoveredColor
184+
local x, y = Cursor.GetPosition()
185+
local centerX, centerY = x + RADIUS, y + RADIUS
186+
local dx = mouseX - centerX
187+
local dy = mouseY - centerY
188+
if not isObstructed and (dx * dx) + (dy * dy) <= RADIUS * RADIUS then
189+
color = Style.ButtonHoveredColor
197190

198-
if ClickedId == Id then
199-
Color = Style.ButtonPressedColor
191+
if clickedId == id then
192+
color = Style.ButtonPressedColor
200193
end
201194

202195
if Mouse.IsClicked(1) then
203-
ClickedId = Id
196+
clickedId = id
204197
end
205198

206-
if Mouse.IsReleased(1) and ClickedId == Id then
207-
Result = true
208-
ClickedId = nil
199+
if Mouse.IsReleased(1) and clickedId == id then
200+
result = true
201+
clickedId = nil
209202
end
210203
end
211204

212-
DrawCommands.Circle('fill', CenterX, CenterY, Radius, Color)
205+
DrawCommands.Circle('fill', centerX, centerY, RADIUS, color)
213206

214-
if Options.Index > 0 and Options.Index == Options.SelectedIndex then
215-
DrawCommands.Circle('fill', CenterX, CenterY, Radius * 0.7, Style.RadioButtonSelectedColor)
207+
if index > 0 and index == selectedIndex then
208+
DrawCommands.Circle('fill', centerX, centerY, RADIUS * 0.7, Style.RadioButtonSelectedColor)
216209
end
217210

218-
if Label ~= "" then
219-
local CursorY = Cursor.GetY()
220-
Cursor.AdvanceX(Radius * 2.0)
221-
LayoutManager.Begin('Ignore', {Ignore = true})
222-
Text.Begin(Label)
211+
if label ~= "" then
212+
local cursorY = Cursor.GetY()
213+
Cursor.AdvanceX(RADIUS * 2.0)
214+
LayoutManager.Begin('Ignore', IGNORE)
215+
Text.Begin(label)
223216
LayoutManager.End()
224-
Cursor.SetY(CursorY)
217+
Cursor.SetY(cursorY)
225218
end
226219

227-
if not IsObstructed and X <= MouseX and MouseX <= X + W and Y <= MouseY and MouseY <= Y + H then
228-
Tooltip.Begin(Options.Tooltip)
229-
Window.SetHotItem(Id)
220+
if not isObstructed and x <= mouseX and mouseX <= x + w and y <= mouseY and mouseY <= y + h then
221+
Tooltip.Begin(options.Tooltip or "")
222+
Window.SetHotItem(id)
230223
end
231224

232-
Cursor.SetItemBounds(X, Y, W, H)
233-
Cursor.AdvanceY(H)
225+
Cursor.SetItemBounds(x, y, w, h)
226+
Cursor.AdvanceY(h)
234227

235-
Window.AddItem(X, Y, W, H)
228+
Window.AddItem(x, y, w, h)
236229

237-
Stats.End(StatHandle)
230+
Stats.End(statHandle)
238231

239-
return Result
232+
return result
240233
end
241234

242-
function Button.GetSize(Label)
243-
local W = Style.Font:getWidth(Label)
244-
local H = Style.Font:getHeight()
245-
return max(W, MinWidth) + Pad * 2.0, H + Pad * 0.5
235+
function Button.GetSize(label)
236+
local w = Style.Font:getWidth(label)
237+
local h = Style.Font:getHeight()
238+
return max(w, MINWIDTH) + PAD * 2.0, h + PAD * 0.5
246239
end
247240

248241
function Button.ClearClicked()
249-
ClickedId = nil
242+
clickedId = nil
250243
end
251244

252245
return Button

0 commit comments

Comments
 (0)