Files
EasySoft-ZenTaoPMS/mobile/corona/tableView.lua
2012-05-04 05:59:47 +00:00

421 lines
15 KiB
Lua

-- tableView.lua, Table View Library
--
-- Version 1.3
--
-- 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)
--properties
local screenW, screenH = display.contentWidth, display.contentHeight
local viewableScreenW, viewableScreenH = display.viewableContentWidth, display.viewableContentHeight
local screenOffsetW, screenOffsetH = display.contentWidth - display.viewableContentWidth, display.contentHeight - display.viewableContentHeight
local currentTarget, detailScreen, velocity, currentDefault, currentOver, prevY
local startTime, lastTime, prevTime = 0, 0, 0
--methods
function showHighlight(event)
local timePassed = system.getTimer() - startTime
if timePassed > 100 then
print("highlight")
currentDefault.isVisible = false
currentOver.isVisible = true
Runtime:removeEventListener( "enterFrame", showHighlight )
end
end
function newListItemHandler(self, event)
local t = currentTarget --could use self.target.parent possibly
local phase = event.phase
print("touch: ".. phase)
local default = self.default
local over = self.over
local top = self.top
local bottom = self.bottom
local upperLimit, bottomLimit = top, screenH - currentTarget.height - bottom
local result = true
if( phase == "began" ) then
-- Subsequent touch events will target button even if they are outside the contentBounds of button
display.getCurrentStage():setFocus( self )
self.isFocus = true
startPos = event.y
prevPos = event.y
delta, velocity = 0, 0
if currentTarget.tween then transition.cancel(currentTarget.tween) end
Runtime:removeEventListener("enterFrame", scrollList )
Runtime:addEventListener("enterFrame", moveCat)
-- Start tracking velocity
Runtime:addEventListener("enterFrame", trackVelocity)
if over then
currentDefault = default
currentOver = over
startTime = system.getTimer()
Runtime:addEventListener( "enterFrame", showHighlight )
end
elseif( self.isFocus ) then
if( phase == "moved" ) then
Runtime:removeEventListener( "enterFrame", showHighlight )
if over then
default.isVisible = true
over.isVisible = false
end
delta = event.y - prevPos
prevPos = event.y
if ( t.y > upperLimit or t.y < bottomLimit ) then
t.y = t.y + delta/2
else
t.y = t.y + delta
end
elseif( phase == "ended" or phase == "cancelled" ) then
lastTime = event.time
local dragDistance = event.y - startPos
--velocity = delta
Runtime:removeEventListener("enterFrame", moveCat)
Runtime:removeEventListener("enterFrame", trackVelocity)
Runtime:addEventListener("enterFrame", scrollList )
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
-- Only consider this a "click", if the user lifts their finger inside button's contentBounds
if isWithinBounds and (dragDistance < 10 and dragDistance > -10 ) then
velocity = 0
result = self.onRelease(event)
end
-- Allow touch events to be sent normally to the objects they "hit"
display.getCurrentStage():setFocus( nil )
self.isFocus = false
if over then
default.isVisible = true
over.isVisible = false
Runtime:removeEventListener( "enterFrame", showHighlight )
end
end
end
return result
end
function newListItem(params)
local data = params.data
local default = params.default
local over = params.over
local onRelease = params.onRelease
local top = params.top
local bottom = params.bottom
local callback = params.callback
local id = params.id
local thisItem = display.newGroup()
if params.default then
default = display.newImage( params.default )
thisItem:insert( default )
default.x = default.width*.5 - screenOffsetW
thisItem.default = default
end
if params.over then
over = display.newImage( params.over )
over.isVisible = false
thisItem:insert( over )
over.x = over.width*.5 - screenOffsetW
thisItem.over = over
end
thisItem.id = id
thisItem.data = data
thisItem.onRelease = onRelease
thisItem.top = top
thisItem.bottom = bottom
local t = callback(data)
thisItem:insert( t )
thisItem.touch = newListItemHandler
thisItem:addEventListener( "touch", thisItem )
return thisItem
end
function newList(params)
local textSize = 16
local data = params.data
local default = params.default
local over = params.over
local onRelease = params.onRelease
local top = params.top or 20
local bottom = params.bottom or 48
local cat = params.cat
local order = params.order or {}
local categoryBackground = params.categoryBackground
local backgroundColor = params.backgroundColor
local callback = params.callback or function(item)
local t = display.newText(item, 0, 0, native.systemFontBold, textSize)
t:setTextColor(255, 255, 255)
t.x = math.floor(t.width/2) + 20
t.y = 24
return t
end
--setup the list view
local listView = display.newGroup()
local prevY, prevH = 0, 0
if cat then
local catTable = {}
--get the implicit categories
local prevCat = 0
for i=1, #data do
if data[i][cat] ~= prevCat then
table.insert(catTable, data[i][cat])
prevCat = data[i][cat]
end
end
if order then
--clean up the user provided order table by removing any empty categories
local n = 1
while n < #order do
if not in_table(order[n], catTable) then
table.remove(order, n)
else
n = n + 1
end
end
--add any categories not specified to the user order of categories
for i=1, #catTable do
if not in_table(catTable[i], order) then
table.insert(order, catTable[i])
end
end
else
order = catTable
end
end
local j = 1
local c = {}
local offset = 12
while true do
local h = order[j]
if h then
local g = display.newGroup()
local b
if categoryBackground then
b = display.newImage(categoryBackground, true)
else
b = display.newRect(0, 0, screenW, textSize*1.5)
b:setFillColor(0, 0, 0, 100)
end
g:insert( b )
local labelShadow = display.newText( h, 0, 0, native.systemFontBold, textSize )
labelShadow:setTextColor( 0, 0, 0, 128 )
g:insert( labelShadow, true )
labelShadow.x = labelShadow.width*.5 + 1 + offset + screenOffsetW*.5
labelShadow.y = textSize*.8 + 1
local t = display.newText(h, 0, 0, native.systemFontBold, textSize)
t:setTextColor(255, 255, 255)
g:insert( t )
t.x = t.width*.5 + offset + screenOffsetW*.5
t.y = textSize*.8
listView:insert( g )
g.x = 0
g.y = prevY + prevH
prevY = g.y
prevH = g.height
table.insert(c, g)
c[#c].yInit = g.y
end
--iterate over the data and add items to the list view
for i=1, #data do
if data[i][cat] == h then
local thisItem = newListItem{
data = data[i],
default = default,
over = over,
onRelease = onRelease,
top = top,
bottom = bottom,
callback = callback,
id = i
}
listView:insert( 1, thisItem )
thisItem.x = 0 + screenOffsetW*.5
thisItem.y = prevY + prevH
--save the Y and height
prevY = thisItem.y
prevH = thisItem.height
end --if
end --for
j = j + 1
if not order[j] then break end
end --while
if backgroundColor then
local bgColor = display.newRect(0, 0, screenW, screenH)
bgColor:setFillColor(backgroundColor[1], backgroundColor[2], backgroundColor[3])
bgColor.width = listView.width
bgColor.height = listView.height
bgColor.y = bgColor.height*.5
listView:insert(1, bgColor)
end
listView.y = top
listView.top = top
listView.bottom = bottom
listView.c = c
currentTarget = listView
function listView:cleanUp()
print("tableView cleanUp")
Runtime:removeEventListener("enterFrame", moveCat )
Runtime:removeEventListener("enterFrame", scrollList )
Runtime:removeEventListener( "enterFrame", showHighlight )
Runtime:removeEventListener("enterFrame", trackVelocity)
local i
for i = listView.numChildren, 1, -1 do
--test
listView[i]:removeEventListener("touch", newListItemHandler)
listView:remove(i)
listView[i] = nil
end
end
return listView
end
function scrollList(event)
local friction = 0.9
local timePassed = event.time - lastTime
lastTime = lastTime + timePassed
--turn off scrolling if velocity is near zero
if math.abs(velocity) < .01 then
velocity = 0
Runtime:removeEventListener("enterFrame", scrollList )
end
velocity = velocity*friction
currentTarget.y = math.floor(currentTarget.y + velocity*timePassed)
moveCat()
local upperLimit = currentTarget.top
local bottomLimit = screenH - currentTarget.height - currentTarget.bottom
if ( currentTarget.y > upperLimit ) then
velocity = 0
Runtime:removeEventListener("enterFrame", scrollList )
Runtime:addEventListener("enterFrame", moveCat )
currentTarget.tween = transition.to(currentTarget, { time=400, y=upperLimit, transition=easing.outQuad})
elseif ( currentTarget.y < bottomLimit and bottomLimit < 0 ) then
velocity = 0
Runtime:removeEventListener("enterFrame", scrollList )
Runtime:addEventListener("enterFrame", moveCat )
currentTarget.tween = transition.to(currentTarget, { time=400, y=bottomLimit, transition=easing.outQuad})
elseif ( currentTarget.y < bottomLimit ) then
velocity = 0
Runtime:removeEventListener("enterFrame", scrollList )
Runtime:addEventListener("enterFrame", moveCat )
currentTarget.tween = transition.to(currentTarget, { time=400, y=upperLimit, transition=easing.outQuad})
end
return true
end
function moveCat()
local upperLimit = currentTarget.top
for i=1, #currentTarget.c do
if( currentTarget.y > upperLimit - currentTarget.c[i].yInit ) then
currentTarget.c[i].y = currentTarget.c[i].yInit
end
if ( currentTarget.y < upperLimit - currentTarget.c[i].yInit ) then
currentTarget.c[i].y = upperLimit - currentTarget.y
end
if( i > 1 ) then
if ( currentTarget.c[i].y < currentTarget.c[i-1].y + currentTarget.c[i].height ) then
currentTarget.c[i-1].y = currentTarget.c[i].y - currentTarget.c[i].height
end
end
end
return true
end
function trackVelocity(event)
local timePassed = event.time - prevTime
prevTime = prevTime + timePassed
if prevY then
velocity = (currentTarget.y - prevY)/timePassed
end
prevY = currentTarget.y
end
--look for an item in a table
function in_table ( e, t )
for _,v in pairs(t) do
if (v==e) then return true end
end
return false
end