UI Button should have disabled state

10 replies [Last post]
SleepySheep
User offline. Last seen 7 years 21 weeks ago. Offline
Joined: 1 Jun 2011

Hello there,

I think it is common sense for button to have disabled state (cannot press/cannot do any interactive).

It will be very useful. For example, button for the level, if level is locked -> button's state is disabled and when the level is unlocked -> button's state is default.

Thank you

Replies

jocf
User offline. Last seen 5 years 5 weeks ago. Offline
Joined: 21 Jun 2011

I have modified ui.lua for that... And I use it.
This version also have its own picture for disabled state.
... But probably needs more tests.
Who can help me to do more tests and to send to somebody who mantain official ui.lua code?

Regards,
J.O.C.F

SleepySheep
User offline. Last seen 7 years 21 weeks ago. Offline
Joined: 1 Jun 2011

@J.O.C.F
It sounds interesting.
May I try?
I wonder that in your custom ui, is it possible to set state of button like button.state = disabled??

Naomi
User offline. Last seen 49 weeks 1 day ago. Offline
Joined: 6 Jun 2011

It would be so great to have "disabled" state for buttons!

PixelEnvision
User offline. Last seen 1 year 44 weeks ago. Offline
Joined: 22 Oct 2010

Hi guys...

After seeing that thread I have decided to update my enhanced version of ui.lua to support this request.

http://developer.anscamobile.com/code/enhanced-ui-library-uilua

After setting your button (it will be enabled by default), you can enable disable it as follows.

1
2
3
4
5
6
7
8
-- Setup your button
myBtn = ui.newButton{......}
 
-- Disable the button
myBtn.isActive =  false
 
-- Re-enable the button
myBtn.isActive =  true

Actually isActive was there for a while but you had to check it yourself in your event function. But the current integration will be easier to use and it also disables click animation (over image).

Naomi
User offline. Last seen 49 weeks 1 day ago. Offline
Joined: 6 Jun 2011

Wow, PixelEnvision, this is super duper awesome!

SleepySheep
User offline. Last seen 7 years 21 weeks ago. Offline
Joined: 1 Jun 2011

@PixelEnvision

It is awesome. But I have a few question.
Is it possible for your version of ui.lua can set disabled state's image?

According to your ui.lua, I have to set size of button(defaultX,defaultY,...)which the my previous used ui.lua is not required. I think it gonna be some messy when thinking about retina (@2x,...). It will be nice if the api can get width and height automatically like display.newImage().

PixelEnvision
User offline. Last seen 1 year 44 weeks ago. Offline
Joined: 22 Oct 2010

@SleepySheep,

Supporting the 3rd image for the disabled state is a nice idea, but I won't be able work on this anytime soon, sorry... May be in a couple of weeks...

Regarding the 2nd question...

You got it in reverse :)

defaultX/defaultY is added TO support retina (@2x,etc) as display.newImageRect() requires image dimensions.

original ui.lua already uses display.newImage() and it does not support retina and that's why it does not require image dimensions...

Take a look at the api for details on display.newImage() & display.newImageRect()
http://developer.anscamobile.com/content/displaynewimagerect

Regards...

jocf
User offline. Last seen 5 years 5 weeks ago. Offline
Joined: 21 Jun 2011

Here I'm back.
Mi code example for a button may be like that:

1
2
3
4
5
6
7
playButton = ui.newButton{
        default = "buttonPlay.png",
        over = "buttonPlayOver.png",
        disabled = "buttonDisabled.png",
        onRelease = playOrPauseButtonRelease,
        id = "play"
}

Then you can change de button state with this:
1
2
playButton:setDisable()
playButton:setEnable()

The new "touched" ui.lua is 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
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
-- ui.lua (currently includes Button class with labels, font selection and optional event model)
 
-- 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.
 
module(..., package.seeall)
 
-----------------
-- Helper function for newButton utility function below
local function newButtonHandler( self, event )
 
        local result = true
 
        local default = self[1]
        local over = self[2]
        
        -- 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
 
        local phase = event.phase
        if "began" == phase then
                if over then 
                        default.isVisible = false
                        over.isVisible = true
                end
 
                if onEvent then
                        buttonEvent.phase = "press"
                        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 contentBounds
                                default.isVisible = not isWithinBounds
                                over.isVisible = isWithinBounds
                        end
                        
                elseif "ended" == phase or "cancelled" == phase then 
                        if over then 
                                default.isVisible = true
                                over.isVisible = false
                        end
                        
                        if "ended" == phase then
                                -- Only consider this a "click" if the user lifts their finger inside button's contentBounds
                                if isWithinBounds then
                                        if onEvent then
                                                buttonEvent.phase = "release"
                                                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
 
        return result
end
 
 
---------------
-- Button class
 
function newButton( params )
        local button, default, over, disabled, size, font, textColor, offset, isActive
 
        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
        
        if params.disabled then
                disabled = display.newImage( params.disabled )
                disabled.isVisible = false
                button:insert( disabled, true )
        end
 
        isActive = true
 
        -- Public method
        function button:setEnable()
                if isActive then return end     -- already active
 
                isActive = true;
                button:addEventListener( "touch", button )
 
                if default then default.isVisible = true end
                if over then over.isVisible = false end
                if disabled then disabled.isVisible = false end
        end
 
        -- Public method
        function button:setDisable()
                if not isActive then return end -- already inactive
 
                isActive = false;
                button:removeEventListener( "touch", button )
 
                if default and disabled then default.isVisible = false end
 
                if over then
                        over.isVisible = false
                        if not disabled then default.isVisible = true end -- in case no disabled image
                end
 
                if disabled then disabled.isVisible = true end
        end
 
        -- Public method
        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
                
                -- 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
                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
 
 
--------------
-- Label class
 
function newLabel( params )
        local labelText
        local size, font, textColor, align
        local t = display.newGroup()
        
        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 )
                        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 / 2
                                elseif ( "right" == align ) then
                                        labelText.x = (left + width) - labelText.contentWidth / 2
                                else
                                        labelText.x = ((2 * left) + width) / 2
                                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

I hope this can help you.
Best regards,

J.O.C.F.
Twitter: @jocf

jaredpack
User offline. Last seen 7 years 7 weeks ago. Offline
Joined: 1 Feb 2011

Thanks @jocf.foros

Your code works perfectly!

jocf
User offline. Last seen 5 years 5 weeks ago. Offline
Joined: 21 Jun 2011

Thanks, @jaredpack. This code is useful for me and I'm happy that somebody else can include it in their Apps.

I'm new with Corona SDK and I'd like that this code may be included in the official ui package. Do you know how to do that? (thanks).

Other possibility is a branch... but I don't like this option (code fragmentation). In this case is necessary change de "version".

Regards,
J.O.C.F.

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.