for (vector <MItemMold>::iterator i = MenuList.begin(); i != MenuList.end(); ++i)
{
for (vector<MItemMold>::iterator a = MenuList.begin(); a != MenuList.end(); ++a)
{
if(( i->Parent.compare(a->Name) == 0 ) // If the button 'a' is the parent of 'i'
&&(a->On)) // and the parent has the 'ON' state
{i->Show = true; i->Awake = true;} // mark 'i' as visible and awake
if(( i->Parent.compare(a->Name) == 0 ) //If the button 'a' is the parent of 'i'
&&(!a->On)) // and if the parent has an 'OFF' state
{i->Show = false; i->Awake = false; i->On = false;}
}
if ((i->CursorOnTop(Mouse))&&(Mouse.LBDown)&&(!i->Blocked)) // When the mouse is on top of the control and the mouse button is down
{ i->On = true; // set button state to 'ON'
for (vector<MItemMold>::iterator a = MenuList.begin(); a != MenuList.end(); ++a)
{
if ((i->Name.compare(a->Name) != 0) // If the control in the list is not the current control, that is the control that had just been set to 'ON' &&
(i->Parent.compare(a->Name)!= 0)) // and the control in the list is not parent for 'i'
a->On = false; // set 'a' to 'OFF'
}
// and so on
}
🔒 Locked
Better GUI algorithm
Advertisement
Original Post
I'm at my second attempt at a GUI Manager for a game. The first one did the job but I'm not sure it had the best design. I'll focus on the main issue: how to make the controls get/loose focus. In the first GUI I had this: - make the control class have two properties: Name and Parent, both string variables. - place all controls in a container (i.e STD::vector) - make two iteration loops one inside another, and run them at each mouse/keyboard event to update the controls state. Compare the controls 'Parent' and 'Name' proprieties to set control properties/state. Here's a snipet from the original algorithm: What would be a better system for a GUI manager? One thing I don't like with this algorithm is that sometimes I have up to 70 controls in the container and it takes quite some time to go through the loops. [Edited by - Calin on April 14, 2006 3:57:36 PM]
Quote:
Original post by Calin
No, both children and parents are in the same list.
Consider letting the parent know of its children. It can make things more efficient.
For example, if you replaced the public varible "on" with void setOff() and bool isOn():
class Thing{public: void setOn() { on = true; foreach( children ) { child.setShow(true); child.setAwake(true); } } void setOff() { on = false; foreach( children ) { child.setShow(false); child.setAwake(false); child.setOff(); } } bool isOn() { return on; }private: bool on; (vector / list) <Thing*> children;};How many loops are you avoiding that way?
It's been a while since I touched my gui code, but in my gui, the only things in the list where the top most parents (parents being a form or a window). A parent then contains children. When the gui system checks input and creates a message, it then only has to pass the message to the parents (with first dibs being given to the control that's in focus), and the parent only has to pass to its children. So in a setup where you have 70 controls total, but only a few per page this works well. Since the system is hierarchal by nature, you can extend this another step. If you have a bunch of controls on one page, you can group them (with a group control), thus if the message doesn't happen with in the boundary of the group, it won't reach any of the children. Finally, at the end of it all, when a control does get a message, it alerts the gui manager that it should receive focus. The manager then unfocuses the old control, and focuses the new one. Also, consider that you do not have to pass every message to every control. Generally, keyboard input and mouse scrolling would only go to the item in focus, so the only messages you need to pass are mouse related.
You should really store your parent nodes in the lists only.
For each input, you check which parent is visible at all, then call a recursive function that passes the input to the control in focus.
if you move and leave the control that held focus(e.g.: you want to switch focus to another control), you do the same recursive iteration to the leave nodes until each child node returns false on your inpunt/is a leave, so the focus is on the last visited node.
this runs in O(logn) where n = maximum # of nested nodes.
One thing you could do is move the top parent of your node with focus to the top of the list of visible gui branches in order to check this one first, so you can overlap controls(e.g.:drop down menus) without loosing focus all the time
For each input, you check which parent is visible at all, then call a recursive function that passes the input to the control in focus.
if you move and leave the control that held focus(e.g.: you want to switch focus to another control), you do the same recursive iteration to the leave nodes until each child node returns false on your inpunt/is a leave, so the focus is on the last visited node.
this runs in O(logn) where n = maximum # of nested nodes.
One thing you could do is move the top parent of your node with focus to the top of the list of visible gui branches in order to check this one first, so you can overlap controls(e.g.:drop down menus) without loosing focus all the time
One thing that I noticed is that you're using string comparisons. String comparisons in general are slow. Consider using a std::map instead of vector; using either an integer or a string key value.
If you don't want to do that, you can at least cut down by storing the value in a temporary variable:
I recommend storing the comparison since you check it about 5 times per loop. But I recommend switching to my first suggestion above all.
I also recommend what the above posters said, allowing the parent to know of its children will help.
Also, if you separate the child and parent, you can send the message to the parent, who can then determine if its even possible for any of its children to recieve the message (For example, if the cursor is outside of the parent widget, none of its children should be able to recieve the message and thus won't spend time running through the loop.)
If you don't want to do that, you can at least cut down by storing the value in a temporary variable:
bool bParentOf = (i->Parent.compare(a->Name) == 0);if(bParentOf && a->On)/**/if(bParentOf && !a->On)/**/OR use an else statementif((i->Parent.compare(a->Name) == 0) && a->On)/**/else if((i->Parent.compare(a->Name) == 0) && !a->On)/**/I recommend storing the comparison since you check it about 5 times per loop. But I recommend switching to my first suggestion above all.
I also recommend what the above posters said, allowing the parent to know of its children will help.
Also, if you separate the child and parent, you can send the message to the parent, who can then determine if its even possible for any of its children to recieve the message (For example, if the cursor is outside of the parent widget, none of its children should be able to recieve the message and thus won't spend time running through the loop.)
Thanks for all the input so far.
I'll go with a composite design pattern as most of you suggested. I'll make a 'baseControl' class that will have a list for children storage.
Programmer16:
I should have mentioned this. I'm building my second game with C# so the GUI manager will be constructed with C# too; Thanks for your other suggestions though.
I'll go with a composite design pattern as most of you suggested. I'll make a 'baseControl' class that will have a
Programmer16:
Quote:
One thing that I noticed is that you're using string comparisons. String comparisons in general are slow. Consider using a std::map instead of vector; using either an integer or a string key value.
I should have mentioned this. I'm building my second game with C# so the GUI manager will be constructed with C# too; Thanks for your other suggestions though.
Quote:
Original post by Programmer16
One thing that I noticed is that you're using string comparisons. String comparisons in general are slow.
Thats is not exactly true.
Consider a string being a list with lexicographic ordering
If you have K different symbols you would need
Vn=((K^2)-K)/(K^2)+(K/(K^2))(1+Vn-1)
comparsions in the average case,
which results in
K/(K-1) comparsions for n->infinite
for binary strings you need only 2 comparsions in the average case.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement