Quickie [was: Immediate Mode Gui]

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Quickie [was: Immediate Mode Gui]

Post by vrld »

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
imgui.jpg (10.18 KiB) Viewed 15517 times
Edit: Making the 2D slider do something.
Attachments
imgui.love
(4.86 KiB) Downloaded 1724 times
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

Post by coffee »

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

Re: Immediate Mode Gui

Post by kikito »

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

Post by coffee »

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! :)
http://www.youtube.com/watch?v=75V4ClJZME4
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Immediate Mode Gui

Post by kikito »

coffee wrote:But much earlier than some trekie give theremin treatment Delia Derbishire already themed original Dr.Who masterpiece! :)
http://www.youtube.com/watch?v=75V4ClJZME4
That's no theremin :P
When I write def I mean function.
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: Immediate Mode Gui

Post by coffee »

kikito wrote:
coffee wrote:But much earlier than some trekie give theremin treatment Delia Derbishire already themed original Dr.Who masterpiece! :)
http://www.youtube.com/watch?v=75V4ClJZME4
That's no theremin :P
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.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Immediate Mode Gui

Post by vrld »

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
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Immediate Mode Gui

Post by vrld »

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'

function love.load()
    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

    -- add more widgets here
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.mouse.updateState(id, x,y,w,h) updates the state for this widget.
	core.mouse.updateState(id, x,y,w,h)

	-- 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
	       (core.keyboard.key == 'return' and core.hasKeyFocus(id))
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
(10.09 KiB) Downloaded 485 times
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

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

Re: Quickie [was: Immediate Mode Gui]

Post by ncarlson »

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
title.png (7.24 KiB) Viewed 15241 times
effect-controls.png
effect-controls.png (10.1 KiB) Viewed 15241 times
A newish (0.8.x) build of Love is required for the attached .love file.
Attachments
quickie-example.love
0.8.0
(91.95 KiB) Downloaded 808 times
Last edited by ncarlson on Thu Feb 09, 2012 4:31 pm, edited 1 time in total.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Quickie [was: Immediate Mode Gui]

Post by kikito »

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.

A couple comments;

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.
Post Reply

Who is online

Users browsing this forum: Majestic-12 [Bot] and 12 guests