main.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. -- Original author: https://github.com/trubblegum
  2. -- This is a modified version of https://github.com/trubblegum/Gspot/blob/cf0a49d7d2073686d7ddb32a4fa04e90593d36c4/main.lua
  3. -- The original program did not include a copyright notice.
  4. -- Modifications © Copyright 2015-2016, 2018, 2021 Pedro Gimeno Fortea.
  5. --
  6. -- This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
  7. -- Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
  8. -- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  9. -- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  10. -- 3. This notice may not be removed or altered from any source distribution.
  11. if love._version_major == 0 and love._version_minor < 9 then
  12. error("This library needs love2d 0.9.0 or above")
  13. end
  14. gui = require('Gspot') -- import the library
  15. --mainmenu = gui() -- create a gui instance. don't have to do this, but you may want a gui for each gamestate so they can talk to each other, and you won't have to recontsruct the gui every time you enter a state
  16. -- 11.0 changes the colour component range from 0-255 to 0-1. Multiplying each
  17. -- component by DIV converts a 0-255 value to the required version-dependent
  18. -- range.
  19. local DIV = love._version_major >= 11 and 1/255 or 1
  20. font = love.graphics.newFont(192)
  21. love.load = function()
  22. love.graphics.setFont(font)
  23. love.graphics.setColor(255 * DIV, 192 * DIV, 0 * DIV, 128 * DIV) -- just setting these so we know the gui isn't stealing our thunder
  24. sometext = 'Lörem ipsum dolor sït amet, consectètur adipisicing élit, sed do eiusmod tempoŕ incididunt ut labore et dọlorẹ magna aliquæ.'
  25. local textout = gui:typetext(sometext, {y = 32, w = 128})
  26. -- button
  27. local button = gui:button('A Button', {x = 128, y = gui.style.unit, w = 128, h = gui.style.unit}) -- a button(label, pos, optional parent) gui.style.unit is a standard gui unit (default 16), used to keep the interface tidy
  28. button.click = function(this, x, y) -- set element:click() to make it respond to gui's click event
  29. gui:feedback('Clicky')
  30. end
  31. -- image
  32. local image = gui:image('An Image', {160, 32, 0, 0}, nil, 'img.png') -- an image(label, pos, parent, love.image or path)
  33. image.click = function(this, x, y)
  34. gui:feedback(tostring(this.pos))
  35. end
  36. image.enter = function(this) this.Gspot:feedback("I'm In!") end -- every element has a reference to the gui instance which created it
  37. image.leave = function(this) this.Gspot:feedback("I'm Out!") end
  38. -- hidden element
  39. local hidden = gui:hidden('', {128, 128, 128, 128}) -- creating a hidden element, to see it at work
  40. hidden.tip = "Can't see me, but I still respond"
  41. -- elements' children will be positioned relative to their parent's position
  42. group1 = gui:collapsegroup('Group 1', {gui.style.unit, gui.style.unit * 3, 128, gui.style.unit}) -- group(label, pos, optional parent)
  43. group1.style.fg = {255 * DIV, 192 * DIV, 0 * DIV, 255 * DIV}
  44. group1.tip = 'Drag and drop' -- add a tooltip
  45. group1.drag = true -- respond to default drag behaviour
  46. group1.drop = function(this, bucket) -- respond to drop event
  47. if bucket then gui:feedback('Dropped on '..tostring(bucket))
  48. else gui:feedback('Dropped on nothing') end
  49. end
  50. -- option (must have a parent)
  51. for i = 1, 3 do
  52. option = gui:option('Option '..i, {0, gui.style.unit * i, 128, gui.style.unit}, group1, i) -- option(label, pos, parent, value) option stores this.value in this.parent.value when clicked, and is selected if this.value == this.parent.value
  53. option.tip = 'Select '..option.value
  54. end
  55. -- another group, with various behaviours
  56. group2 = gui:group('Group 2', {gui.style.unit, 128, 256, 256})
  57. group2.drag = true
  58. group2.tip = 'Drag, right-click, and catch'
  59. group2.rclick = function(this) -- respond to right-click event by creating a button.
  60. gui:feedback('Right-click')
  61. local button = gui:button('A dynamic button', {love.mouse.getX(), love.mouse.getY(), 128, gui.style.unit}) -- button's parent will be the calling element
  62. button.click = function(this) -- temp button to click before removed itself
  63. gui:feedback('I\'ll be back!')
  64. gui:rem(this)
  65. end
  66. end
  67. group2.catch = function(this, ball) -- respond when an element is dragged and then dropped on this element
  68. gui:feedback('Caught '..ball:type())
  69. end
  70. -- scrollgroup's children, excepting its scrollbar, will scroll
  71. scrollgroup = gui:scrollgroup(nil, {0, gui.style.unit, 256, 256}, group2) -- scrollgroup will create its own scrollbar
  72. scrollgroup.scrollh.tip = 'Scroll (mouse or wheel)' -- scrollgroup.scrollh is the horizontal scrollbar
  73. scrollgroup.scrollh.style.hs = scrollgroup.style.unit*2
  74. scrollgroup.scrollv.tip = scrollgroup.scrollh.tip -- scrollgroup.scrollv is the vertical scrollbar
  75. --scrollgroup.scroller:setshape('circle') -- to set a round handle
  76. scrollgroup.scrollh.drop = function(this) gui:feedback('Scrolled to : '..this.values.current..' / '..this.values.min..' - '..this.values.max) end
  77. scrollgroup.scrollv.drop = scrollgroup.scrollh.drop
  78. scrollgroup.scrollv.style.hs = "auto"
  79. -- initialize element.shape to 'circle' by specifying pos.r -- pos.w and pos.h will be set accordingly
  80. local checkbox = gui:checkbox(nil, {r = 8}, scrollgroup) -- scrollgroup.scrollh.values.max, scrollgroup.scrollv.values.max will be updated when a child is added to scrollgroup
  81. checkbox.style.labelfg = checkbox.style.fg -- lock label colour
  82. checkbox.click = function(this)
  83. gui[this.elementtype].click(this) -- calling option's base click() to preserve default functionality, as we're overriding a reserved behaviour
  84. if this.value then this.style.fg = {255 * DIV, 128 * DIV, 0 * DIV, 255 * DIV}
  85. else this.style.fg = {255 * DIV, 255 * DIV, 255 * DIV, 255 * DIV} end
  86. end
  87. local checkboxlabel = gui:text('check', {x = 16}, checkbox, true) -- using the autosize flag to resize the element's width to fit the text
  88. checkboxlabel.click = function(this, x, y)
  89. this.parent:click()
  90. end
  91. local loader = gui:progress('Loading', {x = 64, y = 16, w = 64}, scrollgroup)
  92. loader.updateinterval = 0.25 -- just setting this so we can see the progress bar at work
  93. loader.done = function(this)
  94. done = this:replace(gui:feedback('Done', {0, this.pos.y}, this.parent, false)) -- replace with a new element at the same level in draw order
  95. end
  96. for i = 1, 8 do
  97. loader:add(function() return scrollgroup:addchild(gui:text(sometext, {w = 128}), 'grid') end)
  98. --gui:text(sometext, {w = 128}) -- if not autosize, Gspot wraps text to element.pos.w and adjusts element.pos.h to fit it in
  99. --element:addchild(element, 'vertical') -- using the autostack flag to reposition below existing child elements
  100. --the two lines above accomplish the same as gui:text(str, {y = scrollgroup:getmaxh(), w = 128}, scrollgroup)
  101. end
  102. -- additional scroll controls
  103. button = gui:button('up', {group2.pos.w, 0}, group2) -- a small button attached to the scrollgroup's group, because all of a scrollgroup's children scroll
  104. button.click = function(this)
  105. local scroll = scrollgroup.scrollv
  106. scroll.values.current = math.max(scroll.values.min, scroll.values.current - scroll.values.step) -- decrement scrollgroup.scrollv.values.current by scrollgroup.scrollv.values.step, and the slider will go up a notch
  107. scroll:drop()
  108. end
  109. button = gui:button('dn', {group2.pos.w, group2.pos.h + gui.style.unit}, group2)
  110. button.click = function(this)
  111. local scroll = scrollgroup.scrollv
  112. scroll.values.current = math.min(scroll.values.max, scroll.values.current + scroll.values.step) -- this one increment's the scrollbar's values.current, moving the slider down a notch
  113. scroll:drop()
  114. end
  115. -- text input
  116. input = gui:input('Chat', {64, love.graphics.getHeight() - 32, 256, gui.style.unit})
  117. input.keyrepeat = true -- this is the default anyway
  118. input.done = function(this) -- Gspot calls element:done() when you hit enter while element has focus. override this behaviour with element.done = false
  119. gui:feedback('I say '..this.value)
  120. this.value = ''
  121. this.Gspot:unfocus()
  122. end
  123. button = gui:button('Speak', {input.pos.w + gui.style.unit, 0, 64, gui.style.unit}, input) -- attach a button
  124. button.click = function(this)
  125. this.parent:done()
  126. end
  127. -- easy custom gui element
  128. gui.boxy = function(this, label, pos, parent) -- careful not to override existing element types, and remember we're inside the gui's scope now
  129. local group = this:group(label, pos, parent) -- using the easy method, our custom element should be based on an existing element type
  130. group.tip = 'Drag, and right-click or\ndoubleclick to spawn'
  131. group.drag = true
  132. group.rclick = function(this) gui:boxy('More custom goodness', {love.mouse.getX(), love.mouse.getY(), 128, 64}) end -- boxy will spawn more windows
  133. group.dblclick = function(this) gui:boxy('Doubleclick', {love.mouse.getX(), love.mouse.getY(), 128, 64}) end
  134. local x = this:button('X', {x = group.pos.w - this.style.unit, y = 0, w = this.style.unit, h = this.style.unit}, group) -- adding a control
  135. x.click = function(this) this.Gspot:rem(this.parent) end -- which removes this boxy
  136. return group -- return the element
  137. end
  138. boxy = gui:boxy('Custom goodness', {256, 256, 128, 64}) -- now make one of our windows
  139. -- or if you want more control
  140. gui.mostbasic = {}
  141. gui.mostbasic.load = function(this, Gspot, label, pos, parent)
  142. local element = Gspot:element('group', label, pos, parent) -- Gspot:element(elementtype, label, pos, parent) gives the element its required values and inheritance. elementtype must be an existing type, or it won't work
  143. return Gspot:add(element) -- Gspot:add() adds it to Gspot.elements, and returns the new element
  144. end
  145. gui.mostbasic.update = function(this, dt) end -- dt is passed along by Gspot:update(dt)
  146. gui.mostbasic.draw = function(this, pos) end -- pos is the element's absolute position, supplied by Gspot:draw()
  147. --show, hide, and update
  148. text = gui:text('Hit F1 to show/hide', {love.graphics.getWidth() - 128, gui.style.unit, 128, gui.style.unit}) -- a hint (see love.keypressed() below)
  149. showhider = gui:group('Mouse Below', {love.graphics.getWidth() - 128, gui.style.unit * 2, 128, 64})
  150. counter = gui:text('0', {0, gui.style.unit, 128, 0}, showhider)
  151. counter.count = 0
  152. counter.update = function(this, dt) -- set an update function, which will be called every frame, unless we also specify element.updateinterval
  153. if gui.mousein == this or gui.mousein == this.parent then
  154. this.count = this.count + dt
  155. if this.count > 1 then this.count = 0 end
  156. this.label = this.count
  157. end
  158. end
  159. showhider:hide() -- display state will be propagated to children
  160. end
  161. love.update = function(dt)
  162. gui:update(dt)
  163. end
  164. love.draw = function()
  165. local bg = 'OBEY'
  166. love.graphics.print(bg, 0, 240, math.pi / 4, 1, 1)
  167. gui:draw()
  168. love.graphics.print(bg, 320, 240, math.pi / 4, 1, 1)
  169. end
  170. love.keypressed = function(key, code, isrepeat)
  171. if gui.focus then
  172. gui:keypress(key) -- only sending input to the gui if we're not using it for something else
  173. else
  174. if key == 'return'then -- binding enter key to input focus
  175. input:focus()
  176. elseif key == 'f1' then -- toggle show-hider
  177. if showhider.display then showhider:hide() else showhider:show() end
  178. else
  179. gui:feedback(key) -- why not
  180. end
  181. end
  182. end
  183. love.textinput = function(key)
  184. if gui.focus then
  185. gui:textinput(key) -- only sending input to the gui if we're not using it for something else
  186. end
  187. end
  188. -- deal with 0.10 mouse API changes
  189. love.mousepressed = function(x, y, button)
  190. gui:mousepress(x, y, button) -- pretty sure you want to register mouse events
  191. end
  192. love.mousereleased = function(x, y, button)
  193. gui:mouserelease(x, y, button)
  194. end
  195. love.wheelmoved = function(x, y)
  196. gui:mousewheel(x, y)
  197. end