goo.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. -- Filename: goo.lua
  2. -- Author: Luke Perkin
  3. -- Date: 2010-02-25
  4. require 'goo/MiddleClass'
  5. require 'goo/MindState'
  6. -- Initialization
  7. local goo = {}
  8. --goo.animation = require 'goo.animation.animation'
  9. goo.skin = 'goo/skins/default/'
  10. GOO_SKINPATH = goo.skin
  11. goo.style, goo.fonts = require( goo.skin .. 'style')
  12. function goo:setSkin( skin_name )
  13. skin_name = skin_name or 'default'
  14. goo.skin = 'goo/skins/' .. skin_name .. '/'
  15. GOO_SKINPATH = goo.skin
  16. goo.style, goo.fonts = require( goo.skin .. 'style' )
  17. end
  18. function goo:setSkinAllObjects( skin_name )
  19. self:setSkin( skin_name )
  20. for k,v in pairs(self.objects) do
  21. v:setSkin()
  22. end
  23. for k,v in pairs(self.BASEOBJECT.children) do
  24. v:resetStyle()
  25. end
  26. end
  27. goo.base = class('goo')
  28. function goo.base:initialize()
  29. self.visible = true
  30. self.parent = self
  31. self.children = {}
  32. self.x, self.y = 0, 0
  33. self.xscale, self.yscale = 1, 1
  34. self.mousehover = nil
  35. end
  36. function goo.base:update()
  37. if self.mousehover then
  38. if not self.mousehover.hoverState then self.mousehover:enterHover() end
  39. self.mousehover.hoverState = true
  40. end
  41. self.mousehover = self
  42. end
  43. function goo.base:draw() end
  44. function goo.base:mousepressed() end
  45. function goo.base:mousereleased() end
  46. function goo.base:keypressed() end
  47. function goo.base:keyreleased() end
  48. function goo.base:getAbsolutePos() return 0,0 end
  49. function goo.base:getRelativePos() return 0,0 end
  50. function goo.base:getAbsoluteScale() return 1,1 end
  51. function goo.base:getRelativeScale() return 1,1 end
  52. function goo.base:enterHover() end
  53. function goo.base:exitHover() end
  54. function goo.base:setSkin() end
  55. goo.object = class('goo object')
  56. goo.objects = {}
  57. function goo.object:initialize(parent)
  58. if parent then
  59. table.insert(parent.children,self)
  60. self.parent = parent
  61. else
  62. table.insert( goo.BASEOBJECT.children, self )
  63. self.parent = goo.BASEOBJECT
  64. end
  65. self.z = #self.parent.children
  66. if goo.style[self.class.name] then
  67. self.style = goo.style[self.class.name]
  68. end
  69. self.x = 0
  70. self.y = 0
  71. self.h = 0
  72. self.w = 0
  73. self.xscale = 1
  74. self.yscale = 1
  75. self.lastX = 0
  76. self.lastY = 0
  77. self.bounds = {x1=0,y1=0,x2=0,y2=0}
  78. self.color = {255,255,255,255}
  79. self.children = {}
  80. self.visible = true
  81. self.hoverState = true
  82. end
  83. --- Destroys the object.
  84. -- @class table
  85. function goo.object:destroy()
  86. if self.parent then
  87. for k,v in pairs(self.parent.children) do
  88. if v == self then table.remove(self.parent.children,k) end
  89. end
  90. end
  91. for i,child in ipairs(self.children) do
  92. child:destroy()
  93. end
  94. self = nil
  95. return
  96. end
  97. function goo.object:update(dt)
  98. if self:inBounds( love.mouse.getPosition() ) then
  99. goo.BASEOBJECT.mousehover = self
  100. else
  101. if self.hoverState then self:exitHover() end
  102. self.hoverState = false
  103. end
  104. if love.mouse.isDown('l') then
  105. -- Left mouse button pressed
  106. else
  107. if self.dragState then
  108. self.dragState = false
  109. self:recurse('children', 'updateBounds')
  110. end
  111. end
  112. if self.x ~= self.lastX or self.y ~= self.lastY then
  113. self:recurse('children', 'updateBounds')
  114. end
  115. self.lastX = self.x
  116. self.lastY = self.y
  117. end
  118. function goo.object:draw(x,y)
  119. --love.graphics.push()
  120. --love.graphics.scale( self.xscale, self.yscale )
  121. --love.graphics.translate(x,y)
  122. end
  123. function goo.object:mousepressed(x,y,button)
  124. if self.hoverState and self.onClick then
  125. self:onClick(x,y,button)
  126. end
  127. end
  128. function goo.object:mousereleased(x,y,button)
  129. end
  130. function goo.object:keypressed() end
  131. function goo.object:keyreleased() end
  132. function goo.object:setPos( x, y )
  133. self.x = x or 0
  134. self.y = y or 0
  135. self:updateBounds()
  136. end
  137. function goo.object:setSize( w, h )
  138. self.w = w or self.w
  139. self.h = h or self.h
  140. self:updateBounds()
  141. end
  142. function goo.object:setScale( x, y )
  143. self.xscale = x or 1
  144. self.yscale = y or self.xscale
  145. end
  146. function goo.object:setVisible( bool )
  147. self.visible = bool
  148. end
  149. function goo.object:inBounds( x, y )
  150. local ax, ay = self:getAbsolutePos()
  151. if x > ax and x < ax + self.w and y > ay and y < ay + self.h then
  152. return true
  153. else
  154. return false
  155. end
  156. end
  157. -- DELETE:
  158. function goo.object:isMouseHover()
  159. if not self.bounds then return false end
  160. local x, y = love.mouse.getPosition()
  161. local x1, y1, x2, y2 = self.bounds.x1, self.bounds.y1, self.bounds.x2, self.bounds.y2
  162. if x > x1 and x < x2 and y > y1 and y < y2 then
  163. return true
  164. else
  165. return false
  166. end
  167. end
  168. function goo.object:enterHover() end
  169. function goo.object:exitHover() end
  170. function goo.object:updateBounds()
  171. local x, y = self:getAbsolutePos()
  172. local xs, ys = self:getAbsoluteScale()
  173. local xoff, yoff = self.xoffset or 0, self.yoffset or 0
  174. self.bounds.x1 = x + xoff
  175. self.bounds.y1 = y + yoff
  176. self.bounds.x2 = x + (self.w + xoff)*xs
  177. self.bounds.y2 = y + (self.h + yoff)*ys
  178. end
  179. function goo.object:recurse(key,func,...)
  180. local _tbl = arg or {}
  181. self[func](self, ...)
  182. for k,v in pairs(self.children) do
  183. v:recurse(key,func,...)
  184. end
  185. end
  186. function goo.object:setText( text )
  187. self.text = text
  188. self:updateBounds()
  189. end
  190. function goo.object:getAbsolutePos( x, y )
  191. local x, y = x or self.x, y or self.y
  192. local _x, _y = self.parent:getAbsolutePos()
  193. return _x+(x*self.parent.xscale), _y+(y*self.parent.yscale)
  194. end
  195. function goo.object:getAbsoluteScale( xscale, yscale )
  196. local xscale, yscale = xscale or self.xscale, yscale or self.yscale
  197. local _x, _y = self.parent:getAbsoluteScale()
  198. return _x*xscale, _y*yscale
  199. end
  200. function goo.object:getRelativePos( x, y )
  201. local x = x or 0
  202. local y = y or 0
  203. return (x-self.x), (y-self.y)
  204. end
  205. function goo.object:getRelativeScale( xscale, yscale )
  206. local xscale, yscale = xscale or 1, yscale or 1
  207. return xscale*self.xscale, yscale*self.yscale
  208. end
  209. function goo.object:sizeToContents()
  210. local _font = love.graphics.getFont()
  211. self.w = _font:getWidth(self.text) + (self.spacing or 0)
  212. self.h = _font:getHeight() + (self.spacing or 0)
  213. self.yoffset = -self.h
  214. self:updateBounds()
  215. end
  216. function goo.object:setStyle(style)
  217. local _style = self.style
  218. self.style = {}
  219. for k,v in pairs(_style) do
  220. self.style[k] = v
  221. end
  222. if type(style) == 'table' then
  223. for k,v in pairs(style) do
  224. self.style[k] = v
  225. end
  226. if self.styleDidUpdate then self:styleDidUpdate() end
  227. return true
  228. elseif type(style) == 'string' then
  229. for k,v in pairs(goo.style[style]) do
  230. self.style[k] = v
  231. end
  232. if self.styleDidUpdate then self:styleDidUpdate() end
  233. return true
  234. end
  235. return false
  236. end
  237. -- Resets the style.
  238. function goo.object:resetStyle()
  239. self.style = goo.style[self.class.name]
  240. self:enterHover()
  241. self:exitHover()
  242. end
  243. function goo.object:removeFromParent()
  244. local size = #self.parent.children
  245. local tbl = self.parent.children
  246. tbl[self.z] = nil
  247. for i=self.z, size-1 do
  248. tbl[i] = tbl[i+1]
  249. tbl[i].z = i
  250. end
  251. tbl[size] = nil
  252. end
  253. function goo.object:addToParent( parent )
  254. self.parent = parent
  255. table.insert(parent.children,self)
  256. self.z = #self.parent.children
  257. end
  258. function goo.object:getOpacity()
  259. return self.opacity or self.parent.opacity or 255
  260. end
  261. function goo.object:setOpacity( opacity )
  262. self.opacity = opacity
  263. end
  264. function goo.object:setColor( a, b, c, d )
  265. if type(a) == 'table' then
  266. local op
  267. if a[4] then
  268. op = a[4]
  269. else
  270. op = self.opacity or self.parent.opacity or 255
  271. end
  272. love.graphics.setColor( a[1], a[2], a[3], op )
  273. else
  274. if d then
  275. love.graphics.setColor( a, b, c, d )
  276. else
  277. love.graphics.setColor( a, b, c )
  278. end
  279. end
  280. end
  281. function goo.object:setSkin()
  282. end
  283. --[[
  284. function goo.object:setColor2(r,g,b,a)
  285. self.color = {r or self.color[1], g or self.color[2], b or self.color[3], a or self.color[4]}
  286. end]]--
  287. --
  288. --
  289. -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  290. -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  291. --
  292. -- Load
  293. function goo:load()
  294. self.graphics = {}
  295. self.graphics.roundrect = require 'goo/graphics/roundrect'
  296. -- Baseobject is the master parent for all objects.
  297. self.BASEOBJECT = self.base:new()
  298. -- Load all objects
  299. local object_list = love.filesystem.enumerate( 'goo/objects' )
  300. for k,v in pairs( object_list ) do
  301. goo.objects[v] = require( 'goo/objects/'..v:sub(1,-5) )
  302. if goo.objects[v] and goo.objects[v].setSkin then goo.objects[v]:setSkin() end
  303. end
  304. end
  305. -- Logic
  306. function goo:update( dt, object )
  307. local object = object or self.BASEOBJECT
  308. object:update(dt)
  309. for k,child in pairs(object.children) do
  310. if child.visible then self:update(dt,child) end
  311. end
  312. end
  313. -- Scene Drawing
  314. function goo:draw( x, y, object )
  315. local object = object or self.BASEOBJECT
  316. local x,y = x or 0, y or 0
  317. love.graphics.push()
  318. love.graphics.translate( x, y )
  319. love.graphics.scale( object.xscale, object.yscale )
  320. object:draw()
  321. for i,child in ipairs(object.children) do
  322. if child.visible then self:draw(child.x,child.y,child) end
  323. end
  324. love.graphics.pop()
  325. end
  326. function goo:debugdraw()
  327. local mx,my = love.mouse.getPosition( )
  328. local obj = self.BASEOBJECT.mousehover
  329. local x,y = obj:getAbsolutePos()
  330. local style = self.style['goo debug']
  331. local offx,offy = 10,10
  332. if mx > love.graphics.getWidth()-120 then offx = -(offx+100) end
  333. if my > love.graphics.getHeight()-65 then offy = -(offy+65) end
  334. love.graphics.setFont(style.textFont)
  335. love.graphics.setColor(unpack(style.backgroundColor))
  336. love.graphics.rectangle( 'fill', mx+offx-5, my+offy-15, 118,80)
  337. love.graphics.setColor(unpack(style.textColor))
  338. love.graphics.print( obj.class.name, mx+offx, my+offy )
  339. love.graphics.print( 'mouse: '..mx..', '..my, mx+offx, my+offy+20 )
  340. love.graphics.print( 'position: '..obj.x..', '..obj.y, mx+offx, my+offy+32 )
  341. love.graphics.print( 'relative: '..mx-x..', '..my-y, mx+offx, my+offy+44 )
  342. love.graphics.print( 'parent: '..mx-obj.parent.x..', '..my-obj.parent.y, mx+offx, my+offy+56 )
  343. end
  344. -- Input
  345. function goo:keypressed( key, unicode, object )
  346. local object = object or self.BASEOBJECT
  347. local ret = false
  348. if object.visible then ret = object:keypressed(key, unicode) end
  349. for i,child in ipairs(object.children) do
  350. ret = self:keypressed(key, unicode, child)
  351. end
  352. return ret
  353. end
  354. function goo:keyreleased( key, unicode, object )
  355. local object = object or self.BASEOBJECT
  356. if object.visible then ret = object:keyreleased(key, unicode) end
  357. for i,child in ipairs(object.children) do
  358. local ret = self:keyreleased(key, unicode, child)
  359. end
  360. return ret
  361. end
  362. function goo:mousepressed( x, y, button )
  363. local object = self.BASEOBJECT.mousehover
  364. if object.visible then object:mousepressed( x, y, button ) end
  365. end
  366. function goo:mousereleased( x, y, button )
  367. local object = self.BASEOBJECT.mousehover
  368. if object.visible then object:mousereleased( x, y, button ) end
  369. end
  370. --Misc funcs
  371. function goo.gradientRectangle(x1,y1,x2,y2,color1,color2)
  372. local _lines = y2-y1
  373. local _col = {}
  374. love.graphics.setLine(2,'smooth')
  375. for i=0, _lines do
  376. _col = lerpColor(color1,color2,i/_lines)
  377. love.graphics.setColor( unpack(_col) )
  378. love.graphics.line(x1,y1+i,x2,y1+i)
  379. end
  380. end
  381. function goo.lerpColor(color1,color2,t)
  382. local r = (color2[1] - color1[1]) * t + color1[1]
  383. local g = (color2[2] - color1[2]) * t + color1[2]
  384. local b = (color2[3] - color1[3]) * t + color1[3]
  385. local a = (color2[4] - color1[4]) * t + color1[4]
  386. return {r,g,b,a}
  387. end
  388. return goo