This is pretty old now, but even so I doubt very many people here have seen it.
http://www.mollyrocket.com/forums/viewtopic.php?t=134&start=0&sid=0517c6f755123b9ffab5fd8165b70afeDefinitely worth viewing the video, even if you're on 56k. The idea definitely has its advantages for stuff like editors and in-game GUIs and toolsets.
Hehe, he mentiones Sean Barret at the end. I know him, I used to work right across the hall from him when Irrational Games was in a room at the Looking Glass offices.
When my boss told him that he'd hired me, Sean reportedly said "You hired HIM?", because I used to get into heated discussions on a usenet game programming forum back in the day , that he apparently also frequented. I guess I must have had some arguments with him that I don't recall. :-)
Anyway, this immediatel mode GUI thing I can sum up pretty simply:
Each frame you call DoButton, with perhaps a flag to define some property of the button, and whatever text is on the button.
Like so:
If DoButton(16, 16, "Okay")
The function DoButton then draws a button at 16,16 that says "Okay" on it, and it also checks to see if the mouse is over the button, and if it is, whether the left mouse button is down. If it is down, the button is set to active. And if the button is active, and the left mouse button is up, then the function returns true.
That's all there is to it. If your if statement above returns true, then the button that was just drawn by the function call was clicked, and you can perform an action right there. There's no button id to keep track of.
Now that seems simple enough, but his presentation was pretty confusing and some things aren't clear.
For example, I think he intends for you to handle text boxes by having the button display your text data, rather than having the button store the text data and you query it.
Ie: Instead of doing something like:
PlayerName$ = TextboxText$(MY_TEXTBOX)
You would code the PlayerName$ variable into the textbox code, and have it write directly to that, or perhaps pass a pointer to PlayerName$ to a generic textbox function at the time you want to draw it like the button above. In C this might be like so:
If DoTextBox(16, 16, &PlayerName)
So you pass the address of PlayerName to the textbox, and the textbox writes any new data to that address.
But how would you do radio buttons, if one button cannot be aware of the others because none of them really exist except in the time their function is active? I guess you could maybe define some groups, and have one selectable button slot in each group and then stick that button's function pointer (which you can't do in blitz, but that's what he suggested as an identifier) into that slot, and then a button could check to see if it should draw itself with a selection outline by checking to see if the number in that slow is the same as itself. Which is the same sort of thing you need to do to dtermine if a button is selected normally I guess, or whether it is active. The trick in Blitz would be coming up with a globally unique identifier for each button.
Hm... come to think of it, you couldn't use the function pointer even if you had it if not every button had a unique function related to it. So I guess if every button has to have a unique function either way, then you might as well stick a constant identifier value in the function at the same time. But this seems like kind of a crappy way to do things. It might be better to have the one button function for a standard button, but pass an identifier to it as one of the parameters. So you might go If DoButton(MENU_OPTIONS_OKAY, 16, 16, "Okay"). That would require you to create a list of constants each with a unique value. But that would not make the code too much more of a pain to write I think, and would still avoid the complexity of worrying about making sure buttons get deleted.
There's another problem though. I have a system for animating sprites. You pass the sprite's identifier to the system, and it automatically animates it and tells you when the animation is done. I'm not sure you could easily implement something like this with this sort of system. Also, my BOB system works on the premise of creating bobs and then moving them about and then freeing them later. I guess this is retained mode in style. In order to make that work with this sort of system, one would need to create and destory these BOBS every frame if one wanted to keep them around only long enough to draw once.
When he says that he can use this in 3D too, I am also skeptical, because of how my BOB system works. The way my BOB system works is a lot like how a 3d card works. You don't want to recreate your meshes every frame. You want to keep them on the 3D card. If you do an immediate mode draw like this, where you don't save any data about what the buttons look like, or where they are drawn, would that work well with today's 3D cards which would rather you not constantly update the meshes on them and create new ones? I guess if one's interface is relatively simple then maybe it's not a problem, but it is something to think about.
His presentation made me think anyway... Pasing pointers to textboxes so they can simply update the text you intend to access is an interesting idea. Of course on the other side of the coin, you could simply store your data in the textbox and not have a second location, so either way it's only stored in one place. Hm...
Okay, so it seems to me that all he is doing is moving backwards. The claim seems to be that OOP is bad for GUIs because you have a ton of state information stored for each GUI component and that this state should be coming from the program state instead of the GUI component state. So instead of having a button that knows it's text is "Hello" you have some program variable containing "Hello" and that is passed into the DoButton() function. What he is missing is that you have exactly the same thing going on with objects and it seems a lot cleaner to me. A set of funcitons (methods) that act on a type and type instances keep only the state information they need.
Well isn't that the same thing only forcing you to keep a huge amount of global data? He says the DoButton() function takes an identifier for the button to deal with, that is the point of the Object handle in OOP. So he has basically decided to take a class and rip it all apart putting some code in the UI manager some code in the program state and some code in the event loop.
The upside to this kind of thing is that you get rid of the need for an event system. However this is just as easily accomplished with OOP. iGlass is a perfect example of this. I have my widget objects such as buttons, and instead of having an actual event queue I just call widget.Clicked() to find out if the widget was clicked.
Maybe I don't get it, but this all sounds like someone that wants to code in C instead of C++ for some reason.
one button cannot be aware of the others because none of them really exist except in the time their function is active?
I've only glanced at this stuff but that was my first question, also. In the GUI code I've just been doing, some buttons are inactive (greyed out) depending on other button states.
Basicly, what he is saying is this: A lot of GUI code is way too complicated, and so "Keep It Simple Stupid". I have looked at GUI libraries that were nightmares to use, and so I definitly empathise. For example, not only do you create a button class, you create a layout type class, pass that to a container class, add your button classes, then pass that into a larger parent class... bleh.
However, I don't see why you cant just have a very simple objects.
myButton = new Button
myButton.create("Hello",10,10,active,soundeffect)
while
if myButton.clicked()
Do your stuff here
end if
end while
@Rex, exactly how my stuff works ingame.
And mine, except I can't use methods as I'm using B3D.
Also, if his buttons only trigger an event after releasing the mouse button, what about other button functionality. My GUI has regular buttons (that trigger after mouse release) but also toggle buttons and buttons that trigger immediately and auto-repeat (scrollbar/spinner buttons, etc.).
The point isn't how buttons trigger the 'I got clicked' state, it's how the buttons get rendered and used in the main body of your program.
If you want your button to register a click as soon as MouseDown happens, then do it. I don't know what you're saying about toggles and spinner buttons?
Everything you're doing to draw your widgets remains the same, they just get called directly from your main code. Your toggle button code doesn't store its state (on or off), the main body of your code is responsible.
This makes sense. If the UI library stores the button states and edit-box data then your program has to say "gee, thanks for handling all this edit-box stuff for me, but, errr, what's in the edit box please?". Rather than "mystring$=EditBox(x,y,z)" where EditBox is the UI library function which renders the edit-box.
Wrap that all up in with the Hot / Active logic and you're well away.
"and you're well away."
Don't you mean well on your way? Or is this some more of that funny british speak? :-)
Or is this some more of that funny british speak? :-)
That's English. Just like the name of the language ;)
Interesting idea. I'm playing around with this now. Thanks for bringing it to my attention.