Commits

Chris Klimas committed 8c3352b

Group:add now returns the added object, to aid with initial assignment

e.g. you can write self.player = self:add(Player:new())

Comments (0)

Files changed (30)

 
 		-- blocks
 
-		self.blocks = Group:new()
-		self:add(self.blocks)
+		self.blocks = self:add(Group:new())
 	
 		for x = 480, 750, 50 do
 			for y = 10, 600, 50 do

tests/collisionbenchmark.lua

 		DEBUG = false
 		STRICT = false
 
-		self.blocks = Group:new()
-		self:add(self.blocks)
-		self.countText = Text:new{ x = 10, y = 420, font = 144, width = 200 }
-		self:add(self.countText)
+		self.blocks = self:add(Group:new())
+		self.countText = self:add(Text:new{ x = 10, y = 420, font = 144, width = 200 })
 		self:add(Fill:new{ x = 0, y = 560, width = 800, height = 40, fill = {0, 0, 0, 200} })
 		self:add(Text:new{ x = 10, y = 562, font = 14, width = 600,
 				 text = 'sprites onscreen while maintaining roughly 60 frames per second.\n' ..

tests/collisions.lua

 Collisions = TestApp:extend
 {
 	onRun = function (self)
-		self.player = Fill:new
+		self.player = self:add(Fill:new
 		{
 			x = 16, y = 16, width = 16, height = 16,
 			onStartFrame = function (self)
 					self.fill = { 255, 255, 0 }
 				end
 			end
-		}
+		})
 		
-		self.obstacle = Fill:new
+		self.obstacle = self:add(Fill:new
 		{
 			x = 200, y = 200, width = 96, height = 96, fill = {255, 0, 0},
 			onCollide = function (self, other)
 				self:displace(other)
 			end
-		}
+		})
 								   
-		self.pushable = Fill:new
+		self.pushable = self:add(Fill:new
 		{
 			x = 100, y = 100, width = 48, height = 48, fill = {0, 0, 255},
 			onCollide = function (self, other)
 				other:displace(self)
 			end
-		}
+		})
 							
-		self.collidable = Fill:new{ x = 20, y = 20, width = 32, height = 32,
-									fill = {0, 255, 0} }
+		self.collidable = self:add(Fill:new{ x = 20, y = 20, width = 32, height = 32,
+		                           fill = {0, 255, 0} })
 
-		self.wall = Group:new()
-		self:add(self.wall)
+		self.wall = self:add(Group:new())
 		self.wall:add(CollisionWall:new{ x = 20, y = 100 })
 		self.wall:add(CollisionWall:new{ x = 36, y = 100 })
 		self.wall:add(CollisionWall:new{ x = 52, y = 100 })
 		self.wall:add(CollisionWall:new{ x = 84, y = 100 })
 		self.wall:add(CollisionWall:new{ x = 84, y = 84 })
 
-		self:add(self.collidable)		
-		self:add(self.obstacle)
-		self:add(self.pushable)
-		self:add(self.player)
-
 		self:add(Text:new{ x = 10, y = 560, width = 600, font = 14,
 						   text = 'Use the arrow keys to move. Zoetrope can do basic collision ' ..
 						   'detection based on bounding rectangles, and also have sprites displace each other.' })

tests/debugging.lua

 Debugging = TestApp:extend
 {
 	onRun = function (self)
-		the.block = Fill:new { x = 300, y = 200, width = 200, height = 200, fill = {255, 255, 255 } }
+		the.block = self:add(Fill:new{ x = 300, y = 200, width = 200, height = 200, fill = {255, 255, 255 } })
 		debugger.watch('the.block.x')
 		debugger.watch('the.block.y')
-		self:add(the.block)
 
 		self:add(Text:new
 		{

tests/effects.lua

 {
 	onRun = function (self)
 		self:add(Fill:new{ width = self.width, height = self.height, fill = {200, 200, 200} })
-		the.group = Group:new()
-		self:add(the.group)
+		the.group = self:add(Group:new())
 
 		for i = 1, 100 do
 			the.group:add(Tile:new
 		end
 
 		self:add(Fill:new{ x = 0, y = 550, width = 800, height = 50, fill = {0, 0, 0, 200} })
-		local text = Text:new{ x = 10, y = 560, font = 14, width = 780 }
-		self:add(text)
+		local text = self:add(Text:new{ x = 10, y = 560, font = 14, width = 780 })
 
 		if (love.graphics.isSupported('pixeleffect')) then
 			text.text = 'Press the F key to toggle a fuzzy screen effect, the D key to toggle ' ..

tests/emitters.lua

 	title = 'Particle Emitter',
 
 	onNew = function (self)
-		self.emitter = Emitter:new{ x = 350, y = 250, width = 100, height = 100 }
+		self.emitter = self:add(Emitter:new{ x = 350, y = 250, width = 100, height = 100 })
 		self.emitter.min = { velocity = { x = -500, y = -500, rotation = math.pi / 4 }, alpha = 0.25 }
 		self.emitter.max = { velocity = { x = 500, y = 500, rotation = 4 * math.pi }, alpha = 0.75 }
 		self.emitter.period = 0.05
 		self.emitter:loadParticles(RedParticle, 400)
 		self.emitter:loadParticles(RedParticle:extend{ fill = {0, 255, 0, 128} }, 400)
 
-		self:add(self.emitter)
-
 		self:add(Text:new
 		{
 			x = 10, y = 550, width = 550, font = 14,
 		self.storage.data = { red = 'yes', green = true, blue = 1 }
 		self.storage:save()
 
-		self.label = Text:new{ x = 4, y =4, width = the.app.width, height = the.app.height }
+		self.label = self:add(Text:new{ x = 4, y =4, width = the.app.width, height = the.app.height })
 		self.label.text = 'Saved to storage.dat:\n' .. dump(self.storage.data)
-		self:add(self.label)
 
 		self.countStorage = Storage:new{ filename = 'count.dat' }
 		self.countStorage:load()

tests/gamepad.lua

 				   gp.numButtons .. ' buttons, ' .. gp.numHats .. ' hats'
 		})
 
-		self.controlLabel = Text:new{ x = 4, y = 200, width = 400, height = 400 }
-		self:add(self.controlLabel)
-
-		self.square = Fill:new{ x = 300, y = 300, width = 50, height = 50, fill = {255, 255, 255} }
-		self:add(self.square)
+		self.controlLabel = self:add(Text:new{ x = 4, y = 200, width = 400, height = 400 })
+		self.square = self:add(Fill:new{ x = 300, y = 300, width = 50, height = 50, fill = {255, 255, 255} })
 
 		self:add(Text:new
 		{
 Input = TestApp:extend
 {
 	onNew = function (self)
-		self.released = Sensor:new{ width = 200, height = 400, fill = { 255, 0, 0 } }
-		self:add(self.released)
-		
-		self.justPressed = Sensor:new{ x = 200, width = 200, height = 400, fill = { 0, 255, 0 } }
-		self:add(self.justPressed)
-		
-		self.pressed = Sensor:new{ x = 400, width = 200, height = 400, fill = { 0, 0, 255 } }
-		self:add(self.pressed)
-		
-		self.justReleased = Sensor:new{ x = 600, width = 200, height = 400, fill = { 255, 255, 0 } }
-		self:add(self.justReleased)
-		
-		self.leftMouse = Sensor:new{ y = 400, width = 400, height = 200, fill = { 0, 255, 255 } }
-		self:add(self.leftMouse)
-		
-		self.rightMouse = Sensor:new{ x = 400, y = 400, width = 400, height = 200, fill = { 255, 0, 255 } }
-		self:add(self.rightMouse)
+		self.released = self:add(Sensor:new{ width = 200, height = 400, fill = { 255, 0, 0 } })
+		self.justPressed = self:add(Sensor:new{ x = 200, width = 200, height = 400, fill = { 0, 255, 0 } })
+		self.pressed = self:add(Sensor:new{ x = 400, width = 200, height = 400, fill = { 0, 0, 255 } })
+		self.justReleased = self:add(Sensor:new{ x = 600, width = 200, height = 400, fill = { 255, 255, 0 } })
+		self.leftMouse = self:add(Sensor:new{ y = 400, width = 400, height = 200, fill = { 0, 255, 255 } })
+		self.rightMouse = self:add(Sensor:new{ x = 400, y = 400, width = 400, height = 200, fill = { 255, 0, 255 } })
 
-		self.extraLabel = Text:new
+		self.extraLabel = self:add(Text:new
 		{
 			x = 10, y = 10, width = 200
-		}
-		self:add(self.extraLabel)
+		})
 
 		self:add(Text:new
 		{
 	onRun = function (self)	
 		-- programmatically created map
 	
-		local map = Map:new{ x = 124, y = 10, spriteWidth = 16, spriteHeight = 16 }
+		local map = self:add(Map:new{ x = 124, y = 10, spriteWidth = 16, spriteHeight = 16 })
 		map:empty(16, 16)
 		
 		local x, y
 		map.sprites[2] = Fill:new{ width = 16, height = 16, fill = {0, 255, 0} }
 		map.sprites[3] = Fill:new{ width = 16, height = 16, fill = {0, 0, 255} }
 		map.sprites[4] = Tile:new{ width = 16, height = 16, image = mario }
-		self:add(map)
 		
 		-- map loaded from CSV
 		
-		self.map2 = Map:new{ x = 256, y = 300, spriteWidth = 24, spriteHeight = 24 }
+		self.map2 = self:add(Map:new{ x = 256, y = 300, spriteWidth = 24, spriteHeight = 24 })
 		self.map2:loadMap('tests/assets/map.csv')
 		self.map2.sprites[1] = Fill:new{ width = 24, height = 24, fill = {0, 0, 255},
 			onCollide = function (self, other)
 				self:displace(other)
 			end }
-		self:add(self.map2)
 		
 		-- map with loadTiles() used
 		
-		local map3 = Map:new{ x = 400, y = 10, spriteWidth = 16, spriteHeight = 16 }
+		local map3 = self:add(Map:new{ x = 400, y = 10, spriteWidth = 16, spriteHeight = 16 })
 		map3:loadTiles('tests/assets/tiles.png')
 		map3:empty(16, 16)
 		
 			end
 		end
 		
-		self:add(map3)
-		
 		-- player for testing collisions
 		
-		self.player = Fill:new{ x = 380, y = 380, width = 16, height = 16 }
-		self:add(self.player)
+		self.player = self:add(Fill:new{ x = 380, y = 380, width = 16, height = 16 })
 
 		self:add(Text:new
 		{

tests/recording.lua

 Recording = TestApp:extend
 {
 	onNew = function (self)
-		self.recorder = Recorder:new()
-		self.meta:add(self.recorder)
+		self.recorder = self.meta:add(Recorder:new())
+		self.player = self:add(Fill:new{ x = 100, y = 100, width = 16, height = 16, fill = { 255, 255, 255 } })
 
-		local cursor = Cursor:new()
+		local cursor = self:add(Cursor:new())
 		cursor:add(Fill:new{ width = 8, height = 8, fill = { 255, 0, 0 } })
 		self:useSysCursor(false)
 
-		self.player = Fill:new{ x = 100, y = 100, width = 16, height = 16, fill = { 255, 255, 255 } }
-
-		self.recLabel = Text:new { x = 750, y = 10, tint = { 1, 0, 0 }, text = 'REC', visible = false } 
+		self.recLabel = self:add(Text:new{ x = 750, y = 10, tint = { 1, 0, 0 }, text = 'REC', visible = false })
 		self.view.tween:start(self.recLabel, 'alpha', 0, 0.25):andThen(Tween.reverseForever)
 
-		self:add(self.player)
-		self:add(cursor)
-		self:add(self.recLabel)
-
 		self:add(Text:new
 		{
 			x = 10, y = 510, width = 600, font = 14,
 Reuse = TestApp:extend
 {
 	onNew = function (self)
-		self.particles = Group:new()
-		self:add(self.particles)
-		self.label = Text:new{ x = 10, y = 500, font = 48, width = 800, text = '0 sprites created' }
-		self:add(self.label)
-
+		self.particles = self:add(Group:new())
+		self.label = self:add(Text:new{ x = 10, y = 500, font = 48, width = 800, text = '0 sprites created' })
 		self:add(Text:new{ x = 10, y = 560, width = 640, font = 14,
 						   text = 'Press the R, G, and B keys to create sprites of different hues. ' ..
 						   'When a sprite goes offscreen, it is automatically reused. Zoetrope\'s Factory ' ..

tests/scrolling.lua

 	onRun = function (self)
 		local x
 		
-		local layer1 = Group:new()
+		local layer1 = self:add(Group:new())
 		layer1.translateScale.x = 0.25
 		layer1.translateScale.y = 0.25
-		self:add(layer1)
 		
 		for x = 16, self.width * 5, 64 do
 			layer1:add(Tile:new{ x = x, y = 100, image = 'tests/assets/bluegem.png', scale = 0.5 })
 		end
 		
-		local layer2 = Group:new()
+		local layer2 = self:add(Group:new())
 		layer2.translateScale.x = 0.5
 		layer2.translateScale.y = 0.5
-		self:add(layer2)
 		
 		for x = 16, self.width * 5, 64 do
 			layer2:add(Tile:new{ x = x, y = 150, image = 'tests/assets/bluegem.png' })
 		end
 		
-		local layer3 = Group:new()
-		self:add(layer3)
+		local layer3 = self:add(Group:new())
 		
 		for x = 16, self.width * 5, 64 do
 			layer3:add(Tile:new{ x = x, y = 200, image = 'tests/assets/bluegem.png', scale = 2 })
 		end
 		
-		local layer4 = Group:new()
+		local layer4 = self:add(Group:new())
 		layer4.translateScale.x = 0
 		layer4.translateScale.y = 0
-		self:add(layer4)
 		
 		for x = 16, self.width * 5, 100 do
 			layer4:add(Tile:new{ x = x, y = 400, image = 'tests/assets/bluegem.png', scale = 4 })
 Sounds = TestApp:extend
 {
 	onNew = function (self)
-		self.timer = Timer:new()
-		self:add(self.timer)
+		self.timer = self:add(Timer:new())
 		self.testSound = sound('tests/assets/tone.mp3')
 		self.testSound:play(1)
 		self.testSound:setVolume(0.25)
 		
-		self.signal = Fill:new{ x = 100, y = 100, width = 100, height = 100, fill = { 0, 0, 255 } }
-		self:add(self.signal)
+		self.signal = self:add(Fill:new{ x = 100, y = 100, width = 100, height = 100, fill = { 0, 0, 255 } })
 
 		self.timer:after(1, bind(self.testSound, 'play'))
 

tests/spritebenchmark.lua

 		DEBUG = false
 		STRICT = false
 
-		self.blocks = Group:new()
-		self:add(self.blocks)
-		self.countText = Text:new{ x = 10, y = 440, font = 144, width = 200 }
-		self:add(self.countText)
+		self.blocks = self:add(Group:new())
+		self.countText = self:add(Text:new{ x = 10, y = 440, font = 144, width = 200 })
 		self:add(Fill:new{ x = 0, y = 580, width = 800, height = 20, fill = {0, 0, 0, 200} })
 		self:add(Text:new{ x = 10, y = 582, font = 14, width = 600,
 				 text = 'sprites onscreen while maintaining roughly 60 frames per second.' })

tests/spritetypes.lua

 			text = 'A Tile stamps an image or repeats it across a rectangular area.'
 		})
 		
-		local anim = Animation:new
+		local anim = self:add(Animation:new
 		{
 			x = 600, y = 45,
 			width = 16, height = 24,
 			image = self.chestAnim,
 			sequences = { open = { frames = { 1, 2, 3, 4, 5, 4, 3, 2 }, fps = 10 } }
-		}
+		})
 
 		anim:play('open')
-		self:add(anim)
 
-		local anim2 = Animation:new
+		local anim2 = self:add(Animation:new
 		{
 			x = 640, y = 45,
 			width = 16, height = 24,
 			sequences = { open = { frames = { 1, 2, 3, 4, 5, 4, 3, 2 }, fps = 10 } },
 		  	tint = { 0.5, 1, 0.5 }, alpha = 0.5,
 			velocity = { rotation = math.pi }, scale = 3
-		}
+		})
 		anim2:play('open')
-		self:add(anim2)
 
 		self:add(Text:new
 		{

tests/subview.lua

 		self.subview = Subview:new
 		{
 			onNew = function (self)
-				self.bg = Fill:new{ x = (the.app.width - 300) / 2, y = 100,
-								    height = 50, width = 300, fill = {255, 255, 255} }
-				self:add(self.bg)
+				self.bg = self:add(Fill:new{ x = (the.app.width - 300) / 2, y = 100,
+								    height = 50, width = 300, fill = {255, 255, 255} })
 				self:add(Text:new{ x = (the.app.width - 300) / 2 + 10, y = 110,
 								   width = 280, align = 'center', tint = {0, 0, 0},
 								   text = 'Press the S key again to hide this overlay.', font = 14 })
 		self.view:clampTo(self.view.map)
 		self.view.focus = the.player
 		
-		local overlay = Group:new({ translateScale = { x = 0, y = 0 } })
+		local overlay = self:add(Group:new({ translateScale = { x = 0, y = 0 } }))
 		
 		overlay:add(Fill:new{ x = 0, y = 550, width = 800, height = 50, fill = {0, 0, 0, 200} })
 		overlay:add(Text:new
 			text = 'Move the square with the arrow keys to explore the map. Zoetrope can load tilemaps and objects created in Tiled, and respects layer ' ..
 				   'order. Connecting an object to a class is as simple as giving it a name.'
 		})
-
-		self:add(overlay)
 	end,
 
 	onUpdate = function (self)
 Timers = TestApp:extend
 {
 	onRun = function (self)
-		self.red = Fill:new{ x = 200, y = 250, width = 100, height = 100, fill = { 255, 0, 0 }, visible = false }
-		self:add(self.red)
-		
-		self.green = Fill:new{ x = 350, y = 250, width = 100, height = 100, fill = { 0, 255, 0 }, visible = false }
-		self:add(self.green)
-		
-		self.blue = Fill:new{ x = 500, y = 250, width = 100, height = 100, fill = { 0, 0, 255 }, visible = false }
-		self:add(self.blue)
+		self.red = self:add(Fill:new{ x = 200, y = 250, width = 100, height = 100, fill = { 255, 0, 0 }, visible = false })
+		self.green = self.add(Fill:new{ x = 350, y = 250, width = 100, height = 100, fill = { 0, 255, 0 }, visible = false })
+		self.blue = self.add(Fill:new{ x = 500, y = 250, width = 100, height = 100, fill = { 0, 0, 255 }, visible = false })
 		
 		self.view.timer:after(1, bind(self, 'toggle', self.red))
 			:andThen(bind(self.view.timer, 'after', 1, bind(self, 'toggle', self.blue)))
 		local y = 250
 		
 		for easer, _ in pairs(Tween.easers) do
-			local block = Fill:new{ x = 200, y = y, width = 25, height = 25 }
-			self:add(block)
+			local block = self.add(Fill:new{ x = 200, y = y, width = 25, height = 25 })
 			self.view.tween:start(block, 'x', 275, 1, easer):andThen(Tween.reverseForever)
 			y = y + 25
 		end
 		
-		local alphaBlock = Fill:new{ x = 350, y = 250, width = 100, height = 100 }
-		self:add(alphaBlock)
+		local alphaBlock = self.add(Fill:new{ x = 350, y = 250, width = 100, height = 100 })
 		
-		local colorBlock = Fill:new{ x = 500, y = 250, width = 100, height = 100,
-									  fill = { 255, 0, 0 } }
-		self:add(colorBlock)
+		local colorBlock = self:add(Fill:new{ x = 500, y = 250, width = 100, height = 100,
+		                                      fill = { 255, 0, 0 } })
 		self.view.tween:start(colorBlock, 'fill', { 0, 0, 255 }):andThen(Tween.reverseForever)
 
 		self:add(Text:new
 	name = 'UI Test',
 
 	onRun = function (self)
-		local cursor = Cursor:new()
-		cursor:add(Tile:new{ image = 'tests/assets/bluegem.png', scale = 1.5,
-							 velocity = { x = 0, y = 0, rotation = math.pi } })
-		cursor.hotspot.x = 12
-		cursor.hotspot.y = 12
-
-		local button = Button:new{ x = 250, y = 200, width = 300, height = 100 }
+		local button = self:add(Button:new{ x = 250, y = 200, width = 300, height = 100 })
 		button.background = Fill:new{ width = 300, height = 100,
 									  fill = {25, 25, 25}, border = {255, 255, 255} }
 		button.label = Text:new{ text = 'Hello', font = 72, width = 100, align = 'center' }
 			self.y = math.random(0, the.app.height - self.height - 300)
 		end
 
-		local input = TextInput:new{ x = 250, y = 350, width = 300, height = 24, font = 72 }
+		local input = self:add(TextInput:new{ x = 250, y = 350, width = 300, height = 24, font = 72 })
+
+		local cursor = self:add(Cursor:new())
+		cursor:add(Tile:new{ image = 'tests/assets/bluegem.png', scale = 1.5,
+							 velocity = { x = 0, y = 0, rotation = math.pi } })
+		cursor.hotspot.x = 12
+		cursor.hotspot.y = 12
 
 		self.meta:add(DebugConsole:new())
 		the.console:watch('mouse clicked', 'the.mouse._thisFrame.l == true')
 
-		self:add(input)
-		self:add(button)
-		self:add(cursor)
-
 		self:add(Text:new
 		{
 			x = 10, y = 550, width = 600, font = 14,

zoetrope/core/app.lua

 	--		sprite - sprite to add
 	-- 
 	-- Returns:
-	--		nothing
+	--		sprite added
 
 	add = function (self, sprite)
-		self.view:add(sprite)
+		return self.view:add(sprite)
 	end,
 
 	-- Method: remove

zoetrope/core/group.lua

 	--		sprite - <Sprite> to add
 	--
 	-- Returns:
-	--		nothing
+	--		the sprite added, so you can write things like
+	-- 		self.player = self:add(Player:new())      
 
 	add = function (self, sprite)
 		assert(sprite, 'asked to add nil to a group')
 		end
 
 		table.insert(self.sprites, sprite)
+		return sprite
 	end,
 
 	-- Method: remove
 				end
 
 				if layer.type == 'tilelayer' then
-					local map = Map:new{ spriteWidth = data.tilewidth, spriteHeight = data.tileheight }
+					local map = self:add(Map:new{ spriteWidth = data.tilewidth, spriteHeight = data.tileheight })
 					map:empty(layer.width, layer.height)
 
 					-- load tiles
 					end
 
 					self[layer.name] = map
-					self:add(map)
 				elseif layer.type == 'objectgroup' then
-					local group = Group:new()
+					local group = self:add(Group:new())
 
 					for _, obj in pairs(layer.objects) do
 						-- roll in tile properties if based on a tile
 						if obj.properties._the then
 							the[obj.properties._the] = spr
 						end
-
-						group:add(spr)
 					end
 
 					self[layer.name] = group

zoetrope/debug/console.lua

 	onNew = function (self)
 		self.title.text = 'Console'
 
-		self.log = Text:new{ font = self.font }
-		self:add(self.log)
-
-		self.prompt = Text:new{ font = self.font, text = '>' }
-		self:add(self.prompt)
+		self.log = self:add(Text:new{ font = self.font })
+		self.prompt = self:add(Text:new{ font = self.font, text = '>' })
 
 		local w = self.prompt:getSize()
 		self.inputIndent = w
 		self.lineHeight = self.log._fontObj:getHeight()
 
-		self.input = TextInput:new
+		self.input = self:add(TextInput:new
 		{
 			font = self.font,
 			onType = function (self, char)
 				return char ~= debugger.consoleKey
 			end
-		}
-		self:add(self.input)
+		})
 
 		-- hijack print function
 		-- this is nasty to debug if it goes wrong, be careful

zoetrope/debug/instrument.lua

 			obj.font = 11
 		end
 
-		obj.outerFrame = Fill:new{ width = 0, height = 0, border = obj.outerBorderColor, fill = {0, 0, 0, 0} }
-		obj.innerFrame = Fill:new{ width = 0, height = 0, border = obj.innerBorderColor, fill = obj.backgroundColor }
-		obj.titleBar = Fill:new{ width = 0, height = obj.titleBarHeight, fill = obj.titlebarColor }
-		obj.title = Text:new{ width = 0, height = 0, fill = obj.titlebarColor, font = obj.font,
-		                      tint = {obj.titleColor[1] / 255, obj.titleColor[2] / 255, obj.titleColor[3] / 255}}
-		obj:add(obj.outerFrame)
-		obj:add(obj.innerFrame)
-		obj:add(obj.titleBar)
-		obj:add(obj.title)
+		obj.outerFrame = obj:add(Fill:new{ width = 0, height = 0, border = obj.outerBorderColor, fill = {0, 0, 0, 0} })
+		obj.innerFrame = obj:add(Fill:new{ width = 0, height = 0, border = obj.innerBorderColor, fill = obj.backgroundColor })
+		obj.titleBar = obj:add(Fill:new{ width = 0, height = obj.titleBarHeight, fill = obj.titlebarColor })
+		obj.title = obj:add(Text:new{ width = 0, height = 0, fill = obj.titlebarColor, font = obj.font,
+		                      tint = {obj.titleColor[1] / 255, obj.titleColor[2] / 255, obj.titleColor[3] / 255}})
 
 		if obj.onNew then obj:onNew() end
 		return obj

zoetrope/debug/locals.lua

 
 	onNew = function (self)
 		self.title.text = 'Locals'
-		self.names = Text:new{ font = self.font }
-		self.values = Text:new{ font = self.font }
+		self.names = self:add(Text:new{ font = self.font })
+		self.values = self:add(Text:new{ font = self.font })
 		self.lineHeight = self.names._fontObj:getHeight()
-		self:add(self.names)
-		self:add(self.values)
 
 		debugger.showLocals = function (level) self:showLocals(level) end
 		debugger.hideLocals = function (level) self.visible = false end

zoetrope/debug/shortcuts.lua

 			label = label .. ' (' .. key .. ')'
 		end
 
-		local button = DebugInstrumentButton:new
+		local button = self:add(DebugInstrumentButton:new
 		{
 			label = label,
 			onMouseUp = func
-		}
+		})
 
 		button.label.font = 11
 		button.label.y = 6
 		button.background.height = 24
 		
-		self:add(button)
 		table.insert(self._buttons, button)
 
 		self.contentHeight = #self._buttons * (DebugInstrumentButton.height + self.spacing) + 2 * self.spacing

zoetrope/debug/stack.lua

 
 	onNew = function (self)
 		self.title.text = 'Stack'
-		self.text = Text:new{ font = self.font, wordWrap = false }
+		self.text = self:add(Text:new{ font = self.font, wordWrap = false })
 		self.lineHeight = self.text._fontObj:getHeight()
-		self:add(self.text)
 
 		debugger.showStack = function (level) self:showStack(level) end
 		debugger.hideStack = function() self.visible = false end

zoetrope/debug/stepper.lua

 	_fileCache = {},
 
 	onNew = function (self)
-		self.stepButton = DebugInstrumentButton:new
+		self.stepButton = self:add(DebugInstrumentButton:new
 		{
 			label = 'Step',
 			onMouseUp = function (self)
 				debugger._stepCommand = 'next'
 			end
-		}
-		self:add(self.stepButton)
+		})
 
-		self.continueButton = DebugInstrumentButton:new
+		self.continueButton = self:add(DebugInstrumentButton:new
 		{
 			label = 'Continue',
 			onMouseUp = function (self)
 				debugger._stepCommand = 'continue'
 			end
-		}
-		self:add(self.continueButton)
+		})
 
-		self.lineHighlight = Fill:new{ fill = {64, 64, 64} }
-		self:add(self.lineHighlight)
+		self.lineHighlight = self:add(Fill:new{ fill = {64, 64, 64} })
 
-		self.sourceLines = Text:new
+		self.sourceLines = self:add(Text:new
 		{
 			font = self.font,
 			width = 20,
 			align = 'right',
 			wordWrap = false,
-		}
-		self:add(self.sourceLines)
+		})
 
-		self.sourceView = Text:new{ font = self.font, wordWrap = false }
+		self.sourceView = self:add(Text:new{ font = self.font, wordWrap = false })
 		self.lineHeight = self.sourceView._fontObj:getHeight()
-		self:add(self.sourceView)
 
 		self.title.text = 'Source'
 		self.contentHeight = self.lineHeight * (self.lineContext + 1) * 2 + self.spacing * 3 +

zoetrope/debug/watch.lua

 
 	onNew = function (self)
 		self.title.text = 'Watch'
-		self.labels = Text:new{ font = self.font }
-		self.values = Text:new{ font = self.font }
+		self.labels = self:add(Text:new{ font = self.font })
+		self.values = self:add(Text:new{ font = self.font })
 		self.lineHeight = self.labels._fontObj:getHeight()
-		self:add(self.labels)
-		self:add(self.values)
 
 		self:addExpression('love.timer.getFPS()', 'FPS')
 		self:addExpression('math.floor(collectgarbage("count") / 1024) .. "M"', 'Memory used')