Compare commits
No commits in common. "master" and "v0.10" have entirely different histories.
10 changed files with 66 additions and 198 deletions
|
@ -6,7 +6,6 @@ return function(core, text, ...)
|
||||||
local opt, x,y,w,h = core.getOptionsAndSize(...)
|
local opt, x,y,w,h = core.getOptionsAndSize(...)
|
||||||
opt.id = opt.id or text
|
opt.id = opt.id or text
|
||||||
opt.font = opt.font or love.graphics.getFont()
|
opt.font = opt.font or love.graphics.getFont()
|
||||||
opt.color = opt.color or core.theme.color
|
|
||||||
|
|
||||||
w = w or opt.font:getWidth(text) + 4
|
w = w or opt.font:getWidth(text) + 4
|
||||||
h = h or opt.font:getHeight() + 4
|
h = h or opt.font:getHeight() + 4
|
||||||
|
@ -19,10 +18,6 @@ return function(core, text, ...)
|
||||||
hit = core:mouseReleasedOn(opt.id),
|
hit = core:mouseReleasedOn(opt.id),
|
||||||
hovered = core:isHovered(opt.id),
|
hovered = core:isHovered(opt.id),
|
||||||
entered = core:isHovered(opt.id) and not core:wasHovered(opt.id),
|
entered = core:isHovered(opt.id) and not core:wasHovered(opt.id),
|
||||||
left = not core:isHovered(opt.id) and core:wasHovered(opt.id),
|
left = not core:isHovered(opt.id) and core:wasHovered(opt.id)
|
||||||
x = x,
|
|
||||||
y = y,
|
|
||||||
w = w,
|
|
||||||
h = h
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
19
core.lua
19
core.lua
|
@ -100,7 +100,7 @@ function suit:mouseInRect(x,y,w,h)
|
||||||
end
|
end
|
||||||
|
|
||||||
function suit:registerMouseHit(id, ul_x, ul_y, hit)
|
function suit:registerMouseHit(id, ul_x, ul_y, hit)
|
||||||
if not self.hovered and hit(self.mouse_x - ul_x, self.mouse_y - ul_y) then
|
if hit(self.mouse_x - ul_x, self.mouse_y - ul_y) then
|
||||||
self.hovered = id
|
self.hovered = id
|
||||||
if self.active == nil and self.mouse_button_down then
|
if self.active == nil and self.mouse_button_down then
|
||||||
self.active = id
|
self.active = id
|
||||||
|
@ -176,24 +176,15 @@ function suit:keyPressedOn(id, key)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- state update
|
-- state update
|
||||||
function suit:enterFrame(mouseX, mouseY)
|
function suit:enterFrame()
|
||||||
if not self.mouse_button_down then
|
if not self.mouse_button_down then
|
||||||
self.active = nil
|
self.active = nil
|
||||||
elseif self.active == nil then
|
elseif self.active == nil then
|
||||||
self.active = NONE
|
self.active = NONE
|
||||||
end
|
end
|
||||||
local mx = mouseX
|
|
||||||
local my = mouseY
|
|
||||||
|
|
||||||
if mx == nil then
|
|
||||||
mx = love.mouse.getX()
|
|
||||||
end
|
|
||||||
if my == nil then
|
|
||||||
my = love.mouse.getY()
|
|
||||||
end
|
|
||||||
|
|
||||||
self.hovered_last, self.hovered = self.hovered, nil
|
self.hovered_last, self.hovered = self.hovered, nil
|
||||||
self:updateMouse(mx, my, love.mouse.isDown(1))
|
self:updateMouse(love.mouse.getX(), love.mouse.getY(), love.mouse.isDown(1))
|
||||||
self.key_down, self.textchar = nil, ""
|
self.key_down, self.textchar = nil, ""
|
||||||
self:grabKeyboardFocus(NONE)
|
self:grabKeyboardFocus(NONE)
|
||||||
self.hit = nil
|
self.hit = nil
|
||||||
|
@ -213,14 +204,14 @@ function suit:registerDraw(f, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function suit:draw()
|
function suit:draw()
|
||||||
-- self:exitFrame() -- CALL these manually in your update method
|
self:exitFrame()
|
||||||
love.graphics.push('all')
|
love.graphics.push('all')
|
||||||
for i = self.draw_queue.n,1,-1 do
|
for i = self.draw_queue.n,1,-1 do
|
||||||
self.draw_queue[i]()
|
self.draw_queue[i]()
|
||||||
end
|
end
|
||||||
love.graphics.pop()
|
love.graphics.pop()
|
||||||
self.draw_queue.n = 0
|
self.draw_queue.n = 0
|
||||||
-- self:enterFrame() -- CALL these manually in your update method
|
self:enterFrame()
|
||||||
end
|
end
|
||||||
|
|
||||||
return suit
|
return suit
|
||||||
|
|
|
@ -5,7 +5,7 @@ Before actually getting started, it is important to understand the motivation
|
||||||
and mechanics behind SUIT:
|
and mechanics behind SUIT:
|
||||||
|
|
||||||
- **Immediate mode is better than retained mode**
|
- **Immediate mode is better than retained mode**
|
||||||
- **Layout should not care about content**
|
- **Layout does not care about widgets**
|
||||||
- **Less is more**
|
- **Less is more**
|
||||||
|
|
||||||
Immediate mode?
|
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.
|
SUIT is not a complete GUI library: It does not take control of the runtime.
|
||||||
You have to do everything yourself [1]_.
|
You have to do everything yourself [1]_.
|
||||||
|
|
||||||
**SUIT is not good at processing words!**
|
**SUIT is not good at word processors!**
|
||||||
|
|
||||||
|
|
||||||
Hello, World!
|
Hello, World
|
||||||
-------------
|
------------
|
||||||
|
|
||||||
SUITing up is is straightforward: Define your GUI in ``love.update()``, and
|
SUITing up is is straightforward: Define your GUI in ``love.update()``, and
|
||||||
draw it in ``love.draw()``::
|
draw it in ``love.draw()``::
|
||||||
|
@ -96,19 +96,15 @@ draw it in ``love.draw()``::
|
||||||
suit.draw()
|
suit.draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
This will produce this UI:
|
This will produce this UI (after clicking the button):
|
||||||
|
|
||||||
.. image:: _static/hello-world.gif
|
.. image:: _static/hello-world.gif
|
||||||
|
|
||||||
The two widgets (the button and the label) are each created by a function call
|
As written above, the two widgets are each created by a function call
|
||||||
(:func:`suit.Button <Button>` and :func:`suit.Label <Label>`). The first
|
(:func:`suit.Button <Button>` and :func:`suit.Label <Label>`). The first
|
||||||
argument to a widget function always defines the *payload* of the widget.
|
argument to a widget function is always the "payload" of the widget, and the
|
||||||
Different widgets expect different payloads.
|
last four arguments define the position and dimension of the widget. The
|
||||||
Here, both :func:`suit.Button <Button>` and :func:`suit.Label <Label>` expect a
|
function returns a table that indicates the UI state of the widget.
|
||||||
string.
|
|
||||||
The last four arguments of a widget function define the position and dimension
|
|
||||||
of the widget.
|
|
||||||
The function returns a table that indicates the UI state of the widget.
|
|
||||||
Here, the state ``hit`` is used to figure out if the mouse was clicked and
|
Here, the state ``hit`` is used to figure out if the mouse was clicked and
|
||||||
released on the button. See :doc:`Widgets <widgets>` for more info on widget
|
released on the button. See :doc:`Widgets <widgets>` for more info on widget
|
||||||
states.
|
states.
|
||||||
|
@ -116,8 +112,8 @@ states.
|
||||||
Mutable state
|
Mutable state
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Widgets that mutate some state - input boxes, checkboxes and sliders - expect
|
Widgets that mutate some state - input boxes, checkboxes and sliders - receive
|
||||||
a table as their payload, e.g.::
|
a table argument as payload, e.g.::
|
||||||
|
|
||||||
local slider = {value = 1, min = 0, max = 2}
|
local slider = {value = 1, min = 0, max = 2}
|
||||||
function love.update(dt)
|
function love.update(dt)
|
||||||
|
@ -135,7 +131,8 @@ Options
|
||||||
-------
|
-------
|
||||||
|
|
||||||
You can define optional, well, options after the payload. Most options affect
|
You can define optional, well, options after the payload. Most options affect
|
||||||
how the widget is drawn. For example, to align the label text to the left::
|
how the widget is drawn. For example, to align the label text to the left in
|
||||||
|
the above example, you would write::
|
||||||
|
|
||||||
local slider = {value = 1, max = 2}
|
local slider = {value = 1, max = 2}
|
||||||
function love.update(dt)
|
function love.update(dt)
|
||||||
|
@ -151,8 +148,8 @@ the theme. See :doc:`Widgets <widgets>` for more info on widget options.
|
||||||
Keyboard input
|
Keyboard input
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The :func:`Input` widget requires that you forward the ``keypressed`` and
|
The :func:`input widget <Input>` requires that you forward the ``keypressed``
|
||||||
``textinput`` events to SUIT::
|
and ``textinput`` events to SUIT::
|
||||||
|
|
||||||
local input = {text = ""}
|
local input = {text = ""}
|
||||||
function love.update(dt)
|
function love.update(dt)
|
||||||
|
@ -171,7 +168,7 @@ The :func:`Input` widget requires that you forward the ``keypressed`` and
|
||||||
|
|
||||||
.. image:: _static/keyboard.gif
|
.. image:: _static/keyboard.gif
|
||||||
|
|
||||||
The :func:`Slider` widget can also react to keyboard input. The mouse state is
|
The slider widget can also react to keyboard input. The mouse state is
|
||||||
automatically updated, but you can provide your own version of reality if you
|
automatically updated, but you can provide your own version of reality if you
|
||||||
need to. See the :doc:`Core functions <core>` for more details.
|
need to. See the :doc:`Core functions <core>` for more details.
|
||||||
|
|
||||||
|
@ -188,7 +185,7 @@ you can directly pass as the final four arguments to the widget functions.
|
||||||
If you have ever dabbled with `Qt's <http://qt.io>`_ ``QBoxLayout``, you
|
If you have ever dabbled with `Qt's <http://qt.io>`_ ``QBoxLayout``, you
|
||||||
already know 89% [2]_ of what you need to know.
|
already know 89% [2]_ of what you need to know.
|
||||||
|
|
||||||
Hello, World! can be rewritten as follows::
|
The first example can be written as follows::
|
||||||
|
|
||||||
suit = require 'suit'
|
suit = require 'suit'
|
||||||
|
|
||||||
|
@ -237,10 +234,10 @@ Refer to the :doc:`Layout <layout>` documentation for more information.
|
||||||
Widget ids
|
Widget ids
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Each widget is identified by an ``id`` [4]_. Internally, this ``id`` is used to
|
Each widget is identified by an ``id`` [4]_. Internally, this ``id`` is used t
|
||||||
figure out which widget should handle user input like mouse clicks and keyboard
|
figure out which widget should handle user input like mouse clicks and keyboard
|
||||||
presses.
|
presses.
|
||||||
Unless specified otherwise, the ``id`` is the same as the payload, i.e.,
|
Unless specified otherwise, the ``id`` is the same as the first argument, i.e.,
|
||||||
the ``id`` of ``Button("Hello, World!", ...)`` will be the string
|
the ``id`` of ``Button("Hello, World!", ...)`` will be the string
|
||||||
``"Hello, World!"``.
|
``"Hello, World!"``.
|
||||||
In almost all of the cases, this will work fine and you don't have to worry about
|
In almost all of the cases, this will work fine and you don't have to worry about
|
||||||
|
@ -335,10 +332,10 @@ You can also do minimally invasive surgery::
|
||||||
GUI Instances
|
GUI Instances
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Sometimes you might feel the need to separate parts of the GUI. Maybe certain
|
Sometimes you might feel the need to separate parts of the GUI. Maybe the
|
||||||
UI elements should always be drawn before or after other UI elements, or maybe
|
widgets should have a different theme, maybe certain should always be drawn
|
||||||
you don't want the UI state to "leak" (e.g., from a stacked pause gamestate to
|
before or after other UI elements, or maybe you don't want the UI state to
|
||||||
the main gamestate).
|
"leak" (e.g., from a stacked pause gamestate to the main gamestate).
|
||||||
|
|
||||||
For this reason, SUIT allows you to create GUI instances::
|
For this reason, SUIT allows you to create GUI instances::
|
||||||
|
|
||||||
|
|
|
@ -12,35 +12,14 @@ You may also download the sourcecode as a `zip
|
||||||
<http://github.com/vrld/SUIT/zipball/master>`_ or `tar
|
<http://github.com/vrld/SUIT/zipball/master>`_ or `tar
|
||||||
<http://github.com/vrld/SUIT/tarball/master>`_ file.
|
<http://github.com/vrld/SUIT/tarball/master>`_ file.
|
||||||
|
|
||||||
Otherwise, use `Git <http://git-scm.com>`_::
|
Using `Git <http://git-scm.com>`_, you can clone the project by running::
|
||||||
|
|
||||||
git clone git://github.com/vrld/SUIT
|
git clone git://github.com/vrld/SUIT
|
||||||
|
|
||||||
Update::
|
Once done, you can check for updates by running::
|
||||||
|
|
||||||
git pull
|
git pull
|
||||||
|
|
||||||
Hello, Suit::
|
|
||||||
|
|
||||||
suit = require 'suit'
|
|
||||||
|
|
||||||
local show_message = false
|
|
||||||
function love.update(dt)
|
|
||||||
-- Put a button on the screen. If hit, show a message.
|
|
||||||
if suit.Button("Hello, World!", 100,100, 300,30).hit then
|
|
||||||
show_message = true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if the button was pressed at least one time, but a label below
|
|
||||||
if show_message then
|
|
||||||
suit.Label("How are you today?", 100,150, 300,30)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.draw()
|
|
||||||
suit.draw()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
Read on
|
Read on
|
||||||
-------
|
-------
|
||||||
|
@ -70,7 +49,7 @@ The following code will create this UI:
|
||||||
-- generate some assets (below)
|
-- generate some assets (below)
|
||||||
function love.load()
|
function love.load()
|
||||||
snd = generateClickySound()
|
snd = generateClickySound()
|
||||||
normal, hovered, active, mask = generateImageButton()
|
normal, hovered, active = generateImageButton()
|
||||||
smallerFont = love.graphics.newFont(10)
|
smallerFont = love.graphics.newFont(10)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,14 +128,13 @@ The following code will create this UI:
|
||||||
-- put an image button below the nested cell
|
-- put an image button below the nested cell
|
||||||
-- the size of the cell will be 200 by 100 px,
|
-- the size of the cell will be 200 by 100 px,
|
||||||
-- but the image may be bigger or smaller
|
-- but the image may be bigger or smaller
|
||||||
-- the button shows the image `normal' when the button is inactive
|
-- the button shows the image `normal' when the mouse is outside the image
|
||||||
-- the button shows the image `hovered` if the mouse is over an opaque pixel
|
-- or above a transparent pixel
|
||||||
-- of the ImageData `mask`
|
-- the button shows the image `hovered` if the mouse is above an opaque pixel
|
||||||
|
-- of the image `normal'
|
||||||
-- the button shows the image `active` if the mouse is above an opaque pixel
|
-- the button shows the image `active` if the mouse is above an opaque pixel
|
||||||
-- of the ImageData `mask` and the mouse button is pressed
|
-- of the image `normal' and the mouse button is pressed
|
||||||
-- if `mask` is omitted, the alpha-test will be swapped for a test whether
|
suit.ImageButton(normal, {hovered = hovered, active = active}, suit.layout:row(200,100))
|
||||||
-- 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 the checkbox is checked, display a precomputed layout
|
||||||
if chk.checked then
|
if chk.checked then
|
||||||
|
@ -222,17 +200,17 @@ The following code will create this UI:
|
||||||
local d2 = math.exp(-((px+.7)^2 + (py+.1)^2) * 2)
|
local d2 = math.exp(-((px+.7)^2 + (py+.1)^2) * 2)
|
||||||
local d = (d1 + d2)/2
|
local d = (d1 + d2)/2
|
||||||
if d > t then
|
if d > t then
|
||||||
return r,g,b, ((d-t) / (1-t))^.2
|
return r,g,b, 255 * ((d-t) / (1-t))^.2
|
||||||
end
|
end
|
||||||
return 0,0,0,0
|
return 0,0,0,0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local normal, hovered, active = love.image.newImageData(200,100), love.image.newImageData(200,100), love.image.newImageData(200,100)
|
local normal, hovered, active = love.image.newImageData(200,100), love.image.newImageData(200,100), love.image.newImageData(200,100)
|
||||||
normal:mapPixel(metaballs(.48, .74,.74,.74))
|
normal:mapPixel(metaballs(.48, 188,188,188))
|
||||||
hovered:mapPixel(metaballs(.46, .2,.6,.6))
|
hovered:mapPixel(metaballs(.46, 50,153,187))
|
||||||
active:mapPixel(metaballs(.43, 1,.6,0))
|
active:mapPixel(metaballs(.43, 255,153,0))
|
||||||
return love.graphics.newImage(normal), love.graphics.newImage(hovered), love.graphics.newImage(active), normal
|
return love.graphics.newImage(normal), love.graphics.newImage(hovered), love.graphics.newImage(active)
|
||||||
end
|
end
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
|
|
|
@ -30,7 +30,7 @@ Creates a label at position ``(x,y)`` with width ``w`` and height ``h``.
|
||||||
|
|
||||||
.. function:: ImageButton(normal, options, x,y)
|
.. function:: ImageButton(normal, options, x,y)
|
||||||
|
|
||||||
:param mixed normal: Image of the button in normal state.
|
:param Image normal: Image of the button in normal state.
|
||||||
:param table options: Widget options.
|
:param table options: Widget options.
|
||||||
:param numbers x,y: Upper left corner of the widget.
|
:param numbers x,y: Upper left corner of the widget.
|
||||||
:returns: Return state (see below).
|
:returns: Return state (see below).
|
||||||
|
@ -39,21 +39,13 @@ Creates an image button widget at position ``(x,y)``.
|
||||||
Unlike all other widgets, an ``ImageButton`` is not affected by the current
|
Unlike all other widgets, an ``ImageButton`` is not affected by the current
|
||||||
theme.
|
theme.
|
||||||
The argument ``normal`` defines the image of the normal state as well as the
|
The argument ``normal`` defines the image of the normal state as well as the
|
||||||
area of the widget.
|
area of the widget: The button activates when the mouse is over a pixel with
|
||||||
The button activates when the mouse enters the area occupied by the widget.
|
non-zero alpha value.
|
||||||
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
|
You can provide additional ``hovered`` and ``active`` images, but the widget area
|
||||||
is always computed from the ``normal`` image.
|
is always computed from the ``normal`` image.
|
||||||
|
|
||||||
**Additional Options:**
|
**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``
|
``normal``
|
||||||
Image for the normal state of the widget. Defaults to widget payload.
|
Image for the normal state of the widget. Defaults to widget payload.
|
||||||
|
|
||||||
|
|
|
@ -2,49 +2,36 @@
|
||||||
|
|
||||||
local BASE = (...):match('(.-)[^%.]+$')
|
local BASE = (...):match('(.-)[^%.]+$')
|
||||||
|
|
||||||
local function isType(val, typ)
|
|
||||||
return type(val) == "userdata" and val.typeOf and val:typeOf(typ)
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(core, normal, ...)
|
return function(core, normal, ...)
|
||||||
local opt, x,y = core.getOptionsAndSize(...)
|
local opt, x,y = core.getOptionsAndSize(...)
|
||||||
opt.normal = normal or opt.normal or opt[1]
|
opt.normal = normal or opt.normal or opt[1]
|
||||||
opt.hovered = opt.hovered or opt[2] or opt.normal
|
opt.hovered = opt.hovered or opt[2] or opt.normal
|
||||||
opt.active = opt.active or opt[3] or opt.hovered
|
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.id = opt.id or opt.normal
|
||||||
|
|
||||||
local image = assert(opt.normal, "No image for state `normal'")
|
opt.state = core:registerMouseHit(opt.id, x,y, function(u,v)
|
||||||
|
local id = opt.normal:getData()
|
||||||
core:registerMouseHit(opt.id, x, y, function(u,v)
|
assert(id:typeOf("ImageData"), "Can only use uncompressed images")
|
||||||
-- mouse in image?
|
|
||||||
u, v = math.floor(u+.5), math.floor(v+.5)
|
u, v = math.floor(u+.5), math.floor(v+.5)
|
||||||
if u < 0 or u >= image:getWidth() or v < 0 or v >= image:getHeight() then
|
if u < 0 or u >= opt.normal:getWidth() or v < 0 or v >= opt.normal:getHeight() then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
local _,_,_,a = id:getPixel(u,v)
|
||||||
if opt.mask then
|
return a > 0
|
||||||
-- 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)
|
end)
|
||||||
|
|
||||||
|
local img = opt.normal
|
||||||
if core:isActive(opt.id) then
|
if core:isActive(opt.id) then
|
||||||
image = opt.active
|
img = opt.active
|
||||||
elseif core:isHovered(opt.id) then
|
elseif core:isHovered(opt.id) then
|
||||||
image = opt.hovered
|
img = opt.hovered
|
||||||
end
|
end
|
||||||
|
|
||||||
assert(isType(image, "Image"), "state image is not a love.graphics.image")
|
core:registerDraw(opt.draw or function(img,x,y, r,g,b,a)
|
||||||
|
|
||||||
core:registerDraw(opt.draw or function(image,x,y, r,g,b,a)
|
|
||||||
love.graphics.setColor(r,g,b,a)
|
love.graphics.setColor(r,g,b,a)
|
||||||
love.graphics.draw(image,x,y)
|
love.graphics.draw(img,x,y)
|
||||||
end, image, x,y, love.graphics.getColor())
|
end, img, x,y, love.graphics.getColor())
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id = opt.id,
|
id = opt.id,
|
||||||
|
|
|
@ -6,7 +6,6 @@ return function(core, text, ...)
|
||||||
local opt, x,y,w,h = core.getOptionsAndSize(...)
|
local opt, x,y,w,h = core.getOptionsAndSize(...)
|
||||||
opt.id = opt.id or text
|
opt.id = opt.id or text
|
||||||
opt.font = opt.font or love.graphics.getFont()
|
opt.font = opt.font or love.graphics.getFont()
|
||||||
opt.color = opt.color or core.theme.color
|
|
||||||
|
|
||||||
w = w or opt.font:getWidth(text) + 4
|
w = w or opt.font:getWidth(text) + 4
|
||||||
h = h or opt.font:getHeight() + 4
|
h = h or opt.font:getHeight() + 4
|
||||||
|
|
|
@ -15,7 +15,6 @@ function Layout:reset(x,y, padx,pady)
|
||||||
self._widths = {}
|
self._widths = {}
|
||||||
self._heights = {}
|
self._heights = {}
|
||||||
self._isFirstCell = true
|
self._isFirstCell = true
|
||||||
self._start_x = self._x
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
@ -36,12 +35,6 @@ function Layout:nextRow()
|
||||||
return self._x, self._y + self._h + self._pady
|
return self._x, self._y + self._h + self._pady
|
||||||
end
|
end
|
||||||
|
|
||||||
function Layout:newRow()
|
|
||||||
self._x = self._start_x
|
|
||||||
self._y = self._y + self._h + self._pady
|
|
||||||
self._w = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
Layout.nextDown = Layout.nextRow
|
Layout.nextDown = Layout.nextRow
|
||||||
|
|
||||||
function Layout:nextCol()
|
function Layout:nextCol()
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package = "suit"
|
|
||||||
version = "0.1-1"
|
|
||||||
source = {
|
|
||||||
url = "git://github.com/vrld/suit.git"
|
|
||||||
}
|
|
||||||
description = {
|
|
||||||
summary="Immediate mode GUI library in pure Lua.",
|
|
||||||
homepage = "https://suit.readthedocs.io",
|
|
||||||
license = "MIT",
|
|
||||||
}
|
|
||||||
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",
|
|
||||||
}
|
|
||||||
}
|
|
50
theme.lua
50
theme.lua
|
@ -6,9 +6,9 @@ local theme = {}
|
||||||
theme.cornerRadius = 4
|
theme.cornerRadius = 4
|
||||||
|
|
||||||
theme.color = {
|
theme.color = {
|
||||||
normal = {bg = { 0.25, 0.25, 0.25}, fg = {0.73,0.73,0.73}},
|
normal = {bg = { 66, 66, 66}, fg = {188,188,188}},
|
||||||
hovered = {bg = { 0.19,0.6,0.73}, fg = {1,1,1}},
|
hovered = {bg = { 50,153,187}, fg = {255,255,255}},
|
||||||
active = {bg = {1,0.6, 0}, fg = {1,1,1}}
|
active = {bg = {255,153, 0}, fg = {225,225,225}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,32 +18,16 @@ function theme.getColorForState(opt)
|
||||||
return (opt.color and opt.color[opt.state]) or theme.color[s]
|
return (opt.color and opt.color[opt.state]) or theme.color[s]
|
||||||
end
|
end
|
||||||
|
|
||||||
function theme.drawBox(x,y,w,h, colors, cornerRadius, outline, scale)
|
function theme.drawBox(x,y,w,h, colors, cornerRadius)
|
||||||
colors = colors or theme.getColorForState(opt)
|
colors = colors or theme.getColorForState(opt)
|
||||||
cornerRadius = (cornerRadius or theme.cornerRadius)
|
cornerRadius = cornerRadius or theme.cornerRadius
|
||||||
w = math.max(cornerRadius/2, w)
|
w = math.max(cornerRadius/2, w)
|
||||||
if h < cornerRadius/2 then
|
if h < cornerRadius/2 then
|
||||||
y,h = y - (cornerRadius - h), cornerRadius/2
|
y,h = y - (cornerRadius - h), cornerRadius/2
|
||||||
end
|
end
|
||||||
|
|
||||||
-- by default, scale will operate about the center of the box. meaning it grows
|
|
||||||
-- out/in in all directions
|
|
||||||
if scale and scale ~= 1.0 then
|
|
||||||
local baseW, baseH = w, h
|
|
||||||
w = w * scale
|
|
||||||
h = h * scale
|
|
||||||
x = x - (w - baseW) / 2
|
|
||||||
y = y - (h - baseH) / 2
|
|
||||||
cornerRadius = cornerRadius * scale
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setColor(colors.bg)
|
love.graphics.setColor(colors.bg)
|
||||||
love.graphics.rectangle('fill', x,y, w,h, cornerRadius)
|
love.graphics.rectangle('fill', x,y, w,h, cornerRadius)
|
||||||
if outline ~= nil then
|
|
||||||
love.graphics.setColor(colors.fg)
|
|
||||||
love.graphics.setLineWidth(outline)
|
|
||||||
love.graphics.rectangle('line', x,y, w,h, cornerRadius)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function theme.getVerticalOffsetForAlign(valign, font, h)
|
function theme.getVerticalOffsetForAlign(valign, font, h)
|
||||||
|
@ -67,33 +51,13 @@ end
|
||||||
|
|
||||||
function theme.Button(text, opt, x,y,w,h)
|
function theme.Button(text, opt, x,y,w,h)
|
||||||
local c = theme.getColorForState(opt)
|
local c = theme.getColorForState(opt)
|
||||||
local scale = opt.scale or 1.0
|
|
||||||
|
|
||||||
theme.drawBox(x,y,w,h, c, opt.cornerRadius, opt.outline, scale)
|
theme.drawBox(x,y,w,h, c, opt.cornerRadius)
|
||||||
love.graphics.setColor(c.fg)
|
love.graphics.setColor(c.fg)
|
||||||
love.graphics.setFont(opt.font)
|
love.graphics.setFont(opt.font)
|
||||||
|
|
||||||
-- ensure text remains aligned regardless of scale
|
|
||||||
local align = opt.align or "center"
|
|
||||||
local textX = x
|
|
||||||
local textY = y
|
|
||||||
local textW = w
|
|
||||||
if scale ~= 1.0 then
|
|
||||||
-- For center alignment, shift x so the scaled text stays centered
|
|
||||||
if align == "center" then
|
|
||||||
textX = x + (w - w * scale) / 2
|
|
||||||
elseif align == "right" then
|
|
||||||
textX = x + (w - w * scale)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
y = y + theme.getVerticalOffsetForAlign(opt.valign, opt.font, h)
|
y = y + theme.getVerticalOffsetForAlign(opt.valign, opt.font, h)
|
||||||
love.graphics.printf(text, textX+2, textY, textW-4,
|
love.graphics.printf(text, x+2, y, w-4, opt.align or "center")
|
||||||
align,
|
|
||||||
0,
|
|
||||||
scale,
|
|
||||||
scale
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function theme.Checkbox(chk, opt, x,y,w,h)
|
function theme.Checkbox(chk, opt, x,y,w,h)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue