name uniqueness

Kali

26-02-2008 22:31:10

I noticed that every widget needs a unique name in the last svn version and wondered if this was a permanent change.

Personally I consider a major drawback. It would make it hard to have instances of basically the same window on screen. And in other windows I like to keep a persistent naming scheme.

I could resort to not naming a widget but then I would have to store a pointer for every widget I need the contents of later on, since I can no longer rely on name lookup.

If you ask me it would be sufficiënt that widget names are unique within their window or most local context it is a sign of bad design anyway if you have a need for global widget lookups.

kungfoomasta

27-02-2008 01:40:11

Its a permanent change. Because of the widget design and how composite widgets are created, the naming scheme should not change.

For example, say you create a window called "MyWindow". This window creates a Titlebar with the name of "MyWindow.TitleBar". The titlebar has a close button called "MyWindow.TitleBar.CloseButton". Now say you change the name of the window to "Window1". "MyWindow.TitleBar.CloseButton" is no longer a correct name. You could get around this by coding in a method to recursively update all component widget names when the base widget's name has changed, but its not very trivial.

What could be done in the future is moving the unique naming requirement from the GUIManager domain to the Sheet domain. That way you can have 2 windows with the same name, but they can't be on the same sheet.

If you have widgets that need to be updated a lot, wouldn't it be faster to store a pointer to them than doing a recursive look up? Depending on the number of widgets in the sheet, the order of which it was created, and whether or not its even connected to the parent/child heirarchy, you might find issues.

Kali

27-02-2008 21:18:18

Offcource it would be somewhat faster to store the pointer. But in my opinion, you would need mindbogling complex user interface totally incomprehendable for the human mind, before a simple lookup with a string as a search key will become any kind of performance issue. And even then you can probably still optimize your structure for string lookups.

On the other hand you lose a very convenient feature. Instead of letting the window or sheet keep track of individual windows or widgets, you now need to do so yourself aswell. You have to keep pointers to every widget you need to access. Pointers you will probably want to organise again in some way.
while in fact, QuickGUI allready has them neatly organised in a parent/child relationship. All you need to identify them by is their name and you can then easily navigate through the tree until you've found the right widget.

I feel quite strongly about this, would you accept patches in this direction ?

kungfoomasta

27-02-2008 22:32:22

Patches are welcome for this. Just remember that the getChildWidget function is recursive, so if you have duplicate named widgets it will return the first one it finds.

The only problem I can think of at the moment is the naming of Composite widgets, which use their parent widgets name as part of their own. These would need to update their name when their parent changes names. For example "ComboBox1.DropDownList" would need to be updated to "ResolutionTypeCombo.DropDownList", if you renamed the ComboBox widget from "ComboBox1" to "ResolutionTypeCombo".

I think the easiest way is to make the "setInstanceName" function virtual, so that I can override them in Composite style widgets, so they properly update their widget parts.

virtual Widget::setInstanceName(const std::string& name);
virtual Window::setInstanceName(const std::string& name);
virtual Console::setInstanceName(const std::string& name);
virtual ComboBox::setInstanceName(const std::string& name);
virtual List::setInstanceName(const std::string& name);
virtual HorizontalScrollBar::setInstanceName(const std::string& name);
etc.

Is it acceptable to enforce unique names of widgets per sheet, while allowing the ability to set widget names?

Kali

27-02-2008 23:08:34

Well the obvious solution to me seems that changing the name of a widget recursively changes (regenerates) the name of the composite widgets.

I'll add a non-recursive alternative for the getChildWidget to look for a widget at a specific level if it doesn't allready exist. Recursive lookups can be useful but are not always desireable.

Extending the recursive function to look for multiple children with a certain name or for Nth occurence of a widget seems more trouble than it's worth. In praktical usage situation, you look for a widget in a certain window/sheet/... where a name will most likely be unique by design.

The most flexible solution is to just make widget names unique for their immediate parent, not fixed at any level.

I'll have a go at it this weekend.

Kali

02-03-2008 12:08:38

Here is a path to use locally uniqe names instead of globally unique names.

From the top of my head, the only usage of quickgui that this patch will break is if you relied on the recursiveness of getChildWidgets. The recursive function is renamed to findChildWidgets for reasons explained bellow.

There was no functionality to rename a widget so there was no problem keeping the name of components consistent. A setInstanceName function is simply not present. But adding one would add no additional complexity than it would have with global names.

For some reason all testcode in the demo was commented out, I undid that aswell.

http://wina2.ugent.be/~karel/difffile

commit comments:

This patch removes the requirement of all widget names being unique within the entire QuickGUI system. Now al is required is that each widget's immeditate children have a different name, each sheet has a different name and each RadioButton in a RadioButtonGroup has a different name.

GUIManager

- Removed the global list of names from GUIManager together with the functions: isNameUnique, notifyNameFree, notifyNameUsed and all calls to it.
- Added generateSheetName to generate unique name for a sheet.
- changes createSheet functions to guarantee a locally unique sheet name.

Widget

- Added generateName to generate a unique name widget name.
- Added isNameUnique to see if a name is unique withing the current Widget.
- Used the new local isNameUnique and generateName to guarantee all children have a unique name.

- Changed getChildWidget to findChildWidget which searches recursively for a child
- Added getChildWidget which only looks for a child among it's children.

The getChildWidget functions are now more consistent as they all look for children non-recursively.

Panel

- Used the new local isNameUnique and generateName to guarantee all children have a unique name.

RadioButtonGroup

- Added code to createRadioButton to guarantee a locally unique name

Note: RadioButtonGroup is the the only structure where passing a non-unique name didn't result in an error but resulted in a generating a unique name. I've kept behaviour as is for now but this might not be what was intended.

QuickGUIDemo

- Added code to automatically check if generated names or given names truly are locally unique in all circumstances.

kungfoomasta

03-03-2008 17:59:17

The RadioButton throwing an exception was something I forgot to change, thanks for finding it.

It sounds like your changes are good, but I keep thinking about the removal of the recursive find. This forces people to have some kind of organization, right? For example in the demo I create a TextBox (lets say its named "TestTextBox" since I can't remember) and in the framelistener I get a handle to "TestTextBox" and set its text to the name of the widget the cursor is over. Without the recursive method I have to know who the parent of this textbox is, don't I? Obviously I created it so I would know, but it seems very inconvenient to query the sheet for a window, then query the window for panel, then query the panel for a textbox.

For me personally I store pointers to all widgets I access a lot, I just bring this up in hopes there is some kind of middle ground. As it is before the patch, I can get access to any widget I want using a string identifier and the Sheet its on.

Kali

03-03-2008 23:02:56

Mind, I have not removed the recursive function, why chose one when you can have both. I've simply renamed it to findChildWidget which better reflects what it does. getChildWidget(name) (which is probably what you were looking for in the first place and use most of the time) is faster as it doesn't need to dive into every child and is more consistent with getChildWidget(index) which also searches the immediate children.

Your scenario assumes you will only use strings to search for widgets. You will often use a mix of both. For example in my code I keep a pointers to my windows but use strings to search for widgets within those windows

Now that I think of it, you should probably even rename it to findWidget as it also returns itself if the name matches.

kungfoomasta

04-03-2008 00:17:59

It was late when I first read your post. :oops:

Thanks for clearing it up! findWidget sounds like a good name, I'll apply the change tonight or tomorrow. Thanks for your work on this. :)

kungfoomasta

18-04-2008 18:47:28

Kali,

I was thinking about setting widget names. Re-reading what you suggested up above, it seems like you would like to be able to do the following:


Window (name = myWindow)
Panel (name = myPanel)
Panel (name = myPanel)


Above is a Window that has a child Panel that has a child Panel. Both Panels have the same name, but are not siblings.

If I had to enforce unique names, what would you find acceptable? What do others think about naming? (I really want to enforce unique child widget names per Sheet, and also enforce unique names for Sheets)

The main motivation for enforcing unique names is to protect me from myself.. if by chance I forget I already have a button called "close button", when I do a recursive lookup to get the button I might get the wrong button, and it could cost me a lot of time figuring out the problem. (basically, it feels wrong allowing multiple look-up objects having the same look-up ID)

kungfoomasta

22-04-2008 22:13:50

Just to touch base on this one last time. I have to enforce name uniqueness on a Sheet wide level, it is a requirement of the serialization system. I'm using a modified version of the Script Parser by JohnJ, so you can think of Widget definitions like material definitions. (You can't have 2 materials with the same name) Fortunately I've wrapped this so that 2 different sheets can have widgets with the same name, and no problems will occur, as far as QuickGUI and ogre resources are concerned.

Kali

26-04-2008 16:51:33

Sorry for the late reply but I haven't been doing anything gui related lately so I haven't checked up on this that much.

Still I strongly disagree.

Is it so odd that if I have two windows on a sheet that I want both to have a button named "close".
And suppose I want to create two of the same window just with different data fields, like for example two health bars for two different enemies, is it really user friendly to force me to generate unique names for every element on those health bars. And even if I do, I still need to keep the names somewhere, so I still need to manage resources manually as you would have to do if you stored those elements you need to change by pointer.

For me enforcing unique names makes the menu's just about as useful as just having no names at all. And if you look at it from a user perspective, not from the perspective of the creator of your code, I'm sure you'll agree.

If there are specific issues with like serialization, I'm sure they can be resolved and I'm prepared to step in and take a look at them. I'm not familiar with JohnJ's code, but will look into it.

Edit: A google search wasn't particularly usefull, what is JohnJ's script parser and where does it come from ? Or better yet, commit what you have so I can take a look at it.

Zini

26-04-2008 17:05:48


Is it so odd that if I have two windows on a sheet that I want both to have a button named "close".


You could prefix the button's name with the window's name. Maybe with a special separator, that is not used in a regular name component, so you can split up the components easily, when you need to parse a widget's name.

Kali

26-04-2008 17:14:58

Off course I could but It introduces an extra step when creating a window and an extra step every time I would want to look up a widget.

And read especially my second example, this is not something rare havign multiple instances of the same window/subwindow happen a lot in any gui.

This problem is not critical. It just makes the system considerably less convenient to use.

Zini

27-04-2008 11:37:58

I see you point, though


This problem is not critical. It just makes the system considerably less convenient to use.


sounds a bit overstated. The amount of additional code you would need outside of QuickGUI would be minimal.

My prefix-idea could actually implemented directly in QuickGUI:

1. Add a flag to the create-Funktion, which when set automatically prefixes the name of the created widget with the name of the parent widget.

2. Replace the std::string type with a custom type, when handling widget names. This custom type should be have the same basic interface as std::string (regarding I/O, comparison and probably a few things more). But it should not store a single string, but a sequence of strings, which are concatenated, when making a std::string from the new class.
Furthermore it would need functions to access and manipulate the individual sub-strings.
Instead of calling widget->getInstanceName() you would then call
widget->getInstanceName().getLeaf() to access your "close".

Sounds like a lot of work and with all the changes currently happening, it might be a good idea to defer the implementation a bit (if kungfoomasta decides to do it at all). Actually I have a suitable string-replacement class in my current project. I think I could donate it to QuickGUI (though it would require some minor modifications first).

Kali

27-04-2008 13:34:07

Your system would work quite well but to be honest I don't see the point in mimicking this behavior when it is in fact easier to implement it for real.

You might not have noticed but my patch earlier removed much more code than it actually added, the name uniqueness was artificially enforced and I'm having difficulty understanding why.

The two main reasons I've read here are

1) recursive lookups might end up in the wrong widget. While this is technically correct, this problem wouldn't occur very often. To get back to my example of a close button. It would be odd to look for a close button on the sheet when you actually want a close button of a particular window.
2) serialization seems to suffer from it. The problem here if I understand correct is that the serialization system does not store the windows/widgets/sheets as the nested structures they actually are but it stores them in series, probably with a reference to their parent to put them back together. While I understand the reasons for doing this (it is just easier to walk over all the widgets in the sheet sequentially), a nice recursive function that runs over the widgets would work just as well.

The point I am trying to make is.

1) Enforcing unique names it not very user friendly. And let us not forget providing user friendly (and preferably efficient) access to some functionality is the main and in fact only purpose of a supporting library.
2) The implementation that most closely resembles the reality is most often the most straightforward implementation.

I apologize that I'm being so difficult about this. But I think this is important enough to insist upon. Both for my project as for future users of quickgui.

kungfoomasta

28-04-2008 04:46:59

2) serialization seems to suffer from it. The problem here if I understand correct is that the serialization system does not store the windows/widgets/sheets as the nested structures they actually are but it stores them in series, probably with a reference to their parent to put them back together. While I understand the reasons for doing this (it is just easier to walk over all the widgets in the sheet sequentially), a nice recursive function that runs over the widgets would work just as well.

I make use of the Ogre::ScriptLoader class and JohnJ's universal Script Parser class on the wiki to implement serialization. Basically you have ".sheet" files which are automatically treated as ogre resources (just like .material files) and parsed. After parsing the widget definitions they can be accessed by the ScriptParser easily, since it stores all of the string values in an organized manner. What this means is that each widget definition must have a unique identifier.

For example if you had a material file that looked like this:


material example\ninja
{
...
}
...

material example\ninja
{
...
}


You will get an error on parsing because you have duplicate named materials. (What would you expect to happen when you called MaterialManager::getByName("example\ninja") ?)

Nesting widget definitions would increase the complexity of the parser, reduce readability by a huge amount, and be way too much work to implement.

Kali I sent you a PM, if you want to take a stab at getting this working with my current code base.

@Zini:

Sorry for the short response, I'm really tired today. :) I would be willing to look into the alternative you mentioned, although I'm betting it would be at least a few hours of work for me to digest and start adding in. The main problem I see is that if you adpot the parent's name as your name, you better not be allowed to change names after creation or the search won't work correctly.