Home TI-Nspire Authoring Lua Scripting HQ Lua and JavaScript


Todo:
- Image support
- Font size support
- Physics support
- Toolpallete support
- Clipboard
- D2Editor
- coroutine (possibly not possible)
- string functions
- keyboard improvements
-- by Marc Garneau, 2012 
 -- piman@telus.net 
 -- http://web.me.com/piman2/PimanNspire/Blog/Blog.html 
 -- presented at T^3 International Conference • Chicago, IL • March 3, 2012 

-- This is a simple version of using counters to model integers, 
 -- for the purpose of introducing classes in a workshop. 
-- There are other features I plan to add later; see list at bottom. 

platform.apilevel = '1.0' 

Color = { 
 red = {0xFF, 0x00, 0x00}, 
 yellow = {0xFF, 0xFF, 0x00}, 
} 

function reset() 
 
-- The Objects list will get new generated counters, but starts with one. 
 Objects = { 
  Circle(xstart, ystartred, W/20, "red",-1), 
  Circle(xstart, ystartyellow, W/20, "yellow",1), 
 } 
 
 z = 1 
 
end 

function on.resize() 
 W = platform.window:width() 
 H = platform.window:height() 
 
 xstart = 7*W/8 
 xmat = 3*W/4 
 ystartyellow = H/2 
 ystartred = 5*H/6 
  
 TrackedObject = nil 
 
-- TrackOffsetx = 0 
-- TrackOffsety = 0 
 
 reset() 
 
end 

Circle = class() 

function Circle:init(x, y, radius,color,value) 
 self.x = x 
 self.y = y 
 self.radius = radius 
 self.color = Color[color] 
 self.selected = false 
 self.value = value 
end 

function Circle:contains(x, y) 
 local r = self.radius 
 local d = math.sqrt((self.x - x)^2 + (self.y - y)^2) 
 return d <= r 
end 

function Circle:paint(gc) 
 local cx = self.x - self.radius 
 local cy = self.y - self.radius 
 local diameter = 2*self.radius 
 gc:setColorRGB(unpack(self.color)) 
 gc:fillArc(cx, cy, diameter, diameter, 0, 360) 
 gc:setPen("thin","smooth") 
 gc:setColorRGB(0, 0, 0) 
 gc:drawArc(cx, cy, diameter, diameter, 0, 360) 
 if self.selected then 
  gc:setPen("medium","smooth") 
  gc:setColorRGB(0, 0, 0) 
  gc:drawArc(cx, cy, diameter, diameter, 0, 360) 
 end 
end 

-- this does more than count the value of the counters; it also sends counters back to their starting position if they are moved to the right of the mat; 
-- it also moves counters back onto the mat if they go too far off of the mat 
function count() 
 value = 0 
 for i = 1, #Objects do 
  local obj = Objects[i] 
  if obj.x < xmat then 
   value = value + obj.value 
  else 
   obj.x = xstart 
   if obj.value == 1 then 
    obj.y = ystartyellow 
   else 
    obj.y = ystartred 
   end 
  end 
  if obj.x < 0 then 
   obj.x = obj.radius 
  end 
  if obj.y > H then 
   obj.y = H-obj.radius 
  end 
  if obj.y < 0 then 
   obj.y = obj.radius 
  end 
 end 
end 

function on.mouseDown(x,y) 
 for i = 1, #Objects do 
  local obj = Objects[i] 
  
  if obj:contains(x, y) then 
   TrackedObject = obj 
   obj.selected = true 
-- this avoids the object jumping to centre when you don't put the mouse down in the centre 
--   TrackOffsetx = TrackedObject.x - x 
--   TrackOffsety = TrackedObject.y - y 
-- this is the coolest part; if I grab a counter from the right, it will create a new one to replenish the supply! 
   if obj.x == xstart then 
    if obj.y == ystartred then 
     table.insert(Objects, Circle(xstart, ystartred, W/20, "red",-1)) 
    else 
     table.insert(Objects, Circle(xstart, ystartyellow, W/20, "yellow",1)) 
    end 
   end 
   platform.window:invalidate() 
   break 
  end 
 end 
end 

function on.mouseUp(x,y) 
 if TrackedObject ~= nil then 
  TrackedObject.selected = false 
 end 
 TrackedObject = nil 
 platform.window:invalidate() 
end 

function on.mouseMove(x,y) 
 if TrackedObject ~= nil then 
  TrackedObject.x = x -- + TrackOffsetx 
  TrackedObject.y = y -- + TrackOffsety 
  platform.window:invalidate() 
 end 
end 

-- use tab key to toggle whether the value shows or not 
function on.tabKey() 
 if z == 0 then 
  z = 1 
 else 
  z = 0 
 end 
 platform.window:invalidate() 
end 

function on.charIn(char) 
 if char=="r" or char=="R" then 
  reset() 
 end 
 platform.window:invalidate() 
end 


function on.deleteKey() 
 reset() 
 platform.window:invalidate() 
end 

function on.paint(gc) 
 gc:setColorRGB(204,204,204) 
 gc:fillRect(0,0,xmat,H) 
 gc:setColorRGB(0,0,0) 
 gc:setPen("thick","smooth") 
 gc:drawRect(xmat,0,0,H) 
 for hippo, obj in ipairs(Objects) do 
  obj:paint(gc) 
 end 
 count() 
 gc:setColorRGB(0,0,0) 
 gc:setFont("sansserif","r",10) 
 if #Objects > 2 then 
  gc:drawString("(R)eset",5,0.99*H) 
 end 
 if z == 1 then 
--  gc:drawString("Press TAB to hide total value.",10,20) 
  gc:setFont("sansserif", "b", 10) 
  gc:drawString("Value = "..value,xmat+W/50,20) 
 else 
--  gc:drawString("Press TAB to show total value.",10,20) 
 end 
 gc:setFont("sansserif", "b", 16) 
 gc:drawString("+",xstart-W/50,ystartyellow-W/20) 
 gc:drawString("-",xstart-W/50,ystartred-W/20) 
end 

-- Things to do next 
 -- Track off-set to avoid pointer jumping to center of each counter 
 -- zero pairs 
 -- Use arrow keys to undo/redo 
 -- Animate movement 
 -- Snap counters to grid, with overlap causing a 0 
 -- menu to choose colours of counters 
 -- give a number line representation of what's being modeled (maybe just do that on a split page with a Graph's app) 
 -- change pointer to hand