Jump to content
  • entries
    945
  • comments
    5,899
  • views
    930,094

GUI Design


Josh

4,586 views

 Share

Just thinking out loud here, and I am considering designing the GUI like this:

 

The GUI class handles events, window clipping, widget layout, etc. Rather than having a bunch of C++ classes that extend a base Widget class, there would just be the Widget class with a Lua script attached to it. The Lua script would handle all events and drawing, so it would determine what kind of widget the C++ object is. For example, here's a script for a simple button:

 

function Script:Draw(x,y,width,height)
   if self.pointerhovered==true then
       self.widget.window:SetColor(self.background.r*1.2,self.background.g*1.2,self.background.b*1.2)
   else    
       self.widget.window:SetColor(self.background.r,self.background.g,self.background.b)
   end
   self.widget.window:DrawRect(self.x,self.y,self.width,self.height)
   self.widget.window:SetColor(self.background.r,self.background.g,self.background.b)
   self.widget.window:DrawText(self.text,self.x,self.y,self.width,self.height,Text.Center+Text.VCenter)
end

function Script:MouseEnter(x,y)
   self.pointerhovered=true
   self:Draw(self.x,self.y,self.width,self.height)
end

function Script:MouseLeave(x,y)
   self.pointerhovered=false
   self:Draw(self.x,self.y,self.width,self.height)
end

function Script:MouseUp(x,y)
   if self.pointerhovered==true then
       self.widget.gui:EmitEvent(Widget.ActionEvent)
   end
   self.buttonpressed=false
end

function Script:MouseDown(x,y)
   if self.pointerhovered==true then
       self.buttonpressed=true
   end
end

 

The upside:

  • It's infinitely extensible and can be used to make literally any kind of widget.

 

The downside:

  • The script needs to contains the logic and the drawing, so although skinning is possible, it's not as simple as choosing a couple of colors.
  • Complexity in the interaction between C++ and Lua widget logic.
  • Debugging editor scripts as they are running = not fun. If people modify the editor GUI scripts it could introduce crashes.
  • Coding advanced widgets like a treeview will be quite complex in Lua.

 

Anyways, I'm just experimenting with it for now.

 

movie_idiocracy01.jpg

  • Upvote 3
 Share

16 Comments


Recommended Comments

Does this make the GUI for Leadwerks Lua dependent then? It seems like this might be hard to make both C++ & Lua GUI extendable the same way.

 

When writing a system that others may use, or I may use later I always start with the experience I want to have working with it and work backwards from there. So in your example how would I make a button and register it's click event to do my game logic in? I don't want to draw the button I mean using the button LE will come with.

 

Love the pic. "Put this one in your mouth, this one in your ear, and this one in your butt" Best part of that movie!

Link to comment

GUI* gui = GUI::Create(window);
Widget* widget = Widget::Create(gui);
widget->SetShape(20,40,70,26);
widget->SetScript("Scripts/GUI/Button.lua");

 

Then if someone makes a set of scripts for some crazy RPG UI you can utilize that just as easily.

  • Upvote 3
Link to comment

This really look interesting... How about using LUA to create the widgets that would be represented as a new node type with input and output from the node editor?

 

Since the node editor is good for logic, It could really fill the gap, users could exchange scripts of GUI designs that could be easily used after with the node editor.

  • Upvote 1
Link to comment

That is a possibility. I think it is more interesting for an in-game GUI on a 3D surface, like a simple interface you control to open a door or something. The game's menu GUI will mostly be handling quality settings, etc. so the flowgraph isn't as useful there.

  • Upvote 1
Link to comment

Have you thought about doing something with callbacks? You could have both lua and c++ UI code. I wrote a simple program to prove the concept, the end result is you could write c++ UI like this:

 

Widget* Button = CreateWidget();
Button->Draw = std::bind(&MyDrawFunc);

void MyDrawFunc()
{
   std::cout << "MyDrawFunc" << std::endl;
}

 

Or with classes:

class MyButton
{
public:
   MyButton()
   {
       Widget* Button = CreateWidget();
       Button->Draw = std::bind(&MyButton::Draw, this);
   }

   void Draw()
   {
       std::cout << "MyButtonDraw" << std::endl;
   }
};

MyButton mybutton;

 

The for Lua you could do:

function LuaDrawFunc()
   print("LuaDrawFunc")
end

button = Widget.Create()
button:DrawCallback(LuaDrawFunc)

 

or with a table:

thing = {}

function thing:ThingDraw()
   print("ThingDraw!")
end

thing.button = Widget:Create()
thing.button:DrawCallback(thing.ThingDraw, thing)

Link to comment

C++ callbacks are definitely an option.

 

I've refactored the window class on Windows now, and it allows the creation of embedded subwindows parented to a window. So now I can create a window that uses OS commands to draw a GUI directly onto it, without a 3D context, and subwindows can be created within that window and have an OpenGL context created on them and rendered to.

 

I really like the idea of using a Lua script on widgets just like we do for entities because it makes things so incredibly flexible. I expect we'll have a core set of simple widget scripts, and then people can go crazy with them by modifying the drawing behavior, the widget's response to various events, or both.

 

However, it looks like simple "skinning" probably won't really be a thing, since the drawing commands are built into the script. Instead, you would modify the script to draw the way you want. Another layer of abstraction beyond that would probably be too complicated to be useful, since a skin can't account for every possible widget people will create. Maybe there will be a few modifiable values like foreground / background colors, but only really basic UIs are going to rely solely on that. Even the default Windows theme has lots of subtle variation in colors and shading.

 

This is definitely a very unique approach to GUI design, and after thinking about this issue for years I think I really like the idea.

Link to comment

Are you going to handle resolution independence for us? Without that there isn't much use of the system over the custom ones out there.

  • Upvote 3
Link to comment

Yeah, I have thought about that. I'm thinking a global GUI scaling factor can be used to multiply all coordinates maybe, or perhaps an option will exist to place things in percentage dimensions.

Link to comment

I took a page out of Aggrors and did anchoring and custom "units" for position and size of widgets and then a formula converts those units on the fly to the resolution. Percentages don't work right between aspect ratios when it comes to size from my experience. The hardest part about that is working in these units as it's hard to know where the values show up but that's why a wysiwyg gui editor would be ideal so those values don't mean much to the user as they just position and size widgets in the editor and then anchor them and now it'll look the same on any resolution.

Link to comment
or perhaps an option will exist to place things in percentage dimensions.

 

If I recall if you make a widget image width/height, say, 25% of the screen width in a 4:3 it might look fine, but then the user switches to a 16:9 resolution and it won't look right anymore. Pending that's what you meant in your above quote about percentages.

Link to comment

I know this is a year old, but I'm still interested.

I'm having an error thrown on any function call that follows Widget::Draw(). If I don't call draw, it only renders for a single frame when the mouse hovers.

Any ideas?

Link to comment
1 hour ago, St0nedas said:

I know this is a year old, but I'm still interested.

I'm having an error thrown on any function call that follows Widget::Draw(). If I don't call draw, it only renders for a single frame when the mouse hovers.

Any ideas?

I do not understand your question, or how it relates to a year-old development blog.  Can you post a working example in a new forum topic?

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