Jump to content
  • entries
    943
  • comments
    5,899
  • views
    924,348

lgui


Josh

2,812 views

 Share

I've never considered myself a fan of writing GUI code, but now that I have a small job I need to get it done for, I'm actually having a lot of fun with it. I've been tinkering around with Lua GUI code for two days, and I came up with a really neat system after lots of trial and error.

 

Controls

  • A "control" is the name for a button, label, or other widget. A control is a Lua table.
  • The programmer creates the controls they want and then inputs mouse coordinates and the left mouse button state in the Update() function.
  • There are only three real events that occur; mouse movement, mouse button down, and mouse button up.
  • When the mouse is pressed, the system has a fast hierarchical search to find the selected control, and this control is made active.
  • Since the programmer supplies the mouse coordinates and button state, the GUI could be displayed on a 3D surface and interacted with in the game, like in Doom 3.

 

Frames

  • Frames are a lua table with a drawing method. The simplest frame just draws a rectangle on the screen. An image frame draws an image within the specified coordinates. A more sophisticated frame uses nine images to draw image-based edges around a rectangle of any size.
  • Controls use frames to draw different parts of the control, instead of using a lot of hard-coded GUI drawing or images.
  • You can replace a control's frame easily in Lua:
    button.frame=CreateImageFrame(image)


 

Methods

There are some predefined methods you can add to a control. Right now I have the following:

  • CursorDown
  • CursorUp
  • CursorMove
  • Activate
  • Deactivate
  • HideUpdate
  • ShowUpdate

 

Lua makes it really easy to expand a basic control to look or act differently. You can just overwrite a function, and you have your new control. For example:

function CreateMyButton(text,x,y,width,height,group,style)

local button=CreateButton(text,x,y,width,height,group,style)

function button:CursorMove()
	--Your code here
end

function button:Draw()
	--Your own drawing code goes here
end

return button
end

 Share

6 Comments


Recommended Comments

aye, I have recently been playing with your previous release of the lua gui. So far, it works pretty decent. Also noticed the frame.lua script inside the recent update and have tried to use it to no avail. Look forward to seeing more information on this.

Link to comment

I love gui programming! Sounds like you are missing key presses though. Also events like GotFocus and LostFocus can help with things. It sounds like you have just scratched the surface. Things get interesting when you let into parent/child relationships that controls can have. For example a control could be a child of a window. Or in the case of a combo box it has a textbox, button, and list box control that make it up. So basically you are making a control based on 3 other controls. GUI programming is really fun, but it can also get really involved.

 

I think lua would be really easy for users to bind to the events because you can easily store functions with any signature as the same variable, where in C++ it gets a little trickier with that but still doable.

 

I didn't see it mentioned but I would assume I define the event handler to a control? Something like:

 

function mybutton_onClick(owner, args)
  -- this gets fired when mybutton is clicked
end

mybutton = button.create()
mybutton.onClick = mybutton_onClick

Link to comment

Yes, there is a callback function for events.

 

Or in the case of a combo box it has a textbox, button, and list box control that make it up. So basically you are making a control based on 3 other controls. GUI programming is really fun, but it can also get really involved.

Droplists (my version of comboboxes) are done. I had to add a "Move to back" function to move the list to the back of the queue, so it gets rendered last, on top of underlying controls. The code finds the active control in reverse of drawing order, so the top-most rendered item is selected first. One common programming problem is when you have drop lists that appears in front of buttons, and the GUI pushes an underlying button when you click the list. Well, I think that issue has been solved in a good way.

 

I am paying more attention to the underlying logic and functionality than to the graphics of it. I figure the graphics are easily replaceable, but the functionality needs to be very solid. The whole hierarchy and draw ordering stuff is a lot harder to write than simple behavior, so that is what I am focusing on. If the foundation is solid, then people can easily add their own items without running into problems.

Link to comment

Just to put this out there, use it or not, I find it handy to be able to create event calling chains. So instead of just storing 1 event callback method you store a list (table) of them. Then when the onClick event is to fire, you loop through the list and call them in the order they were added. In C++ I do this so my control class can register for the event first and do something based on it before it goes to the user defined event handler.

 

For example, in my Textbox class I have them register the onGotFocus and onLostFocus events that it exposes in the constructor. That way whenever the main gui manager fires these events, my Textbox control event functions get called first, which allows me to do certain things a textbox should do. Like when a textbox loses focus I have that instance stop showing the caret. When a textbox receives focus I have the textbox say it needs to start showing the caret. That way my gui manager that is looking for events doesn't have to worry about that kind of stuff. It just looks for the raw events that every control would have, and fires them. Then the controls are responsible for doing things that pertain to them and not some outside class. Then since these events are stored in a list, it'll then continue to call the function that the user defined for it's event handler.

 

Another cool effect of this is that a user could define their click event handler for a button and do something inside that click event, but they could also define a different function that will fire also when the button is clicked. This is nice in C++ because the function can be from any class and it'll get called. So it allows for nice interclass communication via events.

Link to comment

Not sure if the Lua UI you are talking about is the stuff that has been there for a while and has the dark blue gradient theme.

 

You can all shoot me for that. I coded it for Josh as some contract work, and the more I look back on it, the more I see how I could have done better.

 

I feel like I let everyone, especially Josh, down with it :D

Link to comment

Tyler, I learned a lot from your initial design. I promised someone (can't talk about it) I would implement a simple GUI for them, and they wanted very simple text-based buttons. This got me thinking about the functionality more than the graphical look of the GUI. Your technique of using a single function for drawing the beveled boxes was where my "frames" idea came from. Before that, I was just hard-coding the vector-based drawing code for every single control! :D

 

Your initial work was valuable because it revealed the different issues we would encounter. There's no way we could have predicted all those interactions without going out there and trying to implement all kinds of controls, and seeing what the issues were once we started actually using it. For example, the combo box problems you ran into made it clear that draw and event ordering needed to be built in at the lowest level. As a result, I found I could get desired behavior by moving controls to the end of the parent's list when they were activated, so they were rendered last. I also found that by reversing their order for selection, I could always select the topmost item.

 

I don't think any of us could really have predicted all of that from the start, but you did the research we needed. Now we know, and a lot of your existing code can be copied and pasted into this system, too. ;)

Link to comment
Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...