Advertisement
lavalevel

tableView.lua

Feb 21st, 2012
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.68 KB | None | 0 0
  1. -- tableView.lua, Table View Library
  2. --
  3. -- Version 1.3
  4. --
  5. -- Copyright (C) 2010 ANSCA Inc. All Rights Reserved.
  6. --
  7. -- Permission is hereby granted, free of charge, to any person obtaining a copy of
  8. -- this software and associated documentation files (the "Software"), to deal in the
  9. -- Software without restriction, including without limitation the rights to use, copy,
  10. -- modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
  11. -- and to permit persons to whom the Software is furnished to do so, subject to the
  12. -- following conditions:
  13. --
  14. -- The above copyright notice and this permission notice shall be included in all copies
  15. -- or substantial portions of the Software.
  16. --
  17. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  18. -- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  19. -- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  20. -- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  21. -- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22. -- DEALINGS IN THE SOFTWARE.
  23.  
  24. module(..., package.seeall)
  25.  
  26. --properties
  27.  local screenW, screenH = display.contentWidth, display.contentHeight
  28. local viewableScreenW, viewableScreenH = display.viewableContentWidth, display.viewableContentHeight
  29. local screenOffsetW, screenOffsetH = display.contentWidth -  display.viewableContentWidth, display.contentHeight - display.viewableContentHeight
  30.  
  31. local currentTarget, detailScreen, velocity, currentDefault, currentOver, prevY
  32. local startTime, lastTime, prevTime = 0, 0, 0
  33.  
  34. --methods
  35.  
  36. function showHighlight(event)
  37.     local timePassed = system.getTimer() - startTime
  38.  
  39.     if timePassed > 100 then
  40.         print("highlight")
  41.         currentDefault.isVisible = false
  42.         currentOver.isVisible = true
  43.         Runtime:removeEventListener( "enterFrame", showHighlight )
  44.     end
  45. end
  46.  
  47. function newListItemHandler(self, event)
  48.         local t = currentTarget --could use self.target.parent possibly
  49.         local phase = event.phase
  50.         print("touch: ".. phase)
  51.  
  52.         local default = self.default
  53.         local over = self.over
  54.         local top = self.top
  55.         local bottom = self.bottom
  56.         local upperLimit, bottomLimit = top, screenH - currentTarget.height - bottom
  57.  
  58.         local result = true        
  59.        
  60.         if( phase == "began" ) then
  61.             -- Subsequent touch events will target button even if they are outside the stageBounds of button
  62.             display.getCurrentStage():setFocus( self )
  63.             self.isFocus = true
  64.  
  65.             startPos = event.y
  66.             prevPos = event.y                                      
  67.             delta, velocity = 0, 0
  68.             if currentTarget.tween then transition.cancel(currentTarget.tween) end
  69.  
  70.             Runtime:removeEventListener("enterFrame", scrollList )
  71.             Runtime:addEventListener("enterFrame", moveCat)
  72.  
  73.             -- Start tracking velocity
  74.             Runtime:addEventListener("enterFrame", trackVelocity)
  75.  
  76.             if over then
  77.                 currentDefault = default
  78.                 currentOver = over
  79.                 startTime = system.getTimer()
  80.                 Runtime:addEventListener( "enterFrame", showHighlight )
  81.             end
  82.              
  83.         elseif( self.isFocus ) then
  84.  
  85.             if( phase == "moved" ) then    
  86.  
  87.                 Runtime:removeEventListener( "enterFrame", showHighlight )
  88.                 if over then
  89.                     default.isVisible = true
  90.                     over.isVisible = false
  91.                 end
  92.  
  93.                 delta = event.y - prevPos
  94.                 prevPos = event.y
  95.                 if ( t.y > upperLimit or t.y < bottomLimit ) then
  96.                     t.y  = t.y + delta/2
  97.                 else
  98.                     t.y = t.y + delta      
  99.                 end
  100.                    
  101.             elseif( phase == "ended" or phase == "cancelled" ) then
  102.  
  103.                 lastTime = event.time
  104.  
  105.                 local dragDistance = event.y - startPos
  106.                 --velocity = delta
  107.                 Runtime:removeEventListener("enterFrame", moveCat)
  108.                 Runtime:removeEventListener("enterFrame", trackVelocity)
  109.                 Runtime:addEventListener("enterFrame", scrollList )            
  110.  
  111.                 local bounds = self.stageBounds
  112.                 local x, y = event.x, event.y
  113.                 local isWithinBounds = bounds.xMin <= x and bounds.xMax >= x and bounds.yMin <= y and bounds.yMax >= y
  114.        
  115.                 -- Only consider this a "click", if the user lifts their finger inside button's stageBounds
  116.                 if isWithinBounds and (dragDistance < 10 and dragDistance > -10 ) then
  117.                     velocity = 0
  118.                     result = self.onRelease(event)
  119.                 end
  120.  
  121.                 -- Allow touch events to be sent normally to the objects they "hit"
  122.                 display.getCurrentStage():setFocus( nil )
  123.                 self.isFocus = false
  124.  
  125.                 if over then
  126.                     default.isVisible = true
  127.                     over.isVisible = false
  128.                     Runtime:removeEventListener( "enterFrame", showHighlight )
  129.                 end
  130.             end
  131.         end
  132.        
  133.         return result
  134. end
  135.  
  136. function newListItem(params)
  137.         local data = params.data
  138.         local default = params.default
  139.         local over = params.over
  140.         local onRelease = params.onRelease
  141.         local top = params.top
  142.         local bottom = params.bottom
  143.         local callback = params.callback
  144.         local id = params.id
  145.  
  146.         local thisItem = display.newGroup()
  147.  
  148.         if params.default then
  149.                 default = display.newImage( params.default )
  150.                 thisItem:insert( default )
  151.                 default.x = default.width*.5 - screenOffsetW
  152.                 thisItem.default  = default
  153.         end
  154.        
  155.         if params.over then
  156.                 over = display.newImage( params.over )
  157.                 over.isVisible = false
  158.                 thisItem:insert( over )
  159.                 over.x = over.width*.5 - screenOffsetW
  160.                 thisItem.over = over
  161.         end
  162.  
  163.         thisItem.id = id
  164.         thisItem.data = data
  165.         thisItem.onRelease = onRelease          
  166.         thisItem.top = top
  167.         thisItem.bottom = bottom
  168.  
  169.         local t = callback(data)
  170.         thisItem:insert( t )
  171.  
  172.         thisItem.touch = newListItemHandler
  173.         thisItem:addEventListener( "touch", thisItem )
  174.        
  175.         return thisItem
  176. end
  177.  
  178. function newList(params)
  179.         local textSize = 16
  180.         local data = params.data
  181.         local default = params.default
  182.         local over = params.over
  183.         local onRelease = params.onRelease
  184.         local top = params.top or 20
  185.         local bottom = params.bottom or 48
  186.         local cat = params.cat
  187.         local order = params.order or {}
  188.         local categoryBackground = params.categoryBackground
  189.         local backgroundColor = params.backgroundColor
  190.         local callback = params.callback or function(item)
  191.                                                 local t = display.newText(item, 0, 0, native.systemFontBold, textSize)
  192.                                                 t:setTextColor(255, 255, 255)
  193.                                                 t.x = math.floor(t.width/2) + 20
  194.                                                 t.y = 24
  195.                                                 return t
  196.                                             end
  197.      
  198.         --setup the list view                  
  199.         local listView = display.newGroup()
  200.         local prevY, prevH = 0, 0
  201.        
  202.  
  203.         if cat then        
  204.             local catTable = {}
  205.    
  206.             --get the implicit categories
  207.             local prevCat = 0
  208.             for i=1, #data do
  209.                 if data[i][cat] ~= prevCat then
  210.                     table.insert(catTable, data[i][cat])
  211.                     prevCat = data[i][cat]
  212.                 end
  213.             end
  214.            
  215.             if order then    
  216.                 --clean up the user provided order table by removing any empty categories
  217.                 local n = 1
  218.                 while n < #order do
  219.                     if not in_table(order[n], catTable) then
  220.                         table.remove(order, n)
  221.                     else
  222.                         n = n + 1
  223.                     end
  224.                 end
  225.  
  226.                 --add any categories not specified to the user order of categories
  227.                 for i=1, #catTable do
  228.                     if not in_table(catTable[i], order) then
  229.                         table.insert(order, catTable[i])
  230.                     end
  231.                 end
  232.             else
  233.                 order = catTable
  234.             end        
  235.  
  236.         end      
  237.                
  238.         local j = 1
  239.         local c = {}
  240.         local offset = 12
  241.         while true do
  242.             local h = order[j]
  243.            
  244.             if h then
  245.                 local g = display.newGroup()
  246.                 local b
  247.                 if categoryBackground then
  248.                     b = display.newImage(categoryBackground, true)
  249.                 else
  250.                     b = display.newRect(0, 0, screenW, textSize*1.5)
  251.                     b:setFillColor(0, 0, 0, 100)
  252.                 end
  253.                 g:insert( b )
  254.  
  255.                 local labelShadow = display.newText( h, 0, 0, native.systemFontBold, textSize )
  256.                 labelShadow:setTextColor( 0, 0, 0, 128 )
  257.                 g:insert( labelShadow, true )
  258.                 labelShadow.x = labelShadow.width*.5 + 1 + offset + screenOffsetW*.5
  259.                 labelShadow.y = textSize*.8 + 1
  260.  
  261.                 local t = display.newText(h, 0, 0, native.systemFontBold, textSize)
  262.                 t:setTextColor(255, 255, 255)
  263.                 g:insert( t )
  264.                 t.x = t.width*.5 + offset + screenOffsetW*.5
  265.                 t.y = textSize*.8  
  266.                
  267.                 listView:insert( g )
  268.                 g.x = 0
  269.                 g.y = prevY + prevH    
  270.                 prevY = g.y
  271.                 prevH = g.height
  272.                 table.insert(c, g)          
  273.                 c[#c].yInit = g.y    
  274.             end
  275.                        
  276.             --iterate over the data and add items to the list view
  277.             for i=1, #data do
  278.                 if data[i][cat] == h then  
  279.                     local thisItem = newListItem{
  280.                         data = data[i],
  281.                         default = default,
  282.                         over = over,
  283.                         onRelease = onRelease,
  284.                         top = top,
  285.                         bottom = bottom,
  286.                         callback = callback,
  287.                         id = i
  288.                     }
  289.      
  290.                     listView:insert( 1, thisItem )    
  291.      
  292.                     thisItem.x = 0 + screenOffsetW*.5
  293.                     thisItem.y = prevY + prevH
  294.      
  295.                     --save the Y and height
  296.                     prevY = thisItem.y
  297.                     prevH = thisItem.height    
  298.                 end --if               
  299.             end --for
  300.                        
  301.             j = j + 1
  302.            
  303.             if not order[j] then break end                                 
  304.         end --while
  305.        
  306.         if backgroundColor then
  307.             local bgColor = display.newRect(0, 0, screenW, screenH)
  308.             bgColor:setFillColor(backgroundColor[1], backgroundColor[2], backgroundColor[3])
  309.             bgColor.width = listView.width
  310.             bgColor.height = listView.height
  311.             bgColor.y = bgColor.height*.5
  312.             listView:insert(1, bgColor)
  313.         end
  314.                
  315.         listView.y = top
  316.         listView.top = top
  317.         listView.bottom = bottom
  318.         listView.c = c
  319.        
  320.         currentTarget = listView
  321.  
  322.         function listView:cleanUp()
  323.             print("tableView cleanUp")
  324.             Runtime:removeEventListener("enterFrame", moveCat )
  325.             Runtime:removeEventListener("enterFrame", scrollList )
  326.             Runtime:removeEventListener( "enterFrame", showHighlight )
  327.             Runtime:removeEventListener("enterFrame", trackVelocity)
  328.             local i
  329.             for i = listView.numChildren, 1, -1 do
  330.                 --test
  331.                 listView[i]:removeEventListener("touch", newListItemHandler)
  332.                 listView:remove(i)
  333.                 listView[i] = nil
  334.             end
  335.         end
  336.        
  337.         return listView
  338. end
  339.  
  340. function scrollList(event)  
  341.         local friction = 0.9
  342.         local timePassed = event.time - lastTime
  343.         lastTime = lastTime + timePassed      
  344.  
  345.         --turn off scrolling if velocity is near zero
  346.         if math.abs(velocity) < .01 then
  347.                 velocity = 0
  348.                 Runtime:removeEventListener("enterFrame", scrollList )
  349.         end      
  350.  
  351.         velocity = velocity*friction
  352.        
  353.         currentTarget.y = math.floor(currentTarget.y + velocity*timePassed)
  354.        
  355.         moveCat()
  356.  
  357.         local upperLimit = currentTarget.top
  358.         local bottomLimit = screenH - currentTarget.height - currentTarget.bottom
  359.        
  360.         if ( currentTarget.y > upperLimit ) then
  361.                 velocity = 0
  362.                 Runtime:removeEventListener("enterFrame", scrollList )          
  363.                 Runtime:addEventListener("enterFrame", moveCat )          
  364.                 currentTarget.tween = transition.to(currentTarget, { time=400, y=upperLimit, transition=easing.outQuad})
  365.         elseif ( currentTarget.y < bottomLimit and bottomLimit < 0 ) then
  366.                 velocity = 0
  367.                 Runtime:removeEventListener("enterFrame", scrollList )          
  368.                 Runtime:addEventListener("enterFrame", moveCat )          
  369.                 currentTarget.tween = transition.to(currentTarget, { time=400, y=bottomLimit, transition=easing.outQuad})
  370.         elseif ( currentTarget.y < bottomLimit ) then
  371.                 velocity = 0
  372.                 Runtime:removeEventListener("enterFrame", scrollList )          
  373.                 Runtime:addEventListener("enterFrame", moveCat )          
  374.                 currentTarget.tween = transition.to(currentTarget, { time=400, y=upperLimit, transition=easing.outQuad})        
  375.         end
  376.                  
  377.         return true
  378. end
  379.  
  380. function moveCat()
  381.         local upperLimit = currentTarget.top
  382.  
  383.         for i=1, #currentTarget.c do
  384.             if( currentTarget.y > upperLimit - currentTarget.c[i].yInit ) then
  385.                 currentTarget.c[i].y = currentTarget.c[i].yInit
  386.             end
  387.            
  388.             if ( currentTarget.y < upperLimit - currentTarget.c[i].yInit ) then
  389.                 currentTarget.c[i].y = upperLimit - currentTarget.y
  390.             end
  391.    
  392.             if( i > 1 ) then
  393.                 if ( currentTarget.c[i].y < currentTarget.c[i-1].y + currentTarget.c[i].height ) then
  394.                     currentTarget.c[i-1].y = currentTarget.c[i].y - currentTarget.c[i].height
  395.                 end
  396.             end
  397.         end
  398.        
  399.         return true
  400. end
  401.  
  402. function trackVelocity(event)  
  403.     local timePassed = event.time - prevTime
  404.     prevTime = prevTime + timePassed
  405.  
  406.     if prevY then
  407.         velocity = (currentTarget.y - prevY)/timePassed
  408.     end
  409.     prevY = currentTarget.y
  410. end        
  411.  
  412. --look for an item in a table
  413. function in_table ( e, t )
  414.     for _,v in pairs(t) do
  415.         if (v==e) then return true end
  416.     end
  417.     return false
  418. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement