Serious bug in ui.lua v1.5

I was seeing “unexpected” results when I was generating newButton’s while reusing the params table to set the button config parameters.

The following example code should show the issue:

[lua]local ui = require(“ui”)

local params = {}
params.default = “buttonBlue.png”
params.over = “buttonBlueOver.png”
params.x = 150
params.y = 150
params.text = “No Way”
params.size = 20

local b = ui.newButton(params)

params.size = 10

b:setText(“Way”)[/lua]

What happens here is that the size of the displayed button is changed to 10 when the setText() is called.

The reason is that in ui.lua, the params values for size are not copied to local values for the closure, and the value for size is read from the params directly. The closure is over the params-reference, which means that if I change the values of the params table properties, that they will be incorporated in the setText function.

I believe that the solution is to copy all params values out of that table to local values in newButton(), and to let the setText() function only work on those local values thru a closure.

-FrankS.
[import]uid: 8093 topic_id: 7496 reply_id: 307496[/import]

The changes I made to the newButton() in ui.lua to mediate this closure issue are the following:
[lua]---------------
– Button class

function newButton( params )
local button, default, over, size, font, textColor, offset, emboss

if ( params.size and type(params.size) == “number” ) then size=params.size else size=20 end
if ( params.font ) then font=params.font else font=native.systemFontBold end
textColor={ 255, 255, 255, 255 }
if ( params.textColor and type(params.textColor)==“table”) then
for i = 1,4 do
textColor[i] = params.textColor[i] or textColor[i]
end
end

– Optional vertical correction for fonts with unusual baselines (I’m looking at you, Zapfino)
if ( params.offset and type(params.offset) == “number” ) then offset=params.offset else offset = 0 end
emboss = params.emboss

if params.default then
button = display.newGroup()
default = display.newImage( params.default )
button:insert( default, true )
end

if params.over then
over = display.newImage( params.over )
over.isVisible = false
button:insert( over, true )
end

– Public methods
function button:setText( newText )

local labelText = self.text
if ( labelText ) then
labelText:removeSelf()
self.text = nil
end

local labelShadow = self.shadow
if ( labelShadow ) then
labelShadow:removeSelf()
self.shadow = nil
end

local labelHighlight = self.highlight
if ( labelHighlight ) then
labelHighlight:removeSelf()
self.highlight = nil
end

if ( emboss ) then
– Make the label text look “embossed” (also adjusts effect for textColor brightness)
local textBrightness = ( textColor[1] + textColor[2] + textColor[3] ) / 3

labelHighlight = display.newText( newText, 0, 0, font, size )
if ( textBrightness > 127) then
labelHighlight:setTextColor( 255, 255, 255, 20 )
else
labelHighlight:setTextColor( 255, 255, 255, 140 )
end
button:insert( labelHighlight, true )
labelHighlight.x = labelHighlight.x + 1.5; labelHighlight.y = labelHighlight.y + 1.5 + offset
self.highlight = labelHighlight

labelShadow = display.newText( newText, 0, 0, font, size )
if ( textBrightness > 127) then
labelShadow:setTextColor( 0, 0, 0, 128 )
else
labelShadow:setTextColor( 0, 0, 0, 20 )
end
button:insert( labelShadow, true )
labelShadow.x = labelShadow.x - 1; labelShadow.y = labelShadow.y - 1 + offset
self.shadow = labelShadow
end

labelText = display.newText( newText, 0, 0, font, size )
labelText:setTextColor( textColor[1], textColor[2], textColor[3], textColor[4] )
button:insert( labelText, true )
labelText.y = labelText.y + offset
self.text = labelText
end

if params.text then
button:setText( params.text )
end

if ( params.onPress and ( type(params.onPress) == “function” ) ) then
button._onPress = params.onPress
end
if ( params.onRelease and ( type(params.onRelease) == “function” ) ) then
button._onRelease = params.onRelease
end

if (params.onEvent and ( type(params.onEvent) == “function” ) ) then
button._onEvent = params.onEvent
end

– Set button as a table listener by setting a table method and adding the button as its own table listener for “touch” events
button.touch = newButtonHandler
button:addEventListener( “touch”, button )

if params.x then
button.x = params.x
end

if params.y then
button.y = params.y
end

if params.id then
button._id = params.id
end

return button
end[/lua]

Please use kdiff3 or some other diff-viewer to view the changes (kdiff3 is a very nice tool…)

-FrankS.

[import]uid: 8093 topic_id: 7496 reply_id: 26542[/import]