├── .gitignore ├── README.md ├── button.lua ├── checkbox.lua ├── core.lua ├── docs ├── Makefile ├── _static │ ├── demo.gif │ ├── different-ids.gif │ ├── hello-world.gif │ ├── keyboard.gif │ ├── layout.gif │ ├── mutable-state.gif │ ├── options.gif │ └── same-ids.gif ├── conf.py ├── core.rst ├── gettingstarted.rst ├── index.rst ├── layout.rst ├── license.rst ├── themes.rst └── widgets.rst ├── imagebutton.lua ├── init.lua ├── input.lua ├── label.lua ├── layout.lua ├── license.txt ├── slider.lua ├── suit-0.1-1.rockspec └── theme.lua /.gitignore: -------------------------------------------------------------------------------- 1 | main.lua 2 | *.love 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SUIT 2 | 3 | Simple User Interface Toolkit for LÖVE. 4 | 5 | SUIT is an immediate mode GUI library. 6 | 7 | ## Documentation? 8 | 9 | Over at [readthedocs](http://suit.readthedocs.org/en/latest/). 10 | 11 | ## Looks? 12 | 13 | Here is how SUIT looks like with the default theme: 14 | 15 | ![Demo of all widgets](docs/_static/demo.gif) 16 | 17 | More info and code is over at [readthedocs](http://suit.readthedocs.org/en/latest/). 18 | 19 | ## Hello, World! 20 | 21 | ```lua 22 | -- suit up 23 | local suit = require 'suit' 24 | 25 | -- storage for text input 26 | local input = {text = ""} 27 | 28 | -- make love use font which support CJK text 29 | function love.load() 30 | local font = love.graphics.newFont("NotoSansHans-Regular.otf", 20) 31 | love.graphics.setFont(font) 32 | end 33 | 34 | -- all the UI is defined in love.update or functions that are called from here 35 | function love.update(dt) 36 | -- put the layout origin at position (100,100) 37 | -- the layout will grow down and to the right from this point 38 | suit.layout:reset(100,100) 39 | 40 | -- put an input widget at the layout origin, with a cell size of 200 by 30 pixels 41 | suit.Input(input, suit.layout:row(200,30)) 42 | 43 | -- put a label that displays the text below the first cell 44 | -- the cell size is the same as the last one (200x30 px) 45 | -- the label text will be aligned to the left 46 | suit.Label("Hello, "..input.text, {align = "left"}, suit.layout:row()) 47 | 48 | -- put an empty cell that has the same size as the last cell (200x30 px) 49 | suit.layout:row() 50 | 51 | -- put a button of size 200x30 px in the cell below 52 | -- if the button is pressed, quit the game 53 | if suit.Button("Close", suit.layout:row()).hit then 54 | love.event.quit() 55 | end 56 | end 57 | 58 | function love.draw() 59 | -- draw the gui 60 | suit.draw() 61 | end 62 | 63 | function love.textedited(text, start, length) 64 | -- for IME input 65 | suit.textedited(text, start, length) 66 | end 67 | 68 | function love.textinput(t) 69 | -- forward text input to SUIT 70 | suit.textinput(t) 71 | end 72 | 73 | function love.keypressed(key) 74 | -- forward keypresses to SUIT 75 | suit.keypressed(key) 76 | end 77 | ``` 78 | -------------------------------------------------------------------------------- /button.lua: -------------------------------------------------------------------------------- 1 | -- This file is part of SUIT, copyright (c) 2016 Matthias Richter 2 | 3 | local BASE = (...):match('(.-)[^%.]+$') 4 | 5 | return function(core, text, ...) 6 | local opt, x,y,w,h = core.getOptionsAndSize(...) 7 | opt.id = opt.id or text 8 | opt.font = opt.font or love.graphics.getFont() 9 | 10 | w = w or opt.font:getWidth(text) + 4 11 | h = h or opt.font:getHeight() + 4 12 | 13 | opt.state = core:registerHitbox(opt.id, x,y,w,h) 14 | core:registerDraw(opt.draw or core.theme.Button, text, opt, x,y,w,h) 15 | 16 | return { 17 | id = opt.id, 18 | hit = core:mouseReleasedOn(opt.id), 19 | hovered = core:isHovered(opt.id), 20 | entered = core:isHovered(opt.id) and not core:wasHovered(opt.id), 21 | left = not core:isHovered(opt.id) and core:wasHovered(opt.id) 22 | } 23 | end 24 | -------------------------------------------------------------------------------- /checkbox.lua: -------------------------------------------------------------------------------- 1 | -- This file is part of SUIT, copyright (c) 2016 Matthias Richter 2 | 3 | local BASE = (...):match('(.-)[^%.]+$') 4 | 5 | return function(core, checkbox, ...) 6 | local opt, x,y,w,h = core.getOptionsAndSize(...) 7 | opt.id = opt.id or checkbox 8 | opt.font = opt.font or love.graphics.getFont() 9 | 10 | w = w or (opt.font:getWidth(checkbox.text) + opt.font:getHeight() + 4) 11 | h = h or opt.font:getHeight() + 4 12 | 13 | opt.state = core:registerHitbox(opt.id, x,y,w,h) 14 | local hit = core:mouseReleasedOn(opt.id) 15 | if hit then 16 | checkbox.checked = not checkbox.checked 17 | end 18 | core:registerDraw(opt.draw or core.theme.Checkbox, checkbox, opt, x,y,w,h) 19 | 20 | return { 21 | id = opt.id, 22 | hit = hit, 23 | hovered = core:isHovered(opt.id), 24 | entered = core:isHovered(opt.id) and not core:wasHovered(opt.id), 25 | left = not core:isHovered(opt.id) and core:wasHovered(opt.id) 26 | } 27 | end 28 | -------------------------------------------------------------------------------- /core.lua: -------------------------------------------------------------------------------- 1 | -- This file is part of SUIT, copyright (c) 2016 Matthias Richter 2 | 3 | local NONE = {} 4 | local BASE = (...):match('(.-)[^%.]+$') 5 | local default_theme = require(BASE..'theme') 6 | 7 | local suit = {} 8 | suit.__index = suit 9 | 10 | function suit.new(theme) 11 | return setmetatable({ 12 | -- TODO: deep copy/copy on write? better to let user handle => documentation? 13 | theme = theme or default_theme, 14 | mouse_x = 0, mouse_y = 0, 15 | mouse_button_down = false, 16 | candidate_text = {text="", start=0, length=0}, 17 | 18 | draw_queue = {n = 0}, 19 | 20 | Button = require(BASE.."button"), 21 | ImageButton = require(BASE.."imagebutton"), 22 | Label = require(BASE.."label"), 23 | Checkbox = require(BASE.."checkbox"), 24 | Input = require(BASE.."input"), 25 | Slider = require(BASE.."slider"), 26 | 27 | layout = require(BASE.."layout").new(), 28 | }, suit) 29 | end 30 | 31 | -- helper 32 | function suit.getOptionsAndSize(opt, ...) 33 | if type(opt) == "table" then 34 | return opt, ... 35 | end 36 | return {}, opt, ... 37 | end 38 | 39 | -- gui state 40 | function suit:setHovered(id) 41 | return self.hovered ~= id 42 | end 43 | 44 | function suit:anyHovered() 45 | return self.hovered ~= nil 46 | end 47 | 48 | function suit:isHovered(id) 49 | return id == self.hovered 50 | end 51 | 52 | function suit:wasHovered(id) 53 | return id == self.hovered_last 54 | end 55 | 56 | function suit:setActive(id) 57 | return self.active ~= nil 58 | end 59 | 60 | function suit:anyActive() 61 | return self.active ~= nil 62 | end 63 | 64 | function suit:isActive(id) 65 | return id == self.active 66 | end 67 | 68 | 69 | function suit:setHit(id) 70 | self.hit = id 71 | -- simulate mouse release on button -- see suit:mouseReleasedOn() 72 | self.mouse_button_down = false 73 | self.active = id 74 | self.hovered = id 75 | end 76 | 77 | function suit:anyHit() 78 | return self.hit ~= nil 79 | end 80 | 81 | function suit:isHit(id) 82 | return id == self.hit 83 | end 84 | 85 | function suit:getStateName(id) 86 | if self:isActive(id) then 87 | return "active" 88 | elseif self:isHovered(id) then 89 | return "hovered" 90 | elseif self:isHit(id) then 91 | return "hit" 92 | end 93 | return "normal" 94 | end 95 | 96 | -- mouse handling 97 | function suit:mouseInRect(x,y,w,h) 98 | return self.mouse_x >= x and self.mouse_y >= y and 99 | self.mouse_x <= x+w and self.mouse_y <= y+h 100 | end 101 | 102 | function suit:registerMouseHit(id, ul_x, ul_y, hit) 103 | if not self.hovered and hit(self.mouse_x - ul_x, self.mouse_y - ul_y) then 104 | self.hovered = id 105 | if self.active == nil and self.mouse_button_down then 106 | self.active = id 107 | end 108 | end 109 | return self:getStateName(id) 110 | end 111 | 112 | function suit:registerHitbox(id, x,y,w,h) 113 | return self:registerMouseHit(id, x,y, function(x,y) 114 | return x >= 0 and x <= w and y >= 0 and y <= h 115 | end) 116 | end 117 | 118 | function suit:mouseReleasedOn(id) 119 | if not self.mouse_button_down and self:isActive(id) and self:isHovered(id) then 120 | self.hit = id 121 | return true 122 | end 123 | return false 124 | end 125 | 126 | function suit:updateMouse(x, y, button_down) 127 | self.mouse_x, self.mouse_y = x,y 128 | if button_down ~= nil then 129 | self.mouse_button_down = button_down 130 | end 131 | end 132 | 133 | function suit:getMousePosition() 134 | return self.mouse_x, self.mouse_y 135 | end 136 | 137 | -- keyboard handling 138 | function suit:getPressedKey() 139 | return self.key_down, self.textchar 140 | end 141 | 142 | function suit:keypressed(key) 143 | self.key_down = key 144 | end 145 | 146 | function suit:textinput(char) 147 | self.textchar = char 148 | end 149 | 150 | function suit:textedited(text, start, length) 151 | self.candidate_text.text = text 152 | self.candidate_text.start = start 153 | self.candidate_text.length = length 154 | end 155 | 156 | function suit:grabKeyboardFocus(id) 157 | if self:isActive(id) then 158 | if love.system.getOS() == "Android" or love.system.getOS() == "iOS" then 159 | if id == NONE then 160 | love.keyboard.setTextInput( false ) 161 | else 162 | love.keyboard.setTextInput( true ) 163 | end 164 | end 165 | self.keyboardFocus = id 166 | end 167 | return self:hasKeyboardFocus(id) 168 | end 169 | 170 | function suit:hasKeyboardFocus(id) 171 | return self.keyboardFocus == id 172 | end 173 | 174 | function suit:keyPressedOn(id, key) 175 | return self:hasKeyboardFocus(id) and self.key_down == key 176 | end 177 | 178 | -- state update 179 | function suit:enterFrame() 180 | if not self.mouse_button_down then 181 | self.active = nil 182 | elseif self.active == nil then 183 | self.active = NONE 184 | end 185 | 186 | self.hovered_last, self.hovered = self.hovered, nil 187 | self:updateMouse(love.mouse.getX(), love.mouse.getY(), love.mouse.isDown(1)) 188 | self.key_down, self.textchar = nil, "" 189 | self:grabKeyboardFocus(NONE) 190 | self.hit = nil 191 | end 192 | 193 | function suit:exitFrame() 194 | end 195 | 196 | -- draw 197 | function suit:registerDraw(f, ...) 198 | local args = {...} 199 | local nargs = select('#', ...) 200 | self.draw_queue.n = self.draw_queue.n + 1 201 | self.draw_queue[self.draw_queue.n] = function() 202 | f(unpack(args, 1, nargs)) 203 | end 204 | end 205 | 206 | function suit:draw() 207 | self:exitFrame() 208 | love.graphics.push('all') 209 | for i = self.draw_queue.n,1,-1 do 210 | self.draw_queue[i]() 211 | end 212 | love.graphics.pop() 213 | self.draw_queue.n = 0 214 | self:enterFrame() 215 | end 216 | 217 | return suit 218 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " applehelp to make an Apple Help Book" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | pickle: 70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 71 | @echo 72 | @echo "Build finished; now you can process the pickle files." 73 | 74 | json: 75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 76 | @echo 77 | @echo "Build finished; now you can process the JSON files." 78 | 79 | htmlhelp: 80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 81 | @echo 82 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 83 | ".hhp project file in $(BUILDDIR)/htmlhelp." 84 | 85 | qthelp: 86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 87 | @echo 88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/hump.qhcp" 91 | @echo "To view the help file:" 92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/hump.qhc" 93 | 94 | applehelp: 95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 96 | @echo 97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 98 | @echo "N.B. You won't be able to view it unless you put it in" \ 99 | "~/Library/Documentation/Help or install it in your application" \ 100 | "bundle." 101 | 102 | devhelp: 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/hump" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/hump" 109 | @echo "# devhelp" 110 | 111 | epub: 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | latex: 117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 118 | @echo 119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 121 | "(use \`make latexpdf' here to do that automatically)." 122 | 123 | latexpdf: 124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 125 | @echo "Running LaTeX files through pdflatex..." 126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 128 | 129 | latexpdfja: 130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 131 | @echo "Running LaTeX files through platex and dvipdfmx..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | text: 136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 137 | @echo 138 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 139 | 140 | man: 141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 142 | @echo 143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 144 | 145 | texinfo: 146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 147 | @echo 148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 149 | @echo "Run \`make' in that directory to run these through makeinfo" \ 150 | "(use \`make info' here to do that automatically)." 151 | 152 | info: 153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 154 | @echo "Running Texinfo files through makeinfo..." 155 | make -C $(BUILDDIR)/texinfo info 156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 157 | 158 | gettext: 159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 160 | @echo 161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 162 | 163 | changes: 164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 165 | @echo 166 | @echo "The overview file is in $(BUILDDIR)/changes." 167 | 168 | linkcheck: 169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 170 | @echo 171 | @echo "Link check complete; look for any errors in the above output " \ 172 | "or in $(BUILDDIR)/linkcheck/output.txt." 173 | 174 | doctest: 175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 176 | @echo "Testing of doctests in the sources finished, look at the " \ 177 | "results in $(BUILDDIR)/doctest/output.txt." 178 | 179 | coverage: 180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 181 | @echo "Testing of coverage in the sources finished, look at the " \ 182 | "results in $(BUILDDIR)/coverage/python.txt." 183 | 184 | xml: 185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 186 | @echo 187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 188 | 189 | pseudoxml: 190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 191 | @echo 192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 193 | -------------------------------------------------------------------------------- /docs/_static/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/demo.gif -------------------------------------------------------------------------------- /docs/_static/different-ids.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/different-ids.gif -------------------------------------------------------------------------------- /docs/_static/hello-world.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/hello-world.gif -------------------------------------------------------------------------------- /docs/_static/keyboard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/keyboard.gif -------------------------------------------------------------------------------- /docs/_static/layout.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/layout.gif -------------------------------------------------------------------------------- /docs/_static/mutable-state.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/mutable-state.gif -------------------------------------------------------------------------------- /docs/_static/options.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/options.gif -------------------------------------------------------------------------------- /docs/_static/same-ids.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vrld/suit/17677826030a7270b474c5717af43834d583094c/docs/_static/same-ids.gif -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # SUIT documentation build configuration file, created by 4 | # sphinx-quickstart on Sat Oct 10 13:10:12 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import sys 16 | import os 17 | import shlex 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | #sys.path.insert(0, os.path.abspath('.')) 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | #needs_sphinx = '1.0' 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = [ 33 | 'sphinx.ext.mathjax', 34 | ] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ['_templates'] 38 | 39 | # The suffix(es) of source filenames. 40 | # You can specify multiple suffix as a list of string: 41 | # source_suffix = ['.rst', '.md'] 42 | source_suffix = '.rst' 43 | 44 | # The encoding of source files. 45 | #source_encoding = 'utf-8-sig' 46 | 47 | # The master toctree document. 48 | master_doc = 'index' 49 | 50 | # General information about the project. 51 | project = u'SUIT' 52 | copyright = u'2016, Matthias Richter' 53 | author = u'Matthias Richter' 54 | 55 | # The version info for the project you're documenting, acts as replacement for 56 | # |version| and |release|, also used in various other places throughout the 57 | # built documents. 58 | # 59 | # The short X.Y version. 60 | version = '1.0' 61 | # The full version, including alpha/beta/rc tags. 62 | release = '1.0' 63 | 64 | # The language for content autogenerated by Sphinx. Refer to documentation 65 | # for a list of supported languages. 66 | # 67 | # This is also used if you do content translation via gettext catalogs. 68 | # Usually you set "language" from the command line for these cases. 69 | language = None 70 | 71 | # There are two options for replacing |today|: either, you set today to some 72 | # non-false value, then it is used: 73 | #today = '' 74 | # Else, today_fmt is used as the format for a strftime call. 75 | #today_fmt = '%B %d, %Y' 76 | 77 | # List of patterns, relative to source directory, that match files and 78 | # directories to ignore when looking for source files. 79 | exclude_patterns = ['_build'] 80 | 81 | # The reST default role (used for this markup: `text`) to use for all 82 | # documents. 83 | #default_role = None 84 | 85 | # If true, '()' will be appended to :func: etc. cross-reference text. 86 | #add_function_parentheses = True 87 | 88 | # If true, the current module name will be prepended to all description 89 | # unit titles (such as .. function::). 90 | #add_module_names = True 91 | 92 | # If true, sectionauthor and moduleauthor directives will be shown in the 93 | # output. They are ignored by default. 94 | #show_authors = False 95 | 96 | # The name of the Pygments (syntax highlighting) style to use. 97 | pygments_style = 'sphinx' 98 | 99 | # A list of ignored prefixes for module index sorting. 100 | #modindex_common_prefix = [] 101 | 102 | # If true, keep warnings as "system message" paragraphs in the built documents. 103 | #keep_warnings = False 104 | 105 | # If true, `todo` and `todoList` produce output, else they produce nothing. 106 | todo_include_todos = False 107 | 108 | 109 | # -- Options for HTML output ---------------------------------------------- 110 | 111 | # The theme to use for HTML and HTML Help pages. See the documentation for 112 | # a list of builtin themes. 113 | html_theme = 'alabaster' 114 | 115 | # Theme options are theme-specific and customize the look and feel of a theme 116 | # further. For a list of options available for each theme, see the 117 | # documentation. 118 | #html_theme_options = {} 119 | 120 | # Add any paths that contain custom themes here, relative to this directory. 121 | #html_theme_path = [] 122 | 123 | # The name for this set of Sphinx documents. If None, it defaults to 124 | # " v documentation". 125 | #html_title = None 126 | 127 | # A shorter title for the navigation bar. Default is the same as html_title. 128 | #html_short_title = None 129 | 130 | # The name of an image file (relative to this directory) to place at the top 131 | # of the sidebar. 132 | #html_logo = None 133 | 134 | # The name of an image file (within the static path) to use as favicon of the 135 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 136 | # pixels large. 137 | #html_favicon = None 138 | 139 | # Add any paths that contain custom static files (such as style sheets) here, 140 | # relative to this directory. They are copied after the builtin static files, 141 | # so a file named "default.css" will overwrite the builtin "default.css". 142 | html_static_path = ['_static'] 143 | 144 | # Add any extra paths that contain custom files (such as robots.txt or 145 | # .htaccess) here, relative to this directory. These files are copied 146 | # directly to the root of the documentation. 147 | #html_extra_path = [] 148 | 149 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 150 | # using the given strftime format. 151 | #html_last_updated_fmt = '%b %d, %Y' 152 | 153 | # If true, SmartyPants will be used to convert quotes and dashes to 154 | # typographically correct entities. 155 | #html_use_smartypants = True 156 | 157 | # Custom sidebar templates, maps document names to template names. 158 | #html_sidebars = {} 159 | 160 | # Additional templates that should be rendered to pages, maps page names to 161 | # template names. 162 | #html_additional_pages = {} 163 | 164 | # If false, no module index is generated. 165 | #html_domain_indices = True 166 | 167 | # If false, no index is generated. 168 | #html_use_index = True 169 | 170 | # If true, the index is split into individual pages for each letter. 171 | #html_split_index = False 172 | 173 | # If true, links to the reST sources are added to the pages. 174 | #html_show_sourcelink = True 175 | 176 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 177 | #html_show_sphinx = True 178 | 179 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 180 | #html_show_copyright = True 181 | 182 | # If true, an OpenSearch description file will be output, and all pages will 183 | # contain a tag referring to it. The value of this option must be the 184 | # base URL from which the finished HTML is served. 185 | #html_use_opensearch = '' 186 | 187 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 188 | #html_file_suffix = None 189 | 190 | # Language to be used for generating the HTML full-text search index. 191 | # Sphinx supports the following languages: 192 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 193 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 194 | #html_search_language = 'en' 195 | 196 | # A dictionary with options for the search language support, empty by default. 197 | # Now only 'ja' uses this config value 198 | #html_search_options = {'type': 'default'} 199 | 200 | # The name of a javascript file (relative to the configuration directory) that 201 | # implements a search results scorer. If empty, the default will be used. 202 | #html_search_scorer = 'scorer.js' 203 | 204 | # Output file base name for HTML help builder. 205 | htmlhelp_basename = 'suitdoc' 206 | 207 | # -- Options for LaTeX output --------------------------------------------- 208 | 209 | latex_elements = { 210 | # The paper size ('letterpaper' or 'a4paper'). 211 | #'papersize': 'letterpaper', 212 | 213 | # The font size ('10pt', '11pt' or '12pt'). 214 | #'pointsize': '10pt', 215 | 216 | # Additional stuff for the LaTeX preamble. 217 | #'preamble': '', 218 | 219 | # Latex figure (float) alignment 220 | #'figure_align': 'htbp', 221 | } 222 | 223 | # Grouping the document tree into LaTeX files. List of tuples 224 | # (source start file, target name, title, 225 | # author, documentclass [howto, manual, or own class]). 226 | latex_documents = [ 227 | (master_doc, 'suit.tex', u'SUIT Documentation', 228 | u'Matthias Richter', 'manual'), 229 | ] 230 | 231 | # The name of an image file (relative to this directory) to place at the top of 232 | # the title page. 233 | #latex_logo = None 234 | 235 | # For "manual" documents, if this is true, then toplevel headings are parts, 236 | # not chapters. 237 | #latex_use_parts = False 238 | 239 | # If true, show page references after internal links. 240 | #latex_show_pagerefs = False 241 | 242 | # If true, show URL addresses after external links. 243 | #latex_show_urls = False 244 | 245 | # Documents to append as an appendix to all manuals. 246 | #latex_appendices = [] 247 | 248 | # If false, no module index is generated. 249 | #latex_domain_indices = True 250 | 251 | 252 | # -- Options for manual page output --------------------------------------- 253 | 254 | # One entry per manual page. List of tuples 255 | # (source start file, name, description, authors, manual section). 256 | man_pages = [ 257 | (master_doc, 'SUIT', u'SUIT Documentation', 258 | [author], 1) 259 | ] 260 | 261 | # If true, show URL addresses after external links. 262 | #man_show_urls = False 263 | 264 | 265 | # -- Options for Texinfo output ------------------------------------------- 266 | 267 | # Grouping the document tree into Texinfo files. List of tuples 268 | # (source start file, target name, title, author, 269 | # dir menu entry, description, category) 270 | texinfo_documents = [ 271 | (master_doc, 'SUIT', u'SUIT Documentation', 272 | author, 'SUIT', 'One line description of project.', 273 | 'Miscellaneous'), 274 | ] 275 | 276 | # Documents to append as an appendix to all manuals. 277 | #texinfo_appendices = [] 278 | 279 | # If false, no module index is generated. 280 | #texinfo_domain_indices = True 281 | 282 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 283 | #texinfo_show_urls = 'footnote' 284 | 285 | # If true, do not generate a @detailmenu in the "Top" node's menu. 286 | #texinfo_no_detailmenu = False 287 | 288 | primary_domain = "js" 289 | highlight_language = "lua" 290 | 291 | import sphinx_rtd_theme 292 | html_theme = 'sphinx_rtd_theme' 293 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 294 | -------------------------------------------------------------------------------- /docs/core.rst: -------------------------------------------------------------------------------- 1 | Core Functions 2 | ============== 3 | 4 | The core functions can be divided into two parts: Functions of interest to the 5 | user and functions of interest to the (widget) developer. 6 | 7 | External Interface 8 | ------------------ 9 | 10 | Drawing 11 | ^^^^^^^ 12 | 13 | .. function:: draw() 14 | 15 | Draw the GUI - call in ``love.draw``. 16 | 17 | .. data:: theme 18 | 19 | The current theme. See :doc:`themes`. 20 | 21 | 22 | Mouse Input 23 | ^^^^^^^^^^^ 24 | 25 | .. function:: updateMouse(x,y, buttonDown) 26 | 27 | :param number x,y: Position of the mouse. 28 | :param boolean buttonDown: Whether the mouse button is down. 29 | 30 | Update mouse position and button status. You do not need to call this function, 31 | unless you use some screen transformation (e.g., scaling, camera systems, ...). 32 | 33 | Keyboard Input 34 | ^^^^^^^^^^^^^^ 35 | 36 | .. function:: keypressed(key) 37 | 38 | :param KeyConstant key: The pressed key. 39 | 40 | Forwards a ``love.keypressed(key)`` event to SUIT. 41 | 42 | .. function:: textinput(char) 43 | 44 | :param string char: The pressed character 45 | 46 | Forwards a ``love.textinput(key)`` event to SUIT. 47 | 48 | 49 | GUI State 50 | ^^^^^^^^^ 51 | 52 | .. function:: anyHovered() 53 | 54 | :returns: ``true`` if any widget is hovered by the mouse. 55 | 56 | Checks if any widget is hovered by the mouse. 57 | 58 | .. function:: isHovered(id) 59 | 60 | :param mixed id: Identifier of the widget. 61 | :returns: ``true`` if the widget is hovered by the mouse. 62 | 63 | Checks if the widget identified by ``id`` is hovered by the mouse. 64 | 65 | .. function:: wasHovered(id) 66 | 67 | :param mixed id: Identifier of the widget. 68 | :returns: ``true`` if the widget was in the hovered by the mouse in the last frame. 69 | 70 | Checks if the widget identified by ``id`` was hovered by the mouse in the last frame. 71 | 72 | .. function:: anyActive() 73 | 74 | :returns: ``true`` if any widget is in the ``active`` state. 75 | 76 | Checks whether the mouse button is pressed and held on any widget. 77 | 78 | .. function:: isActive(id) 79 | 80 | :param mixed id: Identifier of the widget. 81 | :returns: ``true`` if the widget is in the ``active`` state. 82 | 83 | Checks whether the mouse button is pressed and held on the widget identified by ``id``. 84 | 85 | .. function:: anyHit() 86 | 87 | :returns: ``true`` if the mouse was pressed and released on any widget. 88 | 89 | Check whether the mouse was pressed and released on any widget. 90 | 91 | .. function:: isHit(id) 92 | 93 | :param mixed id: Identifier of the widget. 94 | :returns: ``true`` if the mouse was pressed and released on the widget. 95 | 96 | Check whether the mouse was pressed and released on the widget identified by ``id``. 97 | 98 | 99 | Internal Helpers 100 | ---------------- 101 | 102 | .. function:: getOptionsAndSize(...) 103 | 104 | :param mixed ...: Varargs. 105 | :returns: ``options, x,y,w,h``. 106 | 107 | Converts varargs to option table and size definition. Used in the widget 108 | functions. 109 | 110 | .. function:: registerDraw(f, ...) 111 | 112 | :param function f: Function to call in ``draw()``. 113 | :param mixed ...: Arguments to f. 114 | 115 | Registers a function to be executed during :func:`draw()`. Used by widgets to 116 | make themselves visible. 117 | 118 | .. function:: enterFrame() 119 | 120 | Prepares GUI state when entering a frame. 121 | 122 | .. function:: exitFrame() 123 | 124 | Clears GUI state when exiting a frame. 125 | 126 | 127 | Mouse Input 128 | ^^^^^^^^^^^ 129 | 130 | .. function:: mouseInRect(x,y,w,h) 131 | 132 | :param numbers x,y,w,h: Rectangle definition. 133 | :returns: ``true`` if the mouse cursor is in the rectangle. 134 | 135 | Checks whether the mouse cursor is in the rectangle defined by ``x,y,w,h``. 136 | 137 | .. function:: registerMouseHit(id, ul_x, ul_y, hit) 138 | 139 | :param mixed id: Identifier of the widget. 140 | :param numbers ul_x, ul_y: Upper left corner of the widget. 141 | :param function hit: Function to perform the hit test. 142 | 143 | Registers a hit-test defined by the function ``hit`` for the widget identified 144 | by ``id``. Sets the widget to ``hovered`` if th hit-test returns ``true``. Sets the 145 | widget to ``active`` if the hit-test returns ``true`` and the mouse button is 146 | pressed. 147 | 148 | The hit test receives coordinates in the coordinate system of the widget, i.e. 149 | ``(0,0)`` is the upper left corner of the widget. 150 | 151 | .. function:: registerHitbox(id, x,y,w,h) 152 | 153 | :param mixed id: Identifier of the widget. 154 | :param numbers x,y,w,h: Rectangle definition. 155 | 156 | Registers a hitbox for the widget identified by ``id``. Literally this function:: 157 | 158 | function registerHitbox(id, x,y,w,h) 159 | return registerMouseHit(id, x,y, function(u,v) 160 | return u >= 0 and u <= w and v >= 0 and v <= h 161 | end) 162 | end 163 | 164 | .. function:: mouseReleasedOn(id) 165 | 166 | :param mixed id: Identifier of the widget. 167 | :returns: ``true`` if the mouse was released on the widget. 168 | 169 | Checks whether the mouse button was released on the widget identified by ``id``. 170 | 171 | .. function:: getMousePosition() 172 | 173 | :returns: Mouse positon ``mx, my``. 174 | 175 | Get the mouse position. 176 | 177 | Keyboard Input 178 | ^^^^^^^^^^^^^^ 179 | 180 | .. function:: getPressedKey() 181 | 182 | :returns: KeyConstant 183 | 184 | Get the currently pressed key (if any). 185 | 186 | .. function:: grabKeyboardFocus(id) 187 | 188 | :param mixed id: Identifier of the widget. 189 | 190 | Try to grab keyboard focus. Successful only if the widget is in the ``active`` 191 | state. 192 | 193 | .. function:: hasKeyboardFocus(id) 194 | 195 | :param mixed id: Identifier of the widget. 196 | :returns: ``true`` if the widget has keyboard focus. 197 | 198 | Checks whether the widget identified by ``id`` currently has keyboard focus. 199 | 200 | .. function:: keyPressedOn(id, key) 201 | 202 | :param mixed id: Identifier of the widget. 203 | :param KeyConstant key: Key to query. 204 | :returns: ``true`` if ``key`` was pressed on the widget. 205 | 206 | Checks whether the key ``key`` was pressed while the widget identified by 207 | ``id`` has keyboard focus. 208 | 209 | 210 | Instancing 211 | ---------- 212 | 213 | .. function:: new() 214 | 215 | :returns: Separate UI state. 216 | 217 | Create a separate UI and layout state. Everything that happens in the new 218 | state will not affect any other state. You can use the new state like the 219 | "global" state ``suit``, but call functions with the colon syntax instead of 220 | the dot syntax, e.g.:: 221 | 222 | function love.load() 223 | dress = suit.new() 224 | end 225 | 226 | function love.update() 227 | dress.layout:reset() 228 | dress:Label("Hello, World!", dress.layout:row(200,30)) 229 | dress:Input(input, dress.layout:row()) 230 | end 231 | 232 | function love.draw() 233 | dress:draw() 234 | end 235 | 236 | .. warning:: 237 | 238 | Unlike UI and layout state, the theme might be shared with other states. 239 | Changes in a shared theme will be shared across all themes. 240 | See the :ref:`Instance Theme ` subsection in the 241 | :doc:`gettingstarted` guide. 242 | -------------------------------------------------------------------------------- /docs/gettingstarted.rst: -------------------------------------------------------------------------------- 1 | Getting Started 2 | =============== 3 | 4 | Before actually getting started, it is important to understand the motivation 5 | and mechanics behind SUIT: 6 | 7 | - **Immediate mode is better than retained mode** 8 | - **Layout should not care about content** 9 | - **Less is more** 10 | 11 | Immediate mode? 12 | --------------- 13 | 14 | With classical (retained) mode libraries you typically have a stage where you 15 | create the whole UI when the program initializes. This includes what happens 16 | when events like button presses or slider changes occur. After that point, the 17 | GUI is expected to not change very much. This is great for word processors 18 | where the interaction is consistent and straightforward, but bad for games, 19 | where everything changes all the time. 20 | 21 | With immediate mode libraries, on the other hand, the GUI is created every 22 | frame from scratch. Because that would be wasteful, there are no widget 23 | objects. Instead, widgets are created by functions that react to UI state and 24 | present some data. Where this data comes from and how it is maintained does 25 | not concern the widget at all. This is, after all, your job. This gives great 26 | control over what is shown where and when. The widget code can be right next 27 | to the code that does what should happen if the widget state changes. The 28 | layout is also very flexible: adding a widget is one more function call, and if 29 | you want to hide a widget, you simply don't call the corresponding function. 30 | 31 | This separation of data and behaviour is great when a lot of stuff is going on, 32 | but takes a bit of time getting used to. 33 | 34 | 35 | What SUIT is 36 | ^^^^^^^^^^^^ 37 | 38 | SUIT is simple: It provides only a few basic widgets that are important for 39 | games: 40 | 41 | - :func:`Buttons