## Quickie [was: Immediate Mode Gui]

vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

### Quickie [was: Immediate Mode Gui]

Inspired by the I hate myself editor gui and by "Sol on Immediate Mode GUIs", I wrote a little imgui implementation in Lua. Things are handled a bit different than described in the blog article. Check the comments in main.lua and button.lua for a (very brief) introduction how things work. I plan to implement keyboard support soon to enable implementing text-boxes and other widgets using the keyboard. Anyway, here it is:
imgui.jpg (10.18 KiB) Viewed 15576 times
Edit: Making the 2D slider do something.
Attachments
imgui.love
Last edited by vrld on Tue Feb 07, 2012 10:27 pm, edited 1 time in total.
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

### Re: Immediate Mode Gui

Very nice vrld! I haven't yet analyzed the code but I already loved this because of the theremin extra!
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Contact:

### Re: Immediate Mode Gui

That sound square needs to be bigger and allow a wider range of frequencies. Otherwise, you can't play the Star Trek theme with it! Such a shame!

Other than that, pretty nice. Pretty nice.
When I write def I mean function.
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

### Re: Immediate Mode Gui

kikito wrote:That sound square needs to be bigger and allow a wider range of frequencies. Otherwise, you can't play the Star Trek theme with it! Such a shame!
But much earlier than some trekie give theremin treatment Delia Derbishire already themed original Dr.Who masterpiece!
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Contact:

### Re: Immediate Mode Gui

coffee wrote:But much earlier than some trekie give theremin treatment Delia Derbishire already themed original Dr.Who masterpiece!
That's no theremin
When I write def I mean function.
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

### Re: Immediate Mode Gui

kikito wrote:
coffee wrote:But much earlier than some trekie give theremin treatment Delia Derbishire already themed original Dr.Who masterpiece!
That's no theremin
But I didn't said that Delia used a theremin. She used basically pure oscillators devices (that is also VRLD demo concept basis) that is also the base of theremin (2 oscillators). Don't worry I know well enough Dr. Who theme and pioneer electronic music to say an incorrection like that.

Well let's not stay anymore off-topic in vrld nice library!

vrld, I think you need sort better intructions. There is need a lot of lecture jumping to understand things now.
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

### Re: Immediate Mode Gui

kikito wrote:That sound square needs to be bigger and allow a wider range of frequencies. Otherwise, you can't play the Star Trek theme with it! Such a shame!
Easy:
• Change (in main.lua) the sound base frequency (in love.load()) to something like 440:

Code: Select all

sd:setSample(i, math.sin(2 * math.pi * 440 * phase))
• Change min/max x-values of the soundctl' table, e.g.

Code: Select all

local soundctl  = {value = {x = 1, y = .5}, min = {x=.3,y=0}, max = {x=3,y=1}}
• Change the 2dslider dimensions and position (don't forget to update the labels as well), e.g

Code: Select all

if gui.Slider2D(soundctl, 360,10,400,400) then
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

### Re: Immediate Mode Gui

Double post because there is now keyboard support (including tab ordering), and an input and checkbox widget. I also separated the widget style from the behavior code, so you can easily swap the global widget style. See quickie/style-default.lua for reference. You can also influence the colors by overwriting the gui.core.style.color and change the look of individual widgets by passing a custom draw function.

I will put this onto github and make a proper documentation soon-ish, but neither usage nor extension is really hard. You can probably grasp the basics of how to use the library by this snippet:

Code: Select all

local gui = require 'quickie'

love.graphics.setFont(love.graphics.newFont(20))
end

-- widgets are "created" by calling their corresponding functions in love.update.
-- if you want to remove a widget, simply don't call the function (just like with
-- any other love drawable). widgets dont hold their own state - this is your job:
--
-- sliders have a value and optional a minimum (default = 0) and maximum (default = 1)
local slider = {value = 10, min = 0, max = 100}
-- input boxes have a text and a cursor position (defaults to end of string)
local input = {text = "Hello, World!", cursor = 0}
-- checkboxes have only a checked' status
local checkbox = {checked = false}

function love.update(dt)
-- widgets are defined by simply calling them. usually a widget returns true if
-- if its value changed or if it was activated (click on button, ...)
if gui.Input(input, 10, 10, 300, 20) then
print('Text changed:', input.text)
end

-- tab order is determined by the order you call the widgets.
if gui.Button('Clear', 320,10,100,20) then
input.text = ""
end

end

function love.draw()
-- draw the widgets which were "created" in love.update
gui.core.draw()
end

function love.keypressed(key,code)
-- forward keyboard events to the gui. If you don't want widget tabbing and
-- input widgets, skip this line
gui.core.keyboard.pressed(key, code)
end
Implementing own widgets is also super easy. gui.core defines some functions to check mouse state, try grabing keyboard focus and more. This is the code to implement the button widget:

Code: Select all

-- (...):match("^(.+)%.[^%.]+") extracts the require base, e.g. when required with
-- require 'quickie.button', the base is 'quickie.'
local core = require((...):match("^(.+)%.[^%.]+") .. '.core')

-- the widget
return function(title, x,y, w,h, draw)
-- Generate unique identifier for gui state update and querying.
local id = core.generateID()

-- The widget mouse-state can be:
--   hot (mouse over widget),
--   active (mouse pressed on widget) or
--   normal (mouse not on widget and not pressed on widget).
--

-- core.makeTabable makes the item focus on tab. Tab order is determied
-- by the order you call the widget functions.
core.makeTabable(id)

-- core.registerDraw(id, drawfunction, drawfunction-arguments...)
-- shows widget when core.draw() is called.
core.registerDraw(id, draw or core.style.Button, title,x,y,w,h)

return core.mouse.releasedOn(id) or
end
And the relevant drawing function is:

Code: Select all

function Button(state, title, x,y,w,h)
local c = color[state]
if state ~= 'normal' then -- draw drop shadow
love.graphics.setColor(c.fg)
love.graphics.rectangle('fill', x+3,y+3,w,h)
end
love.graphics.setColor(c.bg)
love.graphics.rectangle('fill', x,y,w,h)
love.graphics.setColor(c.fg)
local f = love.graphics.getFont()
love.graphics.print(title, x + (w-f:getWidth(title))/2, y + (h-f:getHeight(title))/2)
end
Code is here: https://github.com/vrld/Quickie.
Attachments
quickie.love
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
ncarlson
Prole
Posts: 35
Joined: Wed Jul 20, 2011 4:00 pm

### Re: Quickie [was: Immediate Mode Gui]

Awesome stuff.

I whipped up an example yesterday. I extended the library with a hackish grid/table arranger. (Press "g" to see the grid outline.)
title.png (7.24 KiB) Viewed 15300 times
effect-controls.png (10.1 KiB) Viewed 15300 times
A newish (0.8.x) build of Love is required for the attached .love file.
Attachments
quickie-example.love
0.8.0
Last edited by ncarlson on Thu Feb 09, 2012 4:31 pm, edited 1 time in total.
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Contact:

### Re: Quickie [was: Immediate Mode Gui]

I'm liking this project more and more every time I see it.

Recently I have been working on a small project which would have benefited from a "simple button drawing" function.

I liked what you did on the init.lua file:

Code: Select all

local BASE = (...) .. '.'
It is clever and elegant. But also a bit brittle. The code will stop working if someone requires the lib with require 'quickie.init' (small chance, but there is some).

In other files you have been using the most common "remove the filename from the path given by require approach":

Code: Select all

local core = require((...):match("^(.+)%.[^%.]+") .. '.core')
This is slightly more verbose than necessary. The following pattern does the same and it's shorter:

Code: Select all

local core = require((...):match("(.-)[^%.]+\$") .. '.core')
I always thought that you had to use the first element of ... to get the path - ({...})[1] . I'm a bit surprised that it works without it.
EDIT: Now I understand why. Clever.

EDIT2: What are save_pack and save_unpack doing in core.lua? I don't quite get it.
ncarlson wrote:Awesome stuff.
I whipped up an example yesterday. I extended the library with a hackish grid/table arranger. (Press "g" to see the grid outline.)
Your example gave me the following error:

Code: Select all

main.lua: 35 attempt to call field 'getMode' (a nil value)
I'm using 0.7.2 . Is your code only valid for 0.8.x?
When I write def I mean function.

### Who is online

Users browsing this forum: Google [Bot] and 25 guests