A gui

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

A gui

Post by Nixola »

Hi, as stated in "What are you working on?" I have been creating a (very) simple gui in these days, mostly to improve my OOP skills. Here is a .love file with a demo.
It has 6 types of objects now, labels (quite useless), buttons, sliders, checkboxes, textlines and radio buttons. It works like this:

Code: Select all

gui = require 'gui' -- or gui = love.filesystem.load('gui.lua')(), for multiple GUIs
--in love.load
label = gui:newLabel(x, y, text, color, font_size) --color is just a table {r, g, b[, a]}
button =gui:newButton(x, y, function, label, width, height, padding, color, font_size)
checkbox = gui:newCheckbox(x, y, value, label, width, height, padding, color, font_size)
slider = gui:newSlider(x, y, min, max, value, vert, width, height, slider, color)
textline = gui:newTextLine(x, y, enter, label, width, size, padding, color)
slider2d = gui:newSlider2d(x, y, Xmin, Xmax, Xvalue, Ymin, Ymax, Yvalue, sliderX, sliderY, w, h, slider, color, border)
radiobuttons = gui:newRadioButton(checkboxes)

--in love.update
gui:update(dt)

--in love.draw
gui:draw()

--in love.mousepressed
gui:mousepressed(x, y, b)

--in love.keypressed
gui:keypressed(k, u)
Label's arguments: they don't need an explanation, I think... Anyway, x and y are its x and y coordinates, text is its text, color is its color and font_size is its size

Button's arguments:
function is a function that is run everytime you click on the button
width and height are the button's width and height and can be omitted, in which case they're set automatically
padding is the space between the label and the borders (2 by default)
color is this table: {border = {r, g, b[, a]}, center = {r, g, b[, a]}, down = {r, g, b[, a]}, up = {r, g, b[, a]}, label = {r, g, b[, a]}} where border is the button's border color, center is the initial button's center color, down is the color the button becomes while left-clicked, up is the color the button becomes while not left-clicked, label is the button's label color

Checkbox:
value is a boolean and is the checkbox initial value (wether it's 'filled' or not, false by default)
label is a text that is printed at (checkbox.x + checkbox.width + checkbox.padding), (checkbox.y + checkbox.padding)
width and height are the checkbox border width and height
padding is the space between the checkbox border and its "center" (the rectangle that appears if the checkbox is "true")
color is a table {border = {r, g, b[, a]}, check (center) = {r, g, b[, a]}, label = {r, g, b[, a]}}

Slider: --x, y, min, max, value, width, height, slider, color
min is the minimum slider's value
max is the maximum slider's value
value is the initial slider's value (it's (min+max)/2 by default)
vert is a boolean, it indicates wether the slider is vertical or not. Note that width is still the actual width, so you have to make it taller yourself
width is the slider's width, while height is its height (3 by default)
slider is a table that defines the size of the rectangle that indicates the value ({width = 8, height = 3} by default)
color is the slider's color {line = {r, g, b[, a]}, slider = {r, g, b[, a]}}

Textline:
x and y are its coordinates;
enter is a function that is run everytime you press 'enter' while that textline is focused
label is the initial text in the textline
width is the textline's width, is set automatically depending on label
size is its font size
padding is the space between its borders and the text
color is a table {border = {r, g, b[, a]}, center = {r, g, b[, a]}, label = {r, g, b[, a]}}

2d Sliders;
x and y are the usual coordinates;
Xmin, Xmax and Xvalue are the minimum, maximum and initial value on the X axis;
Ymin, Ymax and Yvalue are the same values as above, just on the Y axis;
sliderX is optional, it's the slider bound to the X axis of the 2dslider;
sliderY, as above, is optional, it's the sloder bound to the Y axis of the 2dslider;
What do these two lines mean? Well, if you just click and drag the mouse inside the 2dslider's square but you only want to move one axis, it's quite difficult; these two sliders are two one-dimensional slider that should be positioned near the 2d one (but since you pass to the function a custom slider, you can do what you want). When you change the 2d slider, these two simple sliders change accordingly; if you change one of these two, only the "according" axis of the 2d slider changes. For best results, sliderX should have the same width of the 2d slider and it should be adjacent to it, while its min, max and value should be equal to 2dSlider's X axis ones; sliderY should be a vertical slider, with the same height ah the 2d slider, it should be adjacent to it, min, max and value should be 2dSlider's Ymin, Ymax and Yvalue.
w and h are simply the 2dSlider's width and height;
slider is a table: {width = (width of the vertical line that represents the X axis), height = (width of the horizontal line that represents the Y axis)};
color is another table: {bg = (table containing 2dSlider's background color, {r, g, b[, alpha]}), border = (table containing 2dSlider's border color), lines = (table containing the lines' color)}
border is a number, it's the width of the border around the slider. 0 to disable the border.

Radio buttons:
checkboxes is a table containing one or more checkboxes that will be turned into a group of radio buttons, will have their square become a circle with radius = (width+height)/4 and their clicked method will be overwritten.

To delete an object (it will be deleted at the next gui.update end):

Code: Select all

object:delete()
To set a custom object draw/click/update function:

Code: Select all

object.update = function(self, b, x, y) --the arguments are b == the mouse button hold (l, r, m, wu, wd, x1, x2 - in this order, if both r and x1 (example) are hold only r will be used)
object.draw = function(self)
object.clicked = function(self, b, x, y)
To reset a gui simply call gui:erase() or gui.load()

I surely forgot something, I hope I remember it
Any comment about my code?

EDIT: Added vertical sliders, 2d ones are planned, and added a lot of object:set methods! List:
  • Checkboxes:

    Code: Select all

    checkbox:setX(x)
    checkbox:setY(y)
    checkbox:setPosition(x, y)
    checkbox:setWidth(width)
    checkbox:setHeight(height)
    checkbox:setDimension(width, height)
    checkbox:setValue(boolean)
    checkbox:setPadding(padding)
    checkbox:setColor(color)
    checkbox:setLabel(label)
    checkbox:setTextSize(size)
  • Labels:

    Code: Select all

    label:setX(x)
    label:setY(y)
    label:setPosition(x, y)
    label:setColor(color)
    label:setSize(size)
    label:setLabel(text)
  • Buttons:

    Code: Select all

    button:setX(x)
    button:setY(y)
    button:setPosition(x, y)
    button:setWidth(width)
    button:setHeight(height)
    button:setDimension(width, height)
    button:setClickedFunc(function)
    button:setPadding(padding)
    button:setColor(color)
    button:setLabel(text)
    button:setTextSize(size)
  • Sliders:

    Code: Select all

    slider:setX(x)
    slider:setY(y)
    slider:setPosition(x, y)
    slider:setWidth(width)
    slider:setHeight(height)
    slider:setDimension(width, height)
    slider:setSliderWidth(width)
    slider:setSliderHeight(height)
    slider:setSliderDimension(width, height)
    slider:setMin(min)
    slider:setValue(value)
    slider:setMax(max)
    slider:setColor(color)
  • Textlines:

    Code: Select all

    textline:setX(x)
    textline:setY(y)
    textline:setPosition(x, y)
    textline:setWidth(width)
    textline:setHeight(height)
    textline:setDimension(width, height)
    textline:setTextSize(size)
    textline:setColor(color)
    textline:setText(text)
    textline:setEnterFunc(function)
    
  • 2D Sliders:

    Code: Select all

    slider2d:setX(self, x)
    slider2d:setY(self, y)
    slider2d:setPosition(self, x, y)
    slider2d:setWidth(self, w)
    slider2d:setHeight(self, h)
    slider2d:setDimension(self, w, h)
    slider2d:setXValue(self, v)
    slider2d:setYValue(self, v)
    slider2d:setXMin(self, m)
    slider2d:setYMin(self, m)
    slider2d:setXMax(self, m)
    slider2d:setYMax(self, m)
    slider2d:setColor(self, c)
    slider2d:setSliderWidth(self, sw)
    slider2d:setSliderHeight(self, sh)
    slider2d:setSliderDimenion(self, sw, sh)
  • Radio buttons:
    radiogroup:add(checks)
NOTE: Every "set" method has its "get" counterpart, like somevar = slider2d:getColor()!
Just call one of these methods on an object to change a parameter. If you aren't planning to use them or to delete objects you can add objects without "keeping track" of them:

Code: Select all

--I won't have to modify or delete this
gui:addCheckbox(x, y, true, 'Wow!')

--I will modify or delete this
somevar = gui:addCheckbox(x, y, true, 'Wow!')
Attachments
Gui.RadioButtons.NoTextbox.love
(7.28 KiB) Downloaded 145 times
Last edited by Nixola on Wed Sep 19, 2012 9:29 pm, edited 10 times in total.
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: A gui

Post by Nixola »

...I forgot the .love :oops:
EDIT: And I managed to forget it again!
Attachments
gui alpha.love
(3.48 KiB) Downloaded 203 times
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: A gui

Post by Nixola »

Almost 100 views, almost 30 downloads, 2 days and some hours passed and 0 replies! A new World Record! ^^
Anyway, just added textlines. They're lines in which you can type text, and when you press Enter a custom function is run. Textboxes will come soon (tomorrow or tonight, depending on how much I have to do tonight), but without auto-scrolling and with word wrap.
EDIT: What? 19 new downloads? Were there so many people online?
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
Patalo
Prole
Posts: 41
Joined: Sun Apr 29, 2012 1:15 pm
Contact:

Re: A gui

Post by Patalo »

Looks cool!
I think that the slider is missing a callback function, or the ability to change the value by scrolling. It's a feature I look forward. not sure if it's good english :p
I'm not sure, but maybe it's the goal of gui.slider.clicked?

Also (but I think it's much more annoying to implement :D), I think it is missing a feedback to know which element has the focus (brighten the element, or something like that).

I don't think I'm able to judge the code, but it looks simple, which is always the best quality (that's often lost with OOP).

Since I'm thinking about a GUI system for my fractal visualisator, I'm following this with interest!
Current project : 3D fractal explorer DEFract ( viewtopic.php?t=9193)
Github : https://github.com/plule/ | Twitter : http://twitter.com/plule_
User avatar
SiENcE
Party member
Posts: 792
Joined: Thu Jul 24, 2008 2:25 pm
Location: Berlin/Germany
Contact:

Re: A gui

Post by SiENcE »

Hm. My biggest problem with love guis is, that they don't fit the graphical style of my games.

When you create a game, you create assets like buttons, textbox, tooltips aso. You only need a gui management system. The whole graphical representation is not needed.

I would need a blank container, where i can put my images in and define, if the image is a button, textbox or label aso.
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: A gui

Post by Nixola »

You can overwrite objects' draw method:

Code: Select all

object = gui:newObject(x, y, etc.) --This is a generic object, you can do this with every object that I have
object.draw = function(self)
--the rest of the function
end
Anyway, the gui has a focus system, which applies only for textLines (and textBoxes soon) though, you can see the difference 'cause the cursor blinks in the focused textLine.
Sliders automatically change their value, in my demo the label under the slider simply prints sli[1].value, it's calculated automatically, gui.slider.update does that. gui.slider.clicked should not exist since it's not called anymore, I should have deleted it (yeah, I didn't... My bad)
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: A gui

Post by Nixola »

Textboxes added, without cursor drawing now, mainly because I'm a bit tired (didn't almost sleep tonight) and I can't think at a nice way to do it
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
josefnpat
Inner party member
Posts: 955
Joined: Wed Oct 05, 2011 1:36 am
Location: your basement
Contact:

Re: A gui

Post by josefnpat »

The biggest thing that bothers me is the slider. Good gui systems (windows, os x, gnome, etc) seem to allow the user to keep dragging the slider even when the mouse isn't over it. If the slider is horizontal (as it is in yours), then the slider is modified as long as the mouse button is down and it ignores the Y axis and just works with the X axis.
Missing Sentinel Software | Twitter

FORCIBLY IGNORED.
<leafo> when in doubt delete all of your code
<bartbes> git rm -r *
<bartbes> git commit -m "Fixed all bugs"
<bartbes> git push
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: A gui

Post by Nixola »

Thanks Josefnpat, updatet fixing that (Sliders are clickables again!)
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: A gui

Post by Roland_Yonaba »

Hi,
This is getting nicer.
Think about 2d sliders now.

But, your source is unreadable, to me... Use indentation. And i'd rather recommend to avoid the use of ";" to separates two instructions one the same line. Just return to a new line.If not, as this project goes on,it'll become difficult to maintain the code.

Another thing, using directly loadstring to parse a checkbox contents is unsecure. You are providing to the users a way to make your program crash easily. Use a protective call (pcall) an act upon the second argument returned.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 211 guests