Skip to content
jpastuszek edited this page Oct 21, 2010 · 2 revisions

Object Model

Objects (nuiObject)

C++ lacks many very useful features that more dynamic and modern languages have.
Among these missing features there is:

  • the ability to introspect objects.
  • the ability to add some features to “anonymous” objects.

We have tried to add some features to NUI in order to compensate the lack of these. The central point of these features is the nuiObject class. Many classes in NUI inherit from nuiObject to take advantage of its services.

Objects names

Every nuiObject has a name it can use as an id. Unlike ids in many technologies, the object name doesn’t have to be unique. It is stored as an nglString in the object instance. The default name is a string containing the pointer to this in hexadecimal. You can change it for your objects:

pObject->SetObjectName(_T("SomeBetterNameForThisOne"));

To retrieve the object name:

nglString name = pObject->GetObjectName();

The object name can be used in the widget debugger and it is a very nice way to distinguish widgets in the CssSyntax.

Objects classes and Inheritance

Objects name are one thing but one very useful thing to have is the actual class name of the nuiObject pointers you manipulate. For example, the widget tree is just a tree of nuiWidget* and nuiContainer* and appart from using dynamic_cast<> everywhere there is no simple way to know if a particular object is of one type or another.

The object class name is set for once in the constructor of the object. For example let’s create a simple nuiObject sub class:

class MyStuff : public nuiObject
{
public:
  MyStuff()
  {
    if (SetObjectClass(_T("MyStuff")))
    {
      // If SetObjectClass returns true it means we are the first object of this class!
      // We can do something special about this if we need to.
    }
  }

  // ...
};

When we create an instance of MyStuff it will automatically set its class name to “MyStuff”. This means we can ask any object about its class:

nglString class_name = pObject->GetObjectClass();

But we can also ask an object if it is of a particular class:

if (pObject->IsOfClass(_T("foo"))))
{
  // do something special on this type of object
}

Because nuiObject classes also handle inheritance, an object of class “MyStuff” would return

  • false to pObject→IsOfClass(_T(“foo”)))
  • true to pObject→IsOfClass(_T(“MyStuff”)))
  • true to pObject→IsOfClass(_T(“nuiObject”)))

This means we can also get the class inheritance list for the object:

std::vector<nglString>& Classes;
pObject->GetObjectInheritance(Classes);
for (uint32 i = 0; i < Classes.size(); i++)
{
  NGL_OUT(_T("%d %ls"), i, Classes[i].GetChars());
)

If the case of MyStuff, the output would be:


0 nuiObject
1 MyStuff

As strings can be a bit memory and CPU intensive to store and process, NUI don’t store the class name in the object but only an integer index. The class database is stored globally in a static member of nuiObject. This permits to have fast object class comparison. You can get the index for a class name by calling nuiObject::GetClassNameIndex(...) in order to use it to speed your processing as you can use pObject->IsOfClass and pObject->GetObjectClassNameIndex() to test and retrieve these class indices.

Objects Properties

An nuiObject can contain properties. Properties are just like entries in a dictionary: it maps one string (the entries’ name) to another (the entries definition). Changing a property usually doesn’t change the behaviour of the object but it can be really useful to store important information, such as the file path from which the object was loaded from.

  • Set the property: SetProperty(_T("Path"), _T("/foo/bar"));.
  • Retrieve the property: just call nuiObject::GetProperty(_T("Path")).
  • Ask if a particular property was added to an object: use nuiObject::HasProperty(...), if it returns true you can safely call GetProperty(...).
  • You can also enumerate all the properties of an object with nuiObject::GetProperties(...)
  • Or delete one or all of them with nuiObject::ClearProperty(..) and nuiObject::ClearProperties().

Objects Tokens (nuiToken)

If you need to store anything too complicated to be represented by a string, properties will not be of much help to you. In that case, nuiObject still has a potential solution: nuiToken. nuiToken is a template class wih one template argument: the type of the data you want to store in the token. For example if you want to store a pointer to a widget as a token in an nuiObject you do this:

pObject->SetToken(new nuiToken<nuiWidget*>(pSomeWidgetPointer));

The token will be deleted when its containing object is. You can force deletion of a token by calling pObject->SetToken(NULL); if you need to. Replacing a token always deletes the previous one automatically.
Now that you have stored a token on your object, you may want to get it back somewhere else in your code. Here is the simple way to do it:

nuiWidget* pWidget = NULL;
if (nuiGetTokenValue<nuiWidget*>(pObject->GetToken(), pWidget))
{
  //  the token was found with the correct type, you can now use pWidget.
  // Beware that pWidget is valid but it might still be NULL.
}
else
{
  // in this case the token was either invalid (i.e. NULL)
  // or not containing the type we ask for (in this case an pointer to a widget).
}

Objects Attributes (nuiAttributeBase, nuiAttribute<>, nuiAttribBase, nuiAttrib<>)

Attributes is probably the most powerful feature of nuiObject. In many high level languages, some or all data members of a class are considered attributes: they have a getter method, a setter method and they can be enumerated without knowing the internals of the class. This feature doesn’t exists in C++ and just declaring data members public barely makes them accessible to code that already know about the class, statically at compilation time. NUI attributes is a way to get over this limitation of C++.
In NUI, an attribute is a construct that describes an element of an object and gives access to it (read or change its value). Some good example of attributes:

  • an nuiLabel can expose its text as a nglString attribute.
  • every widget expose they alpha value (used for transparency) as a float value.
  • a decoration can expose its main color as an nuiColor.

This permits that any piece of code that knows only about nuiObject to change the text of a label or the color of a decoration without knowing anything about the actual nature or the object they are accessing. They don’t know nuiWidget, nuiLabel or nuiDecoration, they just enumerated the attributes presents on the object and learned that they could set or get an attribute named “Text” that is actually an nglString (for example).

Using attributes

Querying attributes

You can access an attribute using two different classes: nuiAttribBase and nuiAttrib<>.

  • nuiAttribBase doesn’t know any thing about the type of the attribute you are accessing. The interface to get and set the value of the attribute is string based. Here is an example:
    nuiObject* pObject; // The object containing the attribute you need to access
    nuiAttribBase some_attrib(pObject->GetAttribute(_T("SomeAttributeName")));
    if (some_attrib.IsValid())
    {
      nglString value;
      some_attrib.ToString(value); // store the value of some_attrib in the string 'value'.
      some_attrib.FromString(_T("some new value passed as a string")); // change the attribute with the given string.
    }

As you can see some_attrib is created by asking pObject to give the attribute “SomeAttributeName”. If pObject doesn’t contain the requested attribute it will return an invalid nuiAttribBase. That’s why we have to test for the validity of some_attrib before using it.

If you know the actual type of the attribute you are accessing you can use it directly in the following fashion:

nuiObject* pObject; // The object containing the attribute you need to access
nuiAttrib<const nuiColor&> some_attrib(pObject->GetAttribute(_T("SomeAttributeName")));
if (some_attrib.IsValid())
{
  nuiColor col = some_attrib.Get();
  some_attrib.Set(nuiColor(255, 0, 0));
}

Listing attributes

Here is how to get a list of the attribute stored on an object:

nuiObject* pObject; // The object
std::map<nglString, nuiAttribBase> Attribs;
pObject->GetAttributes(Attribs);

This gives you a map of the attribs where the key of the map is their name. As it is a map there is no particular sorting order and enumerating the attribs will not give you any hint on their origin (i.e. what class defines them).

If this information is important to you you can request a sorted list of attribute names:

nuiObject* pObject; // The object
std::list<nuiAttribBase> SortedAttributes;
pObject->GetSortedAttributes();

The SortedAttribute list contains a list of attribute name, is their order of inheritance. This means that if you have this construct:

class A { }  // defines attribs A_0 and A1
class B : public A { }  // defines attribs B_0 and B_1
class C : public B { }  // defines attribs C_0 and C_1

asking for the sorted list of attributes of an instance of C will give you the following list:


A_0
A_1
B_0
B_1
C_0
C_1

Editing attributes

Attribute are nice to use by hand but most of the time one doesn’t want to create a new set of widget to edit simple attributes. In this case, NUI provides many default editors for simple attribute type. To get an editor for an attribute just do this:

nuiObject* pObject;
nuiAttribBase attrib(pObject->GetAttribute(_T("SomeAttribName")));
if (attrib.IsValid())
{
  nuiWidget* pEditor = attrib.GetEditor();
  // to something with editor widget...
}

Creating class attributes

Single values

1D Arrays

2D Arrays

Creating instance attributes