From 2f3db27769997a8e3f96e64c41967c4feb9150f1 Mon Sep 17 00:00:00 2001 From: rodel77 Date: Thu, 5 Apr 2018 18:07:37 -0500 Subject: [PATCH 01/15] Updated to love 11.0 --- theme.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/theme.lua b/theme.lua index 71081fa..7981c21 100644 --- a/theme.lua +++ b/theme.lua @@ -6,9 +6,9 @@ local theme = {} theme.cornerRadius = 4 theme.color = { - normal = {bg = { 66, 66, 66}, fg = {188,188,188}}, - hovered = {bg = { 50,153,187}, fg = {255,255,255}}, - active = {bg = {255,153, 0}, fg = {225,225,225}} + normal = {bg = { 0.25, 0.25, 0.25}, fg = {0.73,0.73,0.73}}, + hovered = {bg = { 0.19,0.6,0.73}, fg = {1,1,1}}, + active = {bg = {1,0.6, 0}, fg = {1,1,1}} } From bd3811ec0305d607a5f412a8f70ce7ec83534a26 Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Sun, 8 Apr 2018 13:58:49 +0200 Subject: [PATCH 02/15] Fix #62: Add rockspec --- suit-0.1-1.rockspec | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 suit-0.1-1.rockspec diff --git a/suit-0.1-1.rockspec b/suit-0.1-1.rockspec new file mode 100644 index 0000000..1fae147 --- /dev/null +++ b/suit-0.1-1.rockspec @@ -0,0 +1,24 @@ +package = "suit" +version = "0.1-1" +source = { + url = "git://github.com/vrld/suit.git" +} +description = {"Immediate mode GUI library in pure Lua."} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + ["suit"] = "init.lua", + ["suit.button"] = "button.lua", + ["suit.checkbox"] = "checkbox.lua", + ["suit.core"] = "core.lua", + ["suit.imagebutton"] = "imagebutton.lua", + ["suit.input"] = "input.lua", + ["suit.label"] = "label.lua", + ["suit.layout"] = "layout.lua", + ["suit.slider"] = "slider.lua", + ["suit.theme"] = "theme.lua", + } +} From 8ec0e638cedd4311058f99525c0e2f2a285a30bd Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Sun, 8 Apr 2018 14:15:21 +0200 Subject: [PATCH 03/15] Fix rockspec --- suit-0.1-1.rockspec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/suit-0.1-1.rockspec b/suit-0.1-1.rockspec index 1fae147..f2d5a29 100644 --- a/suit-0.1-1.rockspec +++ b/suit-0.1-1.rockspec @@ -3,7 +3,11 @@ version = "0.1-1" source = { url = "git://github.com/vrld/suit.git" } -description = {"Immediate mode GUI library in pure Lua."} +description = { + summary="Immediate mode GUI library in pure Lua.", + homepage = "https://suit.readthedocs.io", + license = "MIT", +} dependencies = { "lua >= 5.1" } From eabad8c554fec63b495e27ae540ae90e1ba87f26 Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Sun, 17 Jun 2018 18:10:18 +0200 Subject: [PATCH 04/15] =?UTF-8?q?Fix=20#68:=20ImageButton=20error=20on=20L?= =?UTF-8?q?=C3=96VE=2011.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduction of new option `mask` that should hold an ImageData for the alpha test. --- docs/index.rst | 25 +++++++++++++------------ docs/widgets.rst | 14 +++++++++++--- imagebutton.lua | 39 ++++++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index bfb3156..6e98931 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -49,7 +49,7 @@ The following code will create this UI: -- generate some assets (below) function love.load() snd = generateClickySound() - normal, hovered, active = generateImageButton() + normal, hovered, active, mask = generateImageButton() smallerFont = love.graphics.newFont(10) end @@ -128,13 +128,14 @@ The following code will create this UI: -- put an image button below the nested cell -- the size of the cell will be 200 by 100 px, -- but the image may be bigger or smaller - -- the button shows the image `normal' when the mouse is outside the image - -- or above a transparent pixel - -- the button shows the image `hovered` if the mouse is above an opaque pixel - -- of the image `normal' + -- the button shows the image `normal' when the button is inactive + -- the button shows the image `hovered` if the mouse is over an opaque pixel + -- of the ImageData `mask` -- the button shows the image `active` if the mouse is above an opaque pixel - -- of the image `normal' and the mouse button is pressed - suit.ImageButton(normal, {hovered = hovered, active = active}, suit.layout:row(200,100)) + -- of the ImageData `mask` and the mouse button is pressed + -- if `mask` is omitted, the alpha-test will be swapped for a test whether + -- the mouse is in the area occupied by the widget + suit.ImageButton(normal, {mask = mask, hovered = hovered, active = active}, suit.layout:row(200,50)) -- if the checkbox is checked, display a precomputed layout if chk.checked then @@ -200,17 +201,17 @@ The following code will create this UI: local d2 = math.exp(-((px+.7)^2 + (py+.1)^2) * 2) local d = (d1 + d2)/2 if d > t then - return r,g,b, 255 * ((d-t) / (1-t))^.2 + return r,g,b, ((d-t) / (1-t))^.2 end return 0,0,0,0 end end local normal, hovered, active = love.image.newImageData(200,100), love.image.newImageData(200,100), love.image.newImageData(200,100) - normal:mapPixel(metaballs(.48, 188,188,188)) - hovered:mapPixel(metaballs(.46, 50,153,187)) - active:mapPixel(metaballs(.43, 255,153,0)) - return love.graphics.newImage(normal), love.graphics.newImage(hovered), love.graphics.newImage(active) + normal:mapPixel(metaballs(.48, .74,.74,.74)) + hovered:mapPixel(metaballs(.46, .2,.6,.6)) + active:mapPixel(metaballs(.43, 1,.6,0)) + return love.graphics.newImage(normal), love.graphics.newImage(hovered), love.graphics.newImage(active), normal end Indices and tables diff --git a/docs/widgets.rst b/docs/widgets.rst index c0f18eb..6ffe7cf 100644 --- a/docs/widgets.rst +++ b/docs/widgets.rst @@ -30,7 +30,7 @@ Creates a label at position ``(x,y)`` with width ``w`` and height ``h``. .. function:: ImageButton(normal, options, x,y) - :param Image normal: Image of the button in normal state. + :param mixed normal: Image of the button in normal state. :param table options: Widget options. :param numbers x,y: Upper left corner of the widget. :returns: Return state (see below). @@ -39,13 +39,21 @@ Creates an image button widget at position ``(x,y)``. Unlike all other widgets, an ``ImageButton`` is not affected by the current theme. The argument ``normal`` defines the image of the normal state as well as the -area of the widget: The button activates when the mouse is over a pixel with -non-zero alpha value. +area of the widget. +The button activates when the mouse enters the area occupied by the widget. +If the option ``mask`` defined, the button activates only if the mouse is over +a pixel with non-zero alpha. +You can provide additional ``hovered`` and ``active`` images, but the widget area +is always computed from the ``normal`` image. You can provide additional ``hovered`` and ``active`` images, but the widget area is always computed from the ``normal`` image. **Additional Options:** +``mask`` + Alpha-mask of the button, i.e. an ``ImageData`` of the same size as the + ``normal`` image that has non-zero alpha where the button should activate. + ``normal`` Image for the normal state of the widget. Defaults to widget payload. diff --git a/imagebutton.lua b/imagebutton.lua index 0cf544a..cf7483a 100644 --- a/imagebutton.lua +++ b/imagebutton.lua @@ -2,36 +2,49 @@ local BASE = (...):match('(.-)[^%.]+$') +local function isType(val, typ) + return type(val) == "userdata" and val.typeOf and val:typeOf(typ) +end + return function(core, normal, ...) local opt, x,y = core.getOptionsAndSize(...) opt.normal = normal or opt.normal or opt[1] opt.hovered = opt.hovered or opt[2] or opt.normal opt.active = opt.active or opt[3] or opt.hovered - assert(opt.normal, "Need at least `normal' state image") opt.id = opt.id or opt.normal - opt.state = core:registerMouseHit(opt.id, x,y, function(u,v) - local id = opt.normal:getData() - assert(id:typeOf("ImageData"), "Can only use uncompressed images") + local image = assert(opt.normal, "No image for state `normal'") + + core:registerMouseHit(opt.id, x, y, function(u,v) + -- mouse in image? u, v = math.floor(u+.5), math.floor(v+.5) - if u < 0 or u >= opt.normal:getWidth() or v < 0 or v >= opt.normal:getHeight() then + if u < 0 or u >= image:getWidth() or v < 0 or v >= mask:getHeight() then return false end - local _,_,_,a = id:getPixel(u,v) - return a > 0 + + if opt.mask then + -- alpha test + assert(isType(opt.mask, "ImageData"), "Option `mask` is not a love.image.ImageData") + assert(u < mask:getWidth() and v < mask:getHeight(), "Mask may not be smaller than image.") + local _,_,_,a = mask:getPixel(u,v) + return a > 0 + end + + return true end) - local img = opt.normal if core:isActive(opt.id) then - img = opt.active + image = opt.active elseif core:isHovered(opt.id) then - img = opt.hovered + image = opt.hovered end - core:registerDraw(opt.draw or function(img,x,y, r,g,b,a) + assert(isType(image, "Image"), "state image is not a love.graphics.image") + + core:registerDraw(opt.draw or function(image,x,y, r,g,b,a) love.graphics.setColor(r,g,b,a) - love.graphics.draw(img,x,y) - end, img, x,y, love.graphics.getColor()) + love.graphics.draw(image,x,y) + end, image, x,y, love.graphics.getColor()) return { id = opt.id, From 2f479ba30a8c3284d2d4ebd9b350a2435f4454c6 Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Sun, 17 Jun 2018 18:52:30 +0200 Subject: [PATCH 05/15] Fix #70: overlapping buttons both react to hover --- core.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.lua b/core.lua index 5b4d2ee..716aa6c 100644 --- a/core.lua +++ b/core.lua @@ -100,7 +100,7 @@ function suit:mouseInRect(x,y,w,h) end function suit:registerMouseHit(id, ul_x, ul_y, hit) - if hit(self.mouse_x - ul_x, self.mouse_y - ul_y) then + if not self.hovered and hit(self.mouse_x - ul_x, self.mouse_y - ul_y) then self.hovered = id if self.active == nil and self.mouse_button_down then self.active = id From 0a723777ed92dca7b3bfb6805876cc79a67c5ba6 Mon Sep 17 00:00:00 2001 From: Matthias Richter Date: Thu, 21 Jun 2018 23:46:58 +0200 Subject: [PATCH 06/15] [docs] better words --- docs/gettingstarted.rst | 49 ++++++++++++++++++++++------------------- docs/index.rst | 25 +++++++++++++++++++-- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst index 51605f3..7605047 100644 --- a/docs/gettingstarted.rst +++ b/docs/gettingstarted.rst @@ -5,7 +5,7 @@ Before actually getting started, it is important to understand the motivation and mechanics behind SUIT: - **Immediate mode is better than retained mode** -- **Layout does not care about widgets** +- **Layout should not care about content** - **Less is more** Immediate mode? @@ -68,11 +68,11 @@ to design a user interface. SUIT is not a complete GUI library: It does not take control of the runtime. You have to do everything yourself [1]_. -**SUIT is not good at word processors!** +**SUIT is not good at processing words!** -Hello, World ------------- +Hello, World! +------------- SUITing up is is straightforward: Define your GUI in ``love.update()``, and draw it in ``love.draw()``:: @@ -96,15 +96,19 @@ draw it in ``love.draw()``:: suit.draw() end -This will produce this UI (after clicking the button): +This will produce this UI: .. image:: _static/hello-world.gif -As written above, the two widgets are each created by a function call +The two widgets (the button and the label) are each created by a function call (:func:`suit.Button