Share Your Code

Enhanced UI Library (ui.lua)

Posted by PixelEnvision, Posted on May 31, 2011, Last updated October 1, 2011

UPDATED to 2.4

Most current copy of and ZIP download available at my website.
http://www.pixelenvision.com/1562/coronasdk-enhanced-ui-library-ui-lua/

NEW: Added event support, now returns even.target, event.x & event.y values. You can use x/y values to provide different actions based on the coordinates of the touch event reative to the x/y size of the button image.

NEW: isActive state enhanced, so the button can be enabled/disabled without checking current isActive state with if-then.

See in code comments for the version history.

There are many versions/editions of ui.lua is floating around. Although it is originally created to serve in CoronaSDK samples, in time that library evolved with user contributions. When it's my time to try it for the buttons in my upcoming app, I have decided to combine all the best parts and enhance it to fit my needs which is the one I'm sharing here now. Here is the brief history of the provided ui.lua

So, with this one you can pull your button images from sprite sheets. Or if you wish, you may use same image as the button and also for the over state using alpha and/or scaling functions and save some more texture memory.

local btn = ui.newButton{
defaultSrc = buttonimg,
overSrc = overimg,
overAlpha = .5,
overScale = 1.1,
onEvent = ButtonTouch,
id = "Button",
}

Above code will prove you a button that scales up and becomes transparent when clicked. For buttonimg & overimg you may use same png file or a display object taken from a sprite. Of course it is still possible to use different images as before.

If you have any questions or notice problems with the code, please drop a line here...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
-- ui.lua (currently includes Button class with labels, font selection and optional event model)
 
-- Version 2.4
-- Based on the folowing original provided by Ansca Inc.
-- Version 1.5 (works with multitouch, adds setText() method to buttons)
--
-- Copyright (C) 2010 ANSCA Inc. All Rights Reserved.
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of 
-- this software and associated documentation files (the "Software"), to deal in the 
-- Software without restriction, including without limitation the rights to use, copy, 
-- modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
-- and to permit persons to whom the Software is furnished to do so, subject to the 
-- following conditions:
-- 
-- The above copyright notice and this permission notice shall be included in all copies 
-- or substantial portions of the Software.
-- 
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
-- DEALINGS IN THE SOFTWARE.
 
-- Version 1.6 Works with Dynamic Scaling.
-- Based on the work edited by William Flagello, williamflagello.com
-- Original from https://developer.anscamobile.com/code/ui-library
--
-- Version 1.7 Dynamic Scaling text fixes by Jonathan Bebe
-- http://developer.anscamobile.com/forum/2010/12/17/easily-make-your-text-sharp-retina-displays#comment-18164
-- Provided in Ghosts & Monsters Sample Project
--
-- Version 1.71 Retina Updates by Jonathan Bebe
-- http://developer.anscamobile.com/forum/2010/12/17/easily-make-your-text-sharp-retina-displays#comment-38284
-- Adapted to 1.7 base code by E. Gonenc, pixelenvision.com
--
-- Version 1.8 added support for providing already realized display-objects for use in Tiled/Lime
-- Based on the file changed by Frank Siebenlist
-- http://developer.anscamobile.com/forum/2011/02/19/enhanced-uilua-v15
-- Adapted to 1.7 base code by E. Gonenc, pixelenvision.com
--
-- Version 1.9 
-- Added transparency & scaling options to use as over state. newLabel updated to support retina text.
-- Edited by E. Gonenc, pixelenvision.com
--
-- Version 1.91 
-- Added suggested fix for overlapping buttons by Jonathan Bebe
-- http://jonbeebe.net/to-return-true-or-not-to
-- Adapted by E. Gonenc, pixelenvision.com
--
-- Version 2.02
-- Button text will now follow scaling & alpha states of over button
-- Edited by E. Gonenc, pixelenvision.com
--
-- Version 2.1
-- Added suggested .isActive update by monoxgas http://developer.anscamobile.com/code/enhanced-ui-library-uilua#comment-49272
-- Edited by E. Gonenc, pixelenvision.com
--
-- Version 2.2
-- Updated to eliminate the use of LUAs deprecated module() function. This is an internal change only, usage stays the same.
-- http://blog.anscamobile.com/2011/09/a-better-approach-to-external-modules/
-- Edited by E. Gonenc, pixelenvision.com
--
-- Version 2.3
-- Updated to use object.contentBounds instead of deprecated object.stageBounds
-- Added event support, now returns even.target, event.x & event.y values. You can use x/y values to provide different actions
-- based on the coordinates of the touch event reative to the x/y size of the button image.
-- Edited by E. Gonenc, pixelenvision.com
--
-- Version 2.4
-- isActive state enhanced to button can be enabled/disabled without checking current isActive state with if-then.
-- ie. btn.isActive = true (Default state, button is enabled) btn.isActive = false (button is disabled, no animation and action)
-- Edited by E. Gonenc, pixelenvision.com
 
local M = {}
 
-------------
-- convenience test functions added by Frank.
 
local coronaMetaTable = getmetatable(display.getCurrentStage())
 
--- Test function that returns whether object is a Corona display object.
-- Note that all Corona types seem to share the same metatable...
local isDisplayObject = function(o)
        return type(o) == "table" and getmetatable(o) == coronaMetaTable
end
 
-----------------
-- Helper function for newButton utility function below
local function newButtonHandler( self, event )
 
        local result = true
 
        local default = self[1]
        local over = self[2]
        local txt1,txt2,txt3
        
        local OX,OY,SX,SY,SM
        if self[3] then txt1 = self[3] end
        if self[4] then txt2 = self[4] end
        if self[5] then txt3 = self[5] end
        if txt1 or txt2 or txt3 then
        if display.contentScaleX < 1.0 or display.contentScaleY < 1.0 then SM = 2 else SM = 1 end 
                OX,OY = (over.xScale/default.xScale),(over.yScale/default.yScale)
                SX,SY = (default.xScale/over.xScale),(default.yScale/over.yScale)
        end
 
        -- General "onEvent" function overrides onPress and onRelease, if present
        local onEvent = self._onEvent
 
        local onPress = self._onPress
        local onRelease = self._onRelease
 
        local buttonEvent = {}
        if (self._id) then
                buttonEvent.id = self._id
        end
                buttonEvent.isActive = self.isActive
                buttonEvent.target = self
        local phase = event.phase
        if self.isActive then
        if "began" == phase then
                if over then 
                        default.isVisible = false
                        over.isVisible = true
                if txt1 then txt1:scale(OX,OY);txt1.alpha = over.alpha end
                if txt2 then txt2:scale(OX,OY);txt2.alpha = over.alpha end
                if txt3 then txt3:scale(OX,OY);txt3.alpha = over.alpha end
                end
 
                if onEvent then
                        buttonEvent.phase = "press"
                        buttonEvent.x = event.x - self.contentBounds.xMin
                        buttonEvent.y = event.y - self.contentBounds.yMin
                        result = onEvent( buttonEvent )
                elseif onPress then
                        result = onPress( event )
                end
 
                -- Subsequent touch events will target button even if they are outside the contentBounds of button
                display.getCurrentStage():setFocus( self, event.id )
                self.isFocus = true
                
        elseif self.isFocus then
                local bounds = self.contentBounds
                local x,y = event.x,event.y
                local isWithinBounds = 
                        bounds.xMin <= x and bounds.xMax >= x and bounds.yMin <= y and bounds.yMax >= y
 
                if "moved" == phase then
                        if over then
                                -- The rollover image should only be visible while the finger is within button's stageBounds
                                default.isVisible = not isWithinBounds
                                over.isVisible = isWithinBounds
                        if txt1 and not isWithinBounds and txt1.xScale*SM == OX then txt1:scale(SX,SY);txt1.alpha = default.alpha
                        elseif txt1 and isWithinBounds and txt1.xScale*SM ~= OX then txt1:scale(OX,OY);txt1.alpha = over.alpha end
                        if txt2 and not isWithinBounds and txt2.xScale*SM == OX then txt2:scale(SX,SY);txt2.alpha = default.alpha
                        elseif txt2 and isWithinBounds and txt2.xScale*SM ~= OX then txt2:scale(OX,OY);txt2.alpha = over.alpha end
                        if txt3 and not isWithinBounds and txt3.xScale*SM == OX then txt3:scale(SX,SY);txt3.alpha = default.alpha
                        elseif txt3 and isWithinBounds and txt3.xScale*SM ~= OX then txt3:scale(OX,OY);txt3.alpha = over.alpha end
                        end
                        
                elseif "ended" == phase or "cancelled" == phase then 
                        if over then 
                                default.isVisible = true
                                over.isVisible = false
                        if txt1 and txt1.xScale*SM == OX then txt1:scale(SX,SY);txt1.alpha = default.alpha end
                        if txt2 and txt2.xScale*SM == OX then txt2:scale(SX,SY);txt2.alpha = default.alpha end
                        if txt3 and txt3.xScale*SM == OX then txt3:scale(SX,SY);txt3.alpha = default.alpha end
                        end
                        
                        if "ended" == phase then
                                -- Only consider this a "click" if the user lifts their finger inside button's stageBounds
                                if isWithinBounds then
                                        if onEvent then
                                                buttonEvent.phase = "release"
                                                buttonEvent.x = event.x - bounds.xMin
                                                buttonEvent.y = event.y - bounds.yMin
                                                result = onEvent( buttonEvent )
                                        elseif onRelease then
                                                result = onRelease( event )
                                        end
                                end
                        end
                        
                        -- Allow touch events to be sent normally to the objects they "hit"
                        display.getCurrentStage():setFocus( self, nil )
                        self.isFocus = false
                end
        end
        end
        return true
 
end
 
 
---------------
-- Button class
 
local function newButton( params )
        local button, defaultSrc , defaultX , defaultY , overSrc , overX , overY , overScale , overAlpha , size, font, textColor, offset
        
        local sizeDivide = 1
           local sizeMultiply = 1
 
        if display.contentScaleX < 1.0 or display.contentScaleY < 1.0 then
                sizeMultiply = 2
                sizeDivide = 0.5                
        end
        
        if params.defaultSrc then
                button = display.newGroup()
                if isDisplayObject(params.defaultSrc) then
                        default = params.defaultSrc
                else
                        default = display.newImageRect ( params.defaultSrc , params.defaultX , params.defaultY )
                end             
                button:insert( default, false )
        end
        
        if params.overSrc then
                if isDisplayObject(params.overSrc) then
                        over = params.overSrc
                else
                        over = display.newImageRect ( params.overSrc , params.overX , params.overY )
                end
                if params.overAlpha then
                        over.alpha = params.overAlpha
                end
                if params.overScale then
                        over:scale(params.overScale,params.overScale)
                end
                over.isVisible = false
                button:insert( over, false )    
        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 ( 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
                if ( params.textColor ) then textColor=params.textColor else textColor={ 255, 255, 255, 255 } end
                
                size = size * sizeMultiply
                
                -- 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
                
                if ( params.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
                        
                        labelHighlight.xScale = sizeDivide; labelHighlight.yScale = sizeDivide
                        labelShadow.xScale = sizeDivide; labelShadow.yScale = sizeDivide
                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
                
                labelText.xScale = sizeDivide; labelText.yScale = sizeDivide
        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 to active (meaning, can be pushed)
        button.isActive = true
        
        -- 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
M.newButton = newButton
 
--------------
-- Label class
 
local function newLabel( params )
        local labelText
        local size, font, textColor, align
        local t = display.newGroup()
        
        local sizeDivide = 1
           local sizeMultiply = 1
 
        if ( params.bounds ) then
                local bounds = params.bounds
                local left = bounds[1]
                local top = bounds[2]
                local width = bounds[3]
                local height = bounds[4]
        
                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
                if ( params.textColor ) then textColor=params.textColor else textColor={ 255, 255, 255, 255 } end
                if ( params.offset and type(params.offset) == "number" ) then offset=params.offset else offset = 0 end
                if ( params.align ) then align = params.align else align = "center" end
                
                if ( params.text ) then
                        labelText = display.newText( params.text, 0, 0, font, size * 2 )
                        labelText.xScale = 0.5; labelText.yScale = 0.5
                        labelText:setTextColor( textColor[1], textColor[2], textColor[3], textColor[4] )
                        t:insert( labelText )
                        -- TODO: handle no-initial-text case by creating a field with an empty string?
        
                        if ( align == "left" ) then
                                labelText.x = left + labelText.contentWidth * 0.5
                        elseif ( align == "right" ) then
                                labelText.x = (left + width) - labelText.contentWidth * 0.5
                        else
                                labelText.x = ((2 * left) + width) * 0.5
                        end
                end
                
                labelText.y = top + labelText.contentHeight * 0.5
 
                -- Public methods
                function t:setText( newText )
                        if ( newText ) then
                                labelText.text = newText
                                
                                if ( "left" == align ) then
                                        labelText.x = left + labelText.contentWidth * 0.5
                                elseif ( "right" == align ) then
                                        labelText.x = (left + width) - labelText.contentWidth * 0.5
                                else
                                        labelText.x = ((2 * left) + width) * 0.5
                                end
                        end
                end
                
                function t:setTextColor( r, g, b, a )
                        local newR = 255
                        local newG = 255
                        local newB = 255
                        local newA = 255
 
                        if ( r and type(r) == "number" ) then newR = r end
                        if ( g and type(g) == "number" ) then newG = g end
                        if ( b and type(b) == "number" ) then newB = b end
                        if ( a and type(a) == "number" ) then newA = a end
 
                        labelText:setTextColor( r, g, b, a )
                end
        end
        
        -- Return instance (as display group)
        return t
        
end
M.newLabel = newLabel
 
return M


Replies

doubleslashdesign
User offline. Last seen 2 days 1 min ago. Offline
Joined: 27 Nov 2010

I took the current Director sample renamed the ui.lua file and replaced it with yours.

the images on the screen no longer loaded and the screen text was all jumbled at the top of the screen.
Do you think you may have missed something in the copy / paste ?

Larry

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

Hi Larry,

That is normal as director sample uses original unedited ui.lua file.

When William Flagello added dynamic scaling support, he changed the syntax as it requires new parameters which is the size of supplied button image..

OLD SYNTAX (Director uses that)
local bt01 = ui.newButton{
default = "bt_moveFromLeft.png",
over = "bt_moveFromLeft.png",
onEvent = bt01t,
id = "bt01"
}

NEW SYNTAX
local bt01 = ui.newButton{
defaultSrc = "bt_moveFromLeft.png",
defaultX = 180,
defaultY = 82,
overSrc = "bt_moveFromLeft.png",
overX = 180,
overY = 82,
onEvent = bt01t,
id = "bt01"
}

Same changes required for included samples of CoronaSDK.

I hope this helps :)

yuewah
User offline. Last seen 2 years 18 weeks ago. Offline
Joined: 4 Dec 2010

1
2
-- set button to active (meaning, can be pushed)
        button.isActive = true

it is not functional when button.isActive = false

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

You are right, it has no function within ui.lua. But it looks like it just assigns an isActive state to the button for use in the main code.

I've taken a look at the originals and it looks like that code is added by Jonathan Bebe. I've found it's actual use in tilt monster code.

-- Setup "Play Now" Button
local touchPlayNowBtn = function( event )
if event.phase == "release" and playNowBtn.isActive == true then

playNowBtn.isActive = false

--rest of his button handler code

end

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

Hello, I needed my button to scale down on click so I tried this...

but the Text on the button does not scale along with the button.

It looks pretty bad that way. Can that be added in?

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

Sure, I'll take look at that as soon as I have some spare time...

But for a quick fix, if your text on the button is not dynamic (fx, if it always says "Play", etc.) just embed the text on the button image itself.

That will also save you some texture memory (even if it's very small, still counts) from the text object.

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

Yeah my text is dynamic. Play Level ...

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

Actually, that was bugging me too... So, decided to spare some time for this. :)

I'll update the code shortly with two more bonuses, please let me know how it goes...

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

Thanks for the quick service ;)

I tried it and it worked much better. I tested it on my iphone as well.

There is one thing: If you touch the button and slide your finger off, the image gets bigger but the text stays smaller. The text doesn't go back to original size until you release your finger. This is the same in the Simulator.

Now I doubt anyone would do this but just wanted you to be aware. It is probably a simple fix.

Thanks again... now what are the 2 more bonuses?? I am curious!

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

Not a problem ;)

It should be ok now...

Bonuses were: 1. alpha support for button text 2. overlapping buttons fix...

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

whoa. It worked fine in the Simulator.

I tested it on my iphone 4, when i touched the button the text went to twice or three times the size!

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

I saw that too, but it was in the previous build.

It should be fixed now, make sure to use above code (2.01) and it should be ok.

doubleslashdesign
User offline. Last seen 2 days 1 min ago. Offline
Joined: 27 Nov 2010

I got this working there was one thing that was very confusing. defaultX, defaultY, overX, overY
should actually be defaultHeight, defaultWidth, overHeight, overWidth.

because that what they are used for in creating the display.newImageRect ( params.defaultSrc , params.defaultX , params.defaultY )

As it does not set the X/Y positions the object(s). although I think someone else created it like that

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

You are right about that, those are coming from the original retina support edit. As there are many people using it that way, I've decided to keep them as they were...

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

Finally I was able to test this tonight and I am having the same issue. On my iphone4 the text gets bigger when I press it and when I slide off and back on it gets even bigger. The button gets smaller like it should but the text gets big- the opposite of what it should.

I copied the code from the window above. Is that the wrong code?

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

@noahm26 that shouldn't be happening...

What you are describing is the problem of initial 2.0 and I have seen it too. Above code (2.01) does not have this issue anymore.

Are you sure above code overwritten the old one properly and it is the ui.la in the project folder you are running? Also you may try to copy files to a new location and try it from there...

I made a test scene here with two buttons, one scaling down, one scaling up. Copied above code back (just in case) compiled it and tested on my iPhone4 & iPad and it was fine.

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

Here is the button codes from my test...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
                 local ofBtn = ui.newButton{
                        defaultSrc = of,--pulled from spritesheet
                        overSrc = ofo,--pulled from spritesheet
                        overScale = 0.8,
                        onEvent = onOFTouch,
                        id = "OFButton",
                        text = "Button",
                        font = "Trebuchet-BoldItalic",
                        textColor = {255,255, 255, 255 },
                        size = 24,
                        emboss = false
                }
                
        ofBtn:setReferencePoint( display.TopLeftReferencePoint )
        ofBtn.x = screenX ofBtn.y = screenY
 
                 local ofBtn2 = ui.newButton{
                        defaultSrc = of2,--pulled from spritesheet
                        overSrc = ofo2,--pulled from spritesheet
                        overScale = 1.2,
                        onEvent = onOFTouch,
                        id = "OFButton2",
                        text = "Butto2",
                        font = "Trebuchet-BoldItalic",
                        textColor = {255,255, 255, 255 },
                        size = 24,
                        emboss = true
                }
                
        ofBtn2.x = screenX+170 ofBtn2.y = screenY+70

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

@PixelEnvision
I double checked again with the code above. I don't know why but it is still happening to me with that code. Here is my button code, maybe you can see where I am going wrong.

local levelButton = ui.newButton{
defaultSrc = "level-btn.png",
defaultX = 184,
defaultY = 36,
overSrc = "level-btn.png",
overX = 184,
overY = 36,
overScale = 0.95,
text = "PLAY LEVEL "..level,
size = 16,
font = "Helvetica-Bold",
textColor = { 255, 255, 255, 255 },
onEvent = playLevel,
id = "levelButton"
}

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

Ok, I have been able to reproduce your problem. Please try it with the new version (2.02), it should be working fine now...

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

Great! Unfortunately I have to wait until I get home from work to try it.

ChunkyApps
User offline. Last seen 2 days 10 hours ago. Offline
Joined: 19 Jan 2011

Alright! Works like a charm!

Thanks for this. It allowed me to get rid of 8 alternate "down button" images. Hi res and low res.

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

Ah, nice to hear that! You're welcome and thanks for helping me testing it...

mroberti
User offline. Last seen 10 hours 46 min ago. Offline
Joined: 20 Nov 2010

Hey thanks for the great lib PixelEnvision! I was going to ask what's the proper way to handle destroying the buttons when I switch scenes in director? I was going to code my own routine to handle the destruction process of the images, but how would I handle the removal of the listener assigned to each button when I created it?

Like, I have this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
local ui = require("ui")
local bt01
local function bt01t(event)
        if "release" == event.phase then
                print(event.phase)
                print("We released!")
                
                -- Let's whack the listener
                bt01:removeEventListener("touch",bt01t)
                -- .....but the listener is still in play here
                -- even after I remove it above...?
        end
end
 
 
bt01 = ui.newButton{
defaultSrc = "/Assets/Textures/UI/attack.png",
defaultX = 82,
defaultY = 82,
overSrc = "/Assets/Textures/UI/attack.png",
overX = 82,
overY = 82,
onEvent = bt01t,
id = "bt01"
}
 
bt01.x = 100
bt01.y = 100
bt01:setText( "sausage" )

Appreciate any help when you get a chance!

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

@mroberti you're welcome :)

As you are using director class you don't have to worry about removing listeners. Director & Corona (recent update) handles that as attached listeners also removed when the display objects are removed.

Just make sure to insert your buttons to current display group used by director.

If that helps that's how I'm using it...

I've grabbed latest copy of director (1.3) and changed that line objectOrGroup:removeSelf() to display.remove( objectOrGroup ) which is a newer method added to Corona.

Then just insert button to display group with menuGroup:insert( playBtn ) and let the director to take care of removal.

I'm also using the if active true/false check to make sure once clicked, there are no further clicks allowed to the button.

With above ui.lua, each button will be set to an active state after creation.

So you can do this:

1
2
3
4
5
6
7
8
local onPlayTouch = function( event )
                        if event.phase == "release" and playBtn.isActive then
                                playBtn.isActive = false
                                audio.play( tapSound )
                                director:changeScene("game","crossfade") 
                                print("change to game")                         
                        end
                end

I hope this helps...

mroberti
User offline. Last seen 10 hours 46 min ago. Offline
Joined: 20 Nov 2010

Where can I grab Director 1.3? I've been searching Ricardo's homepage, the forums and I can't find it! I'd love to get a hold of that!

[EDIT] More coffee helped me find the link buried in here:

http://developer.anscamobile.com/forum/2011/04/21/who-has-most-updated-and-tested-version-director-12

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010
mroberti
User offline. Last seen 10 hours 46 min ago. Offline
Joined: 20 Nov 2010

w00t!! Thanks again sir!

edgar86m
User offline. Last seen 2 years 6 days ago. Offline
Joined: 7 Jan 2011

At the top of the file in the comments it states...

1
--Version 1.5 (works with multitouch, adds setText() method to buttons

Shouldn't you change this to "Version 2.02" and then just provide the 1.5 as history at the bottom of the comments (like you did with the other versions)? I was getting confused when I downloaded this file and it stated it was "Version 1.5", I thought I downloaded the original file instead of the enhanced one.

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

@edgar86m actually you are right about that!

I'll do that for the next update, I'm planning to add highlight/shadows/emboss options to the newLabel function as well...

mroberti
User offline. Last seen 10 hours 46 min ago. Offline
Joined: 20 Nov 2010

Hey, a quick question. I'm failing the IQ test, and I haven't been drinking even!

I wanted to get the x and y location of my button I'm clicking on. event.x doesn't bring back the expected info, Corona complains about it being nil. Can someone show me where I'm being dense?

Here's my error:

...\Users\mroberti\DOCUME~1\CORONA~2\Sandbox\3\main.lua:60: attempt to c
oncatenate field 'y' (a nil value)
stack traceback:
[C]: ?
...\Users\mroberti\DOCUME~1\CORONA~2\Sandbox\3\main.lua:60: in function
'onEvent'
C:\Users\mroberti\DOCUME

...and here's my event handler, pretty simple test:

1
2
3
4
5
6
7
local function bt01t(event)
        if "release" == event.phase then
                print(event.phase)
                print("We released!")
                print("The X:"..event.x.." Y:"..event.y)
        end
end

Any clues? I am being dense, I know it! I even tried with event.target.x too and no joy!

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

I haven't tried this but I assume you are using "onEvent = bt01t" in your button setup. When setting up your button try using

onPress = bt01t OR onRelease = bt01t

Depending on your need...

amandavines
User offline. Last seen 1 year 51 weeks ago. Offline
Joined: 27 Jan 2011

hello,
I was curious, is it possible to wrap the text? if the text is too long to fit on the button, is there a quick way to wrap the text for the button?

thanks,
amanda

photiscta
User offline. Last seen 1 day 3 hours ago. Offline
Joined: 16 Feb 2011

Hello!

How can I make a button not to receive any more touches? I want to cancel the "button behavior" after specific conditions.
So, the button must work several times, and for example when the turnOFF == true, the button must not listen any more.
The button is called btnUP.
I tried with no luck
btnUP.isActive = false
and btnUP:removeEventListener("touch",functioneventname)

Thank you!

edgar86m
User offline. Last seen 2 years 6 days ago. Offline
Joined: 7 Jan 2011

@ photiscta: The following should work

1
2
3
btnUP._onEvent = nil
btnUP._onPress = nil
btnUP._onRelease = nil

You might want to save a reference to all those functions if you want to "enabled" the button later.

photiscta
User offline. Last seen 1 day 3 hours ago. Offline
Joined: 16 Feb 2011

Thank you edgar86m, but it does not work.
The error is: "attemp to index global 'btnUP' (a nil value)" and also runtime error.

Also, what the "_" means?

Thank you!!!

edgar86m
User offline. Last seen 2 years 6 days ago. Offline
Joined: 7 Jan 2011

If you are getting that error, you need to figure out why "btnUp" is nil. This has to do with how you instantiated/created the object, not with the events you're trying to remove.

The "_" prefix is just how they keep track of the event function internally within their file, it's just a common coding convention

photiscta
User offline. Last seen 1 day 3 hours ago. Offline
Joined: 16 Feb 2011

@edgar86m
I don't have any problem using the button. It works fine.
the code:

1
2
3
4
5
6
7
8
9
10
function choiceUP (event)
--something
end
 
local btnUP = ui.newButton{
                default = "arrowUP.png",
                over = "arrowUP-over.png",
                onRelease = choiceUP,
                id = "btnUP"
}

edgar86m
User offline. Last seen 2 years 6 days ago. Offline
Joined: 7 Jan 2011

It's "defaultSrc" not "default"

photiscta
User offline. Last seen 1 day 3 hours ago. Offline
Joined: 16 Feb 2011

@edgar86m
You are right. In this project, I am using UI.lua ver 1.5
The solution you are giving is working on 2.02?

Thank you again :)

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

@photiscta

Have you taken a look at my post above? #24
http://developer.anscamobile.com/code/enhanced-ui-library-uilua#comment-41455

btnUP.isActive = false

You can set this flag to disable button function at any time, isn't that what you need?

photiscta
User offline. Last seen 1 day 3 hours ago. Offline
Joined: 16 Feb 2011

@edgar86m
btnUP.isActive = false does not work.
Wherever i put that code, even on start main function, there is no change.
I can press the button, and it works fine!

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

@photiscta

Are you using the code (2.02) above? Because it won't work with 1.5.

Also when using 2.02 your function should be like that:

1
2
3
4
5
6
function choiceUP (event)
if event.phase == "release" and btnUP.isActive then
--something
end
end
 

Then you can set btnUP.isActive = false where you want it to be disabled.

Also as @edgar86m said...

Button definition is not the same as 1.5, so to get your button work you'll ned to use it like:

1
2
3
4
5
6
7
8
9
10
local btnUP = ui.newButton{
                defaultSrc = "arrowUP.png",
                defaultX = (Depends on your image size),
                defaultY = (Depends on your image size),
                overSrc = "arrowUP-over.png",
                overX = (Depends on your image size),
                overY = (Depends on your image size),
                onEvent = choiceUP,
                id = "btnUP"
}

monoxgas
User offline. Last seen 2 years 27 weeks ago. Offline
Joined: 6 Jun 2011

I have a little solution for people struggling with the .isActive problem. Pretty much with these buttons, .isActive is just a property that you set, but you have to check by yourself in the button handler. The class doesn't really handle isActive at all. So usually you have to do:

1
2
3
4
5
function choiceUP (event)
if event.phase == "release" and btnUP.isActive then
--something
end
end

But for me, I was using one function to handle multiple button events, so I couldnt specifically check each button for the isActive state. So my solution was this:

Put this line of code somewhere in the newButtonHandler() function in the ui.lua:

1
buttonEvent.isActive = self.isActive

Keep in mind that this is not the same as the newButton() function

Then instead of this:

1
2
3
4
5
function choiceUP (event)
if event.phase == "release" and btnUP.isActive then
--something
end
end

Use this:

1
2
3
4
5
function choiceUP (event)
if event.phase == "release" and event.isActive then
--something
end
end

This makes sure you dont have to specifically designate the button to check against, it will just check it against the button connected to the handler. That way it makes life a little easier when using isActive. Could someone please update the ui.lua to reflect this?

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

@monoxgas

Very nice suggestion! It's also fully backwards compatible so if anyone updates to new ui.lua their code continue to work..

I've just updated the page, thanks...

KevinM2k
User offline. Last seen 7 weeks 15 hours ago. Offline
Joined: 28 Jun 2011

Is there a way you can have sub text on this, so a button with 2 or more types of labels, I basically want my button to have a title, and a small description underneath.

PixelEnvision
User offline. Last seen 31 weeks 1 day ago. Offline
Joined: 22 Oct 2010

@KevinM2k

I'm afraid that's not possible with the current version but that could be an update...

Does your text is dynamic? Or you are using same button image for multiple buttons with different text?

If not, I think you may just embed your text on to the button image, right?

KevinM2k
User offline. Last seen 7 weeks 15 hours ago. Offline
Joined: 28 Jun 2011

Hi,

Text comes from a database, but at present it is the same button.

What i've decided to do, is copy the existing newButton routine and create newCustomButton or whatever I decide to call it. I am doing it first so that I dont need a background image as the button and I can change the styling (border and background, and add an image to a part of the button.

I am then going to try and extend it so I can have sub texts so my function will be something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
new ui.newCustomButton= {
   defaultButton = {
      top = 5,
      left = 5,
      width = 100,
      height = 40,
      backgroundColor = { 0, 0, 0 }
      alpha = 0,
      borderColor = { 0, 0, 0 }
      borderWidth = 1
   },
   overButton = {
      -- Same params as above
   },
   mainText = {
      text = 'some text here',
      color = { 255, 255, 255 },
      alpha = 0,
      align = 'left',
   },
   subText = {
      -- Same params
   },
   onPress = call back function
}

Something along the lines of that anyways, just need to get on with it really.

Should work hopefully!! :)

simon.wetterlind
User offline. Last seen 2 years 33 weeks ago. Offline
Joined: 21 Aug 2011

Nice!

Why not move the line 192

1
button = display.newGroup()

to before the if statement?

you might want a button without default image...

Cheers!

Harm
User offline. Last seen 16 weeks 4 days ago. Offline
Joined: 21 Oct 2010

Is there a way to send parameters with the onEvent?

I tried to do this but it doesn't work:
onEvent = itemButton("itemname")

Or maybe another way to identify what button was pressed from the itemButton function?

rahulsingh2k10
User offline. Last seen 22 weeks 1 day ago. Offline
Joined: 9 Aug 2011

Hi