Next: 2.4 The connectors section Up: 2. The GNUstep Markup Previous: 2.2 General overview of

Subsections


2.3 The objects section

2.3.1 Relationship between tags and objects

The objects section describes objects which are to be created when the file is loaded into a running application. The section describes the intention of the programmer about the objects to be created - the logic of the GUI objects in other words - rather than the precise details of how the objects are to be created on each platform. For example, a button with title 'Quit' and which, when clicked, terminates the application, is described in the file as:

<button title="Quit" action="terminate:" />
The actual appearance of the button (border, imaged used for borders, font used for the title, changing in the button appearance when it's clicked etc) is not specified - on each platform it will different - on platforms supporting themes or just preferences like allowing the user to change the default font size, it might even change each time depending on the configuration. The actual size of the button is computed automatically by the system at runtime when the button object is created; the title is also translated automatically at runtime (and the button sized depending on the translated title). All this information (appearance of buttons, fonts, images, translation of titles etc) really is not known till the program is run, so the button object will result different on each platform and each configuration.

For this reason, the list of objects really is more an abstract description of the logic of the GUI interface rather than an exact specification. Most tags correspond to objects; a few tags (such as the separators tag, used to add separators in menus and hboxes/vboxes) don't necessarily correspond to objects.

In some cases, different tags produce objects of the same class; for example the <label> tag creates a NSTextField object used to display a non-editable string (such as a title or a message), while the <textField> tag creates a NSTextField object used to display an area on screen where the user can insert some text. While they are implemented using the same class, they are conceptually completely different GUI objects, because they have a completely different function.

In other cases, the same tag could produce objects of different classes depending on the attributes it contains. As an extreme example, all tags representing view and window objects support an instanceOf attribute - if this attribute is set to a value, the value is used as the name of the class of the object to create (provided that this class is a subclass of the class which would be used by default). For example,

<button title="Example" />
would create a button object (an instance of NSButton). Now if MyButton is a subclass of NSButton, then
<button title="Example" instanceOf="MyButton" />
would do exactly the same, but allocating the object using the custom subclass MyButton instead of the default class NSButton. This is a very powerful and simple way of embedding customized objects in windows.

Normally, each tag creates an object, except in special cases, which are clearly documented.

2.3.2 Object tags - basic example

Consider for example the <window> tag, used to create a window object. In the simplest case, the tag is just opened and closed:
<?xml version="1.0"?>
<!DOCTYPE gsmarkup>

<gsmarkup>

  <objects>
    <window>
    </window>
  </objects>

</gsmarkup>
or more simply (using the abbreviation <window />, which in XML means <window> </window>):
<?xml version="1.0"?> 
<!DOCTYPE gsmarkup>

<gsmarkup>

  <objects>
    <window />
  </objects>

</gsmarkup>
(in this example, we showed all the document; in the next examples of object tags, we will omit all but the tags we are discussing). If you load this example into an application, it will create a window, with no particular attributes and nothing inside it.

2.3.3 Object tags - attributes

If you want to modify the properties of an object, you add attributes to the tag. For example, if you create a window using the <window> tag, it is created by default miniaturizable, resizable and closable. If you don't want it to be closable, you need to add an attribute to the tag -
<window closable="no" />
This causes the window to be created without the close button. Attributes are generally used to change the properties of that specific object. Each object is normally created with default properties set up for the most common case, so you only need to specify attributes when you need some special behaviour. In the example of the window, all windows are created by default with a close button, unless you specify closable="no".

A tag can have more than one attribute - it can have as many attributes as you need. The attributes are written one after the other one, separated by spaces. For example, if you want both to specify that a window should not be closable and not resizable, you can write

<window closable="no" resizable="no" />

We now examine and classify all the different types of attributes you can use for a tag. Some attributes have a string value, other a boolean value, other even describe a color or a font; other still give a name to the object so that it can be referenced from elsewhere; other are references to other objects.

2.3.3.1 String attributes

String attributes are very common - a string attribute sets a property of the object which is described by a string. For example, if you want to create a window with a title Game Board, you write
<window title="Game Board" />
The attribute title is set to a string, Game Board in the example. You can use any character in the string, except a few special XML characters - to insert them, you need to use the entities listed in table 2.1. Each tag has a different set of available string attributes - the reference documentation later on in this document lists all available string attributes for each tag.

2.3.3.2 Localizable strings attributes

Most (but not all) strings need to be localized - that is, translated into the user preferred language - before they are displayed. Each tag knows which attributes are strings to localize, and which are strings not to localize (it's normally quite obvious - anything which is meant to be displayed to the user must be localized, while anything which is only used internally by the program must not be; for example, window titles or button titles are localized; selectors as used in actions are not). To localize a string, the gsmarkup framework calls the NSBundle method +localizedStringForKey:value:table:, first looking for the string in the specific table (normally loaded from a file having the same name as the .gsmarkup file, but with a .strings extension rather than a .gsmarkup extension), and failing that, in the Localizable.strings strings table. If that fails too, the string is used untranslated. For example, suppose that you have the window
<window title="Game Board" />
created in your main.gsmarkup file. To translate the window into Italian, you need to add a file Italian.lproj/main.strings to your application, containing the following line:
"Game Board"="Tavolo di Gioco";
when the application loads the .gsmarkup file, it automatically translates it into the appropriate language by using the appropriate main.strings file for that language. In this example, when the user sets Italian as his preferred language, the window will be created with title Tavolo di Gioco rather than Game Board. Please note that by default different .gsmarkup files use different .strings files - for each .gsmarkup file there is a corresponding .strings file. This makes it easier to keep the .strings files updated (you only need to update a .strings file when the corresponding .gsmarkup files has changed), makes clear where each string comes from, and allows different .gsmarkup files to contain the same English string, and yet to translate it in different ways.

2.3.3.3 Boolean attributes

Boolean attributes are used to set a boolean property of the object. The valid values of a boolean attributes are yes and no - for example, you can write
<window resizable="no" />
Resizable is a boolean attribute, which can be YES or NO. The example sets it to NO. For consistency with other stuff which is always written lowercase, we prefer to use yes and no (lowercase), but it is only a matter of taste: Yes, YES are valid as well as attribute values, and they mean the same thing as yes; No and NO are valid as well to mean no. For example, it is perfectly correct to write
<window resizable="NO" />
and it means the same as before.

Each boolean attribute normally has a default value (documented in the documentation); if a boolean attribute is not present, or if its value can't be parsed as a yes or a no, then it's ignored, which implicitly means that the default for it is used.

2.3.3.4 Number attributes

Number attributes are used to set a property to a number (integer or float). For example, to create window with width 200 and heigth 50, you do
<window width="200" height="50" />

2.3.3.5 Image attributes

Image attributes are used to set a property to an image. The image is found by invoking the method +imageNamed: of NSImage. For example,
<button image="mail" title="Read Mail" imagePosition="above" />
would set the button image to the result of calling
[NSImage imageNamed: @"mail"]
and position it above the title.

2.3.3.6 Sound attributes

Sound attributes are used to set a property to a sound. The sound is found by invoking the method +soundNamed: of NSSound. For example,
<button sound="mail" title="Read Mail" />
would set the button sound to the result of calling
[NSSound soundNamed: @"mail"]

2.3.3.7 Color attributes

Color attributes are used to set a property to a color. You should use this very rarely, because you want your program to use the native platform colors when running on a certain platform. But in some cases - for example when setting up a colorWell (a gui object which allows the user to choose a color) - you need to specify colors.

Color attributes are evaluated in the following way by the system:

  1. First, the system checks if NSColor responds to the method +xxxColor, where xxx is the value of the attribute. If it does, the method is invoked, and the result is used as the color. For example,
    <colorWell width="50" height="50" color="red" />
    
    will create a colorWell which displays the color returned by [NSColor redColor]. In this way, you can access all standard colors by name, such as black, white, red, blue, green, yellow, windowBackground, etc. (advanced tip: if you want to access a non-standard one by name, you can always implement a NSColor category, and add the method you need).
  2. If the method is not found, the system tries to parse the color as a calibrated RRGGBB or RRGGBBAA description of the color, where RR, GG, BB and AA are hexadecimal two-digits number between 00 and FF describing the red, green, blue and alpha components of the color (btw this is the same format used in HTML pages, without the # at the beginning). For example, FFFFFF is white, 000000 is black, FF0000 is red, and FF000065 is a semi-transparent red color.

2.3.3.8 Font attributes

Font attributes are used to set a font property. This is very delicate, because you want your program to use the native platform fonts when running on a certain platform - hardcoding a certain font might actually destroy the visual impact of your program rather than improving it (typically, the font you want might not be available on that system, and be replaced with an ugly one, or might simply clash completely with the rest of the look on the system, be too big, too little, or too bold or too fuzzy compared with the other native fonts used by the system). In general, system fonts are normally chosen between the prettier fonts available on the plaform, and the appearance of the user interface elements is made to match those fonts. Last, the user/theme might have changed the fonts to fit their wishes/needs, and you certainly don't want to argue with your users. For this reason, gsmarkup normally doesn't really allow you to specify a font, but only to scale the default system fonts.

In some cases - for example when creating panels - you might want to display a title on top of your panel, or other information which you want to display in a more prominent font. This is typically needed by labels (objects which display non-editable strings such as those used by titles or messages). A font attribute allows you to specify the size and type of font you want.

The font for labels is normally found by calling the [NSFont labelFontOfSize:0] method (or the [NSFont systemFontOfSize:0] on older systems which don't have +labelFontOfSize:).

You normally only need to make the font bigger or smaller. To do it, you can use the following font values:

For example,
<label font="Big">Contents</label>
displays Contents using the default label font, with the default label font size multiplied by 1.5.

You can also specify a float, which is read and interpreted as a scaling factor. For example,

<label font="1.5">Contents</label>
is completely equivalent to setting the font to Big.

Normally, you only want to change the fonts in labels, and you don't need to bother with the font type. For very special cases, you might need to change font type. The current API used on OpenStep systems provides NSFont methods to get recommended fonts to be used on that particular platform to display various types of gui objects - for example, [NSFont userFontOfSize: 0] returns the font to be used for user editable text, in the default size. To choose that type of font, you just specify user as the font value, as in

<label font="user">Testing fonts</label>
this draws the label using the font [NSFont userFontOfSize: 0]. In general, if the value of the font attribute is xxx, the NSFont method +xxxFontOfSize: (if it exists) is used to get the font. The types of fonts available on gsmarkup at the moment are label, boldSystem, user, userFixedPitch, menu, message, palette, system, titleBar, toolTips. These fonts should be available on other OpenStep systems as well, but not all them are available on older OpenStep systems, and you would extremely rarely need to use them anyway.

Anyway, if for example you want to display a button containing a title with a bigger font, you may need them.

You can use one of those standard fonts in any size, for example

<label font="user big">Testing fonts</label>
is valid, and uses the same font returned by [NSFont userFontOfSize: 0] but enlarged by a factor of 1.20.

2.3.3.9 The instanceOf attribute

This is a special attribute which is recognized by all objects which inherit from windows or views (views represent rectangular areas in windows). It allows you to allocate the object using a subclass instead of the original class; it is typically used to create objects of custom subclasses. For example, if you implement a class called NPWindow, which is a subclass of NSWindow with some special behaviour added to it, then you can create a window of you subclass by doing
<window instanceOf="NPWindow" />
This will create a window using the standard procedure used for windows, except it will lookup the class named NPWindow at run time, and allocate the object using that class instead of NSWindow class. Please note that all the standard attributes of a window object are still recognized:
<window instanceOf="NPWindow" width="100" height="100" resizable="no" />
the attributes will be read, and applied to the window exactly as if the window was a standard NSWindow object. Because NPWindow is a subclass of NSWindow (and Renaissance will check it at run time), all the attributes and methods which are valid for a NSWindow are expect to be available for an NPWindow object too, so this is expected to work.

In detail, when you specify a instanceOf="XXX" attribute for a view or window tag, Renaissance at run time looks up XXX as a class name, searching for a class with that name. If a class with that name is found (in the executable), Renaissance checks that the class is a subclass of the default class (the one which would be used if no instanceOf attribute had been specified). If it is, then Renaissance allocates the new object using class XXX instead of the default class. It is important to check that the class XXX is a subclass of the default class, because that makes sure that the object created supports all the attributes and methods that a default object would. Then, everything else goes on as if the created object was of the default class.

The reference documentation should mark clearly tags which recognize the instanceOf attribute, and tags which ignore it.

As a final note, if you need to allocate an object which is not a subclass of a view or of a window, you can use the <instance> tag, which allows you to allocate an instance of any class (still specified with the instanceOf attribute). This is mostly used to create controller objects. Because of the wide generality of the objects allocated by the <instance> tag (which could be of any class), there are no defined attributes you can set for the object created, except for embedded outlets (described in the next sections), which are always available for all objects. The <instance> tag is normally used if you want to create an instance of a controller class from a gsmarkup file; it's not used to embed custom controls in windows, or to create custom windows: in those case, you are better off using a view or window tag with a instanceOf attribute, because then Renaissance will know what type of object it is and will treat it accordingly, including recognizing all the appropriate attributes.

2.3.3.10 The id attribute

This is a special attribute which any object can have; it is used to tag objects with names, so that you can refer to that object by name. The attribute is always called id, and its value is a string which is the internal name to give to the object2.1. For example,
<window id="board" />
creates a window, and tags it with the id board. You can then refer to this window object by name whenever you need it (we'll explain later on when you might need to refer to the window object). Of course, you don't need to tag all objects with names - you would just be wasting time and making your gsmarkup files more difficult to read if you do - you only need to tag the ones which you need to refer to. The id name of the window is never shown to the user - it's only used internally to refer to objects by name, and establish connections between objects.

2.3.3.11 Mask attributes

Some attributes are used for integer mask, where a number of possibilities are combined. In that case, the description of the attributes lists all the possible values, and a | character can be used to specify multiple values at the same time (the | character is used because internally a bitfield OR will be used to calculate the final value). For example, a <button> tag has a sendActionOn attribute (inherited from <control>) which can be used to control when the button specific action is triggered. The sendActionOn attribute can take a number of values, such as leftMouseUp or leftMouseDown (indicating that the button's action is triggered when the left mouse button is released, or pressed). To specify that it should the action both when the left mouse button is pressed and released, you can use the | character as in the following example:
<button title="Test" action="dummyAction:" 
               sendActionOn="leftMouseDown | leftMouseUp" />
Note that spaces around the | character are ignored, so you can use them for readability if you want.

2.3.3.12 Attributes referring to other objects

In the previous section we have explained how you can tag an object with an id. In this section we learn how you can refer to an object by id. There is a very general syntax which can be used to refer to an object which has been given an id: you prefix the id name with a hashmark (#). For example, if you create a window and give it an id of board, as in
<window id="board" />
then you can refer to that window object by using the syntax #board. #board simply means the object whose id name is board.

This is normally used to establish connections between objects. There are two ways of building connections between objects: one is adding a connector to a connectors section. A gsmarkup file can contain one or more connectors sections, where you can freely build up connections between objects (and you refer to objects by using their ids and the syntax just explained). The other way, the one we learn about here, is by using attributes which take objects as values.

Some attributes wants other objects as values. For example, a window can have a delegate, and this delegate is an object. You can specify the delegate object for a window by using the following syntax:

<window delegate="#myDelegate">
When this file is loaded in a running application, the attribute delegate is treated specially. It is treated specially because its value begins with a hash (#), which means it is a reference to another object (in the file or even outside the file). When the file is loaded, the method setDelegate: of the window object will automatically be called, with argument the object which has id name myDelegate. This object can be
  1. another object which is created by the file when the file is loaded. In the example, since you can create objects of custom classes in the file, you could allocate an instance of a custom class, give it the id name myDelegate, and then make it the window controller.

  2. the file owner. The file owner is an existing object in the application which loads the file; whenever the application loads a gsmarkup file, it needs to specify a file owner object, which is automatically made available to the file with the id name NSOwner. For example, to make the file owner the delegate of your window, you would do
    <window delegate="#NSOwner">
    
    Normally, all connections between the objects loaded in the file and the existing application objects are done through the file owner.

  3. NSApp (the shared application instance), which is automatically made available by Renaissance with the id name NSApp. For example, to create a popup button with an item which terminates the application, you would do
    <popUpButton>
      <popUpButtonItem title="terminate the app" action="terminate:"
                       target="#NSApp" />
    </popUpButton>
    

  4. some other existing object in the application which is made available to the file when the file is loaded. If the application needs it, by using the extended NSBundle GSMarkup API, it can make available any existing object in the application specifying under which name it should be available. If there is a single object to connect, it is simpler to make that object available as file owner; if there are more, you can specify them in the external name table dictionary (see description of the NSBundle GSMarkup API), and then the file can make any connections to those objects by referring to them by id, and using the special syntax with the hash.

Here is another example -

<window>
  <hbox>
    <button title="yes" id="yes" nextKeyView="#no" />
    <button title="no" id="no" nextKeyView="#yes" />
  </hbox>
</window>
in this example, a window with two buttons is created. The first button has title yes, the second one has title no. The first button is given id yes, and the second one is given id no. Then, the nextKeyView attribute of the first button is set to point to the second one, and the nextKeyView attribute of the second button is set to point to the first one. This allows users to navigate between the buttons using the keyboard - pressing TAB while the input focus is on an object moves the focus to the nextKeyView of that object. In the example, the nextKeyView of the first button is the second one, and viceversa, so by pressing TAB the user can move the input focus between the two buttons.

2.3.3.13 Technical details of embedded outlets

You can skip this section at a first reading. It is explaining the technical details of attributes referring to objects.

Technically, whenever an attribute has a value which begins with a single hash (#), the system automatically creates an outlet connector when the file is loaded (and adds it to the list of outlet connections to be established), and removes the attribute from the list of attributes. So if you wish to encode attribute text beginning with a hash, you must escape that leading hash by doubling it. No check is done on the attribute name, so you are free to setup any sort of connectors you want. When the outlet connections are established, the outlet will establish the connection from the source (the object bound to the tag where the attribute was found) to the target (the object which is referred by the attribute) using as key the attribute name. Establishing outlet connections uses key-value coding, so in practice by writing

<window delegate="#myDelegate">
you are effectively establishing that the value of the key delegate of the created window object should be set to the object whose id is myDelegate.

This way of embedding outlets inside object description is both very natural and very powerful; it is certainly much more natural than having to write in the separated connectors section.

2.3.3.14 Advanced embedded outlets using key value paths

This section explains a rarely useful, and rarely used, advanced technique. Unless you are already familiar with key-value coding, you can/should definitely skip it at a first reading.

Renaissance allows the advanced syntax

<window delegate="#NSOwner.windowDelegate" />
to mean extracting the value for the key windowDelegate of the #NSOwner object, and setting it as the delegate of the window. ``Extracting the value for the key'' will use key-value coding to get it. In practice, if the #NSOwner responds to one of the methods getWindowDelegate, windowDelegate, _getWindowDelegate, _windowDelegate, or has an instace variable called _windowDelegate or windowDelegate, to get the value for the key, the method will be called, or the instance variable will be read2.2.

This can be a very handy trick. Typically, you can have delegates (or other similar attributes) of objects created from the gsmarkup to be set to point to instance variables (or the result of calling certain methods) of the #NSOwner. It's an additional layer of flexibility.

Renaissance also allows multiple key-value coding in sequence, for example

<window delegate="#NSOwner.controller.preferenceWindowDelegate" />
This will start with #NSOwner, use key-value coding to extract the value for key controller of that object, then use key-value coding to extract the value for key preferenceWindowDelegate of the resulting object, and finally set the window's delegate to the result.

To support both simple and multiple key-value coding, Renaissance uses -valueForKeyPath:. For example, when Renaissance processes the code

<window delegate="#NSOwner.windowDelegate" />
it assigns to the window's delegate the result of calling
[#NSOwner valueForKeyPath: @"windowDelegate"]
which, in this case, because there are no dots in the keypath, does the same as [#NSOwner valueForKey: @"windowDelegate"].

As a general rule, if the id of the source or target of an embedded outlet (or other connector) contains a dot (that is, the character '.'), then the string up to the dot is the id of an object to use, and the string following the dot is interpreted as a key path value to apply to the object in order to get the actual source or target of the connector. So, #xxx.yyy is to be interpreted as meaning ``the result of [#xxx valueForKeyPath: @"yyy"], where #xxx is the object with id xxx.''

For example, the expression #NSApp.mainMenu means the result of calling

[NSApp valueForKeyPath: @"mainMenu"]
which will return the application main menu. #NSApp.delegate.description means the result of calling
[NSApp valueForKeyPath: @"delegate.description"]
which will invoke the description method of the delegate of NSApp.

For more information, please refer to the documentation of key-value coding, for example the documentation for the -valueForKeyPath: and -valueForKey: methods.

2.3.4 Object tags - content

Everything which is found between an open tag and the corresponding close tag is called the content of the tag. For example, in
<label>Please reboot your system</label>
the open tag is <label>, the close tag is </label>, and the string inside is the content of the tag. Often, the content of a tag can include other tags. For example,
<window>
  <button title="Click me to quit" action="terminate:" />
</window>
in this case, the content of the window tag is the button tag.

In general, while attributes are used to change the properties of the specific objects represented by that tag, the content of a tag are used to describe things which go inside the object. This concept is of course human and not completely well defined, anyway the idea is that, for example, the attributes of a <window> tag (such as closable="no", width="200", title="Main Window") change the general properties of the window, while the tags inside the window tag represent objects which should be displayed inside the window.

Now we examine typical examples of tags and the type of content they can hold.

2.3.4.1 No content

Some gui objects do not contain anything. For example, a button or a colorWell do not contain anything and never have a content.

2.3.4.2 String content

Some gui objects have a simple string content, representing a string to be displayed inside the gui object. This typically happens with labels and textfields; in this case, the string is not in the attributes because it could potentially be very large. For example,
<label>Missing image</label>
displays a label with the string Missing image, while
<textField>user@host</textField>
displays an editable textField which contains the string user@host when it is first displayed. In this case, the string to display is in the content of the tag because it can potentially be very big (and perhaps optionally contain formatting tags (html?) in the future for attributed strings ?).

In most cases, string content are localizable - they are automatically localized by the gsmarkup framework in the same way as it is done for localizable string attributes.

2.3.4.3 Tag content

Other gui objects have content which is composed of other objects. Typical examples include:


Next: 2.4 The connectors section Up: 2. The GNUstep Markup Previous: 2.2 General overview of
2008-03-19