motifdeveloper.com
Sponsored by IST Limited
Formerly MW3: Motif on the World Wide Web [MW3 Logo]
Last Updated
November 18, 2002
 


X-Designer - The Leading X/Motif GUI Builder - Click to download a FREE evaluation
 

motifdeveloper.com
Home
About the site
Bulletin Board
News Archive
OpenGroup News
Events
Search
Frequently Asked Questions
The Motif FAQ
X/Motif FAQs
General FAQs
Ask Antony
Latest Q & A
All Q & As
Submit Question
Tips & Pointers
Code Examples
Software
OpenMotif
Widget Sets
GUI Toolkits & Libraries
Motif suppliers
Non-commercial S/W
Commercial Software
Multimedia
Miscellaneous
Organizations
Docs & Pubs
X/Motif Newsgroups
Security
Internationalization
Feedback
Feedback Form
Contributors
 

What are Render Tables and how are they used?

4-Dec-00 16:00 GMT

Introduction

In Motif 1.2, compound strings were rendered with respect to an XmFontList. The XmFontList we will define simply as a group of X Fonts and Font Sets, which has an order imposed upon it by the Motif toolkit. Each widget context where it was possible to display a compound string (XmString) would support in parallel an XmFontList resource, so that the specification of the compound string, and the font (or fonts) in which it was to be drawn were logically separate.

The beauty of the design was that, by separating the contents of a compound string from the way in which it was rendered, it was possible to display the same string in different ways, simply by changing the XmFontList associated with each given context. Indeed, both the font and the compound string could be specified externally to the application, thus enabling a full internationalization of the application simply by maintaining multiple locale-specific resources for each language context.

The limitations of the design are immediately obvious: the only information held separately from the compound string was font data. If you wanted to display a given compound string in multiple colors, you could only do so by either drawing each string by hand, or by splitting the string across more than one widget, and thereafter specifying the appropriate colors for each widget.

From Motif 2.0, this is all changed. The XmFontList is obsolete, and is replaced by the XmRenderTable. A Render Table is a complete specification of style for compound strings. The Render Table consists of XmRendition objects, each of which describes not just font, but also line style, color and multi-column layout information. In Motif 2.0 and later, we can have multi-column, multi-color, multi-font Lists. And thus, whereas in Motif 1.2 we render compound strings with respect to an ordered set of named (tagged) fonts, in Motif 2.1 they are rendered with respect to tagged rendition objects contained in a render table. The difference is that the rendition object is considerably more descriptive than just a font specification.

In order to make use of the new render table facilities, the Motif 2.1 compound string has been enhanced in a number of ways. There are new compound string component types that allow the programmer to explicitly specify which rendition within a render table is currently operative. It is not essential however to use these new segment types because the XmStringGenerate() routine automatically places these segments into the compound string on the programmer's behalf. The only new segment type which the programmer does have to specify is the tab component, which controls multi-column layout. This is outlined below both in the text and in example programs.

Throughout Motif, all the places which used to contain an XmFontList resource also now support an XmRenderTable equivalent. For backwards compatibility, the XmFontList has been internally re-implemented as a Render Table (although the render table it creates only contains font data).

For efficiency, Render Tables and Rendition objects are shareable across widget contexts, and independently reference-counted. They are also inherited within the widget hierarchy, thus enabling a degree of consistent appearance for the application. The XmNbuttonFontList, XmNlabelFontList, XmNtextFontList resources, for example, which used to specify default fonts for objects further down the widget hierarchy, are now augmented with the XmNbuttonRenderTable, XmNlabelRenderTable, and XmNtextRenderTable resources respectively.

Think of a Render Table simply as a style sheet for compound strings. A Rendition is just one piece of the overall style. Since it is the lowest building block, it is this object which we must describe first.

The XmRendition Object

An XmRendition object is a pseudo-widget. Although not a true widget, it has many of the properties of one, namely resource attributes and a resource-style interface. Rendition attributes can be specified in a resource file, just like widget attributes.

Creating a Rendition Object

In code, an XmRendition object is created using the following routine:

    XmRendition
    XmRenditionCreate (Widget widget, XmStringTag tag, Arg *argList, Cardinal argCount)

The widget parameter is simply a hook by which the routine finds a Display (X server) connection: it does not have to be related in any way to the widget(s) where the rendition is to be applied. Its use is so that the fonts and colors specified in the argList parameter can be created. The valid resources which can be specified in the argList are given below.

The rendition object is identified through the tag specification: it is the name by which the rendition object is looked up in the containing render table, when a compound string segment is to be drawn. In other words, whereas in Motif 1.2 a compound string segment was drawn by looking up tags within an XmFontList, in Motif 2.0 and later they are drawn with respect to XmRendition tags. A given rendition object is used to draw a compound string segment if the tag associated with the segment matches the tag associated with the rendition object.

If the tag is NULL, the default value _MOTIF_DEFAULT_LOCALE is internally assigned, and this will match any compound string segment which is tagged XmFONTLIST_DEFAULT_TAG.

As an example, the following code fragment creates a simple rendition object. The meaning of the particular rendition object resources applied in the example is discussed in the following section.

    extern Widget widget;       /* An arbitrary widget      */

    XmRendition   rendition;    /* The new rendition object */
    Arg           args[8];      /* New rendition resources  */
    Cardinal      n = 0;        /* Count of new resources   */

    ...

    /* Use the standard fixed font */
    XtSetArg (args[n], XmNfontName, "fixed"); n++;

    /* Its an X Font, not a Font Set */
    XtSetArg (args[n], XmNfontType, XmFONT_IS_FONT); n++;

    /* Create the rendition */
    rendition = XmRenditionCreate (widget, "my_tag", args, n) ;

The set of resources which can be specified for an XmRendition object is given in the following table:

Rendition Resources

Name Class Type Default Access
XmNfontName XmCFontName String XmAS_IS CSG
XmNfontType XmCFontType XmFontType XmAS_IS CSG
XmNfont XmCFont XtPointer NULL CSG
XmNloadModel XmCLoadModel unsigned char XmAS_IS CSG
XmNunderlineType XmCUnderlineType unsigned char XmAS_IS CSG
XmNstrikethruType XmCStrikethruType unsigned char XmAS_IS CSG
XmNrenditionForeground XmCRenditionForeground Pixel XmAS_IS CSG
XmNrenditionBackground XmCRenditionBackground Pixel XmAS_IS CSG
XmNtabList XmCTabList XmTabList XmAS_IS CSG
XmNtag XmCTag XmStringTag "" C

Firstly, we should specify what the XmAS_IS value means. A render table contains an ordered set of renditions, any one of which may have the right tag to render some given compound string segment. However, it is not necessary to fully specify a rendition object for it to be effective: certain of its resources may be inherited from previous renditions in the render table. The value XmAS_IS indicates that the given attribute is indeed inherited from earlier renditions. In other words, if we only specify the rendition background, the font used to draw the current compound string segment will depend upon an earlier rendition in the render table. The order of renditions in a render table is therefore of some importance.

There are two ways of specifying fonts in a rendition object. The first method is to directly load an X Font (or X Font Set) by hand, and specify the resulting XFontStruct * (or XFontSet) as the XmNfont resource of the rendition object. The second method is to specify just the name using the XmNfontName resource: this should be a standard XLFD font specification. If you specify both methods, the XmNfont takes precedence. In either method, we also need to specify the XmNfontType resource, specifying whether we are loading an X Font (XmFONT_IS_FONT) or an X FontSet (XmFONT_IS_FONTSET).

The XmNloadModel resource only comes into play if we are specifying the XmNfontName. In Motif 1.2, whenever an XmFontList was specified as a resource to a widget, the fonts associated with the XmFontList had to be loaded prior to usage, whether or not they were actually referenced by any compound string in the widget. This was not particularly efficient, especially in internationalized applications which require multiple fonts to satisfy the current locale. In Motif 2.1, the situation is different. We can specify that a font is to be loaded only if referenced. This is where the XmNloadModel resource comes in: the value XmLOAD_IMMEDIATE loads the font immediately whether referenced or not, and the value XmLOAD_DEFERRED will only load the font at a later time if and when required at the precise point of compound string rendition, thus potentially saving considerable resources.

The XmNrenditionBackground and XmNrenditionForeground resources are straightforward, and represent the colors to use when rendering a compound string using this rendition. The color of a compound string in Motif 2.1 is thus potentially independent of the background and foreground of the widget where the string is drawn.

The XmNunderlineType and XmNstrikethruType resources specify additional line attributes for the rendition object. Possible values are:

    XmNO_LINE
    XmSINGLE_LINE		XmDOUBLE_LINE
    XmSINGLE_DASHED_LINE	XmDOUBLE_DASHED_LINE

The XmNtag resource is not to be manipulated by the programmer: it is a copy of the tag parameter as supplied to the XmRenditionCreate() routine, and is for internal use.

Lastly, the XmNtabList resource specifies an XmTabList object: it is the means whereby Motif 2.1 implements multi-column layout of compound strings. The XmTabList is described below.

Freeing a Rendition Object

When a rendition object is no longer required, it should be freed using the following routine:

    void
    XmRenditionFree (XmRendition rendition)

The routine internally decrements the reference count associated with the object: you must use this in preference to XtFree() or other dellocation routines so that Motif can keep the reference count in order. Bear in mind that the rendition object may appear in many render tables referenced throughout the widget hierarchy. Only when the reference count reaches zero is the rendition object actually freed.

Updating Rendition Resources

The attributes of an arbitrary rendition object can be modified using the following routine:

    void
    XmRenditionUpdate (XmRendition rendition, Arg *argList, Cardinal argCount)

Updating rendition resources is simple. As an example, the following code fragment changes the font associated with a rendition object:

    extern XmRendition rendition;  /* An arbitrary rendition object */
    Arg                args[8];    /* New rendition resources       */
    Cardinal           n = 0;      /* Count of new resources        */

    ...

    /* A new courier 12-pt font */
    XtSetArg (args[n], XmNfontName, "-*-courier-bold-r-*-*-12-*-*-*-*-*-*-*"); n++;

    /* Its an X Font, not a Font Set */
    XtSetArg (args[n], XmNfontType, XmFONT_IS_FONT); n++;

    /* Load later, for potential efficiency */
    XtSetArg (args[n], XmNloadModel, XmLOAD_DEFERRED); n++;

    /* Update the rendition */

    XmRenditionUpdate (rendition, args, n) ;

Retrieving Rendition Resources

Retrieving rendition resources is also fairly simple, except that in common with widget fetch routines, for example XtGetValues(), we pass the address of a variable into the argument list. The following code fetches the underline type and foreground color from a given rendition object:

    extern XmRendition rendition;   /* Arbitrary rendition */
    Arg                args[4];
    Cardinal           n = 0;
    Pixel              fg;
    unsigned char      underline;

    /* Pass the address of the underline variable */
    XtSetArg (args[n], XmNunderlineType, &underline); n++;

    /* Pass the address of the fg variable */
    XtSetArg (args[n], XmNrenditionForeground, &fg); n++;

    /* Fetch the values */
    XmRenditionRetrieve (rendition, args, n);

This is all that there is to know about the rendition object: four simple routines to create, free, update, and fetch the object values. However, Rendition objects themselves are not used stand-alone: they must be merged into a render table. How to do this is covered in the following section.

The XmRenderTable Object

An XmRenderTable is nothing more than an ordered collection of XmRendition objects. This is not to say that we can simply create an array of XmRendition objects and throw them at a widget. The XmRenderTable is not defined as XmRendition *, but is a distinct, opaque type. Render tables are created using reserved toolkit routines; thereafter we merge, reorder, remove, and otherwise manipulate the renditions in the render table using further toolkit functions. The render table is a shared, reference-counted object: using these routines ensures that the reference associated with a render table is maintained.

Adding Renditions to a Render Table

Rendition objects are merged into a render table using the following routine:

    XmRenderTable
    XmRenderTableAddRenditions (XmRenderTable old_table,
				XmRendition  *new_renditions,
				Cardinal      new_count,
				XmMergeMode   merge_mode)

There is no routine to create a render table which is empty: if a new table is required, it is necessary to create (or share) rendition objects first. In this instance, if old_table is NULL, a new table is created using only the new_renditions supplied as a parameter. Otherwise, the new_renditions are merged into old_table using the merging rule merge_mode to control the process. A newly allocated render table is returned by the routine: the old_table has its reference count internally decremented as a side effect.

If merge_mode is XmMERGE_REPLACE, renditions within the new_renditions array take precedence over similarly tagged renditions which may already exist within the old_table: pre-existing renditions with matching tags are ignored in the returned render table.

If merge_mode is XmMERGE_SKIP, pre-existing renditions in old_table have precedence, and new renditions in the new_renditions array with matching tags are ignored.

If merge_mode is XmMERGE_NEW, renditions in the new_renditions list take priority, except that if they have any attributes marked as XmAS_IS, the value is copied over from any matching pre-existing rendition.

Lastly, if merge_mode is XmMERGE_OLD, pre-existing renditions take priority, except that if any of their attributes are marked as XmAS_IS, the value is copied from the matching new rendition.

Removing Renditions from a Render Table

Renditions can be removed from a render table using the following routine:

	
    XmRenderTable
    XmRenderTableRemoveRenditions (XmRenderTable old_table,
				   XmStringTag  *tags,
				   Cardinal      tag_count)

The routine allocates and returns a new render table, formed out of an existing old_table, ignoring any renditions from the old_table which have a tag matching any in the tags array. The old_table has its reference count internally decremented as a side effect. The routine works more like a filtered copy function than a true removal routine; this implementation is required in order to maintain the reference counting associated with the objects.

Copying a Render Table

A copy of an existing render table can be had through the following routine:

	
    XmRenderTable
    XmRenderTableCopy (XmRenderTable table,
		       XmStringTag  *tags,
		       int           tag_count)

This is a true filtered copy routine: it copies over all renditions in table which have a tag that matches those specified in the tags array. If tags is NULL, all renditions are copied. This routine therefore works in a very similar way to the internal implementation of XmRenderTableRemoveRenditions, except that the tags array is an inclusive rather than an exclusive control. The reference counting is, however, entirely different in effect.

Fetching a Rendition from a Render Table

Given a known tag associated with some rendition object in a render table, that rendition can be fetched using the following routine:

	
    XmRendition
    XmRenderTableGetRendition (XmRenderTable table,
			       XmStringTag   tag)

The routine returns NULL if either the table is empty, or no rendition with the designated tag could be found.

Fetching a set of Renditions from a Render Table

Under the assumption that the rendition tags are known, a set of rendition objects can be fetched from a render table through the following routine:

	
    XmRendition *
    XmRenderTableGetRenditions (XmRenderTable table,
				XmStringTag  *tag,
				Cardinal      tag_count)

The official OSF documentation states that the function returns an allocated array, where renditions are copied into the array at the same index of the matching tag within the tagsarray. For example, if the third tag in tags matches a rendition in the table, the third slot in the returned array will be filled in with the rendition so found, otherwise it will be a NULL slot.

The sources do not match the official documentation, however. Renditions are copied in the order in which they are found, ignoring any slots for which a rendition could not be found. Hence if the first two tags in the tags array refer to non-existing renditions, and the third tag is located, then the first slot in the returned rendition array is filled in with the third rendition, not the third slot.

Memory is reallocated to the size of the returned rendition array: it does not contain memory allocated for exactly tag_count elements, which the OSF would have us believe. Be warned: it is not safe to assume that any given returned rendition is necessarily related to a position in the corresponding tag array.

Since this routine allocates memory, it should be freed at an appropriate point using XtFree().

Fetching the set of Rendition Tags in a Render Table

Some of the above manipulation routines assume that you know the names of the tags associated with the rendition objects in a render table. This is not necessarily the case, and so the following routine can be used to fetch the set of rendition tags for all the renditions in a render table:

	
    int
    XmRenderTableGetTags (XmRenderTable table,
			  XmStringTag **tag_list)

The routine returns the number of renditions in the supplied table. It places the list of tags for the rendition objects into the address specified by the tag_list parameter. The routine allocates space for this, both for each of the tags in the returned array, and for the array itself. It is the responsibility of the programmer to deallocate the utilized space using XtFree() at a suitable point. The following code fragment outlines the basic scheme of operations:

    extern XmRenderTable render_table;
    XmStringTag         *tags;
    int                  tag_count ;
    int                  i ;

    tag_count = XmRenderTableGetTags (render_table, &tags) ;
    ...
    /* Use the tags for whatever reason */
    ...
    /* Free the utilized space */
    for (i = 0 ; i < tag_count ; i++) {
	    XtFree(tags[i]) ;
    }
    /* Free the array */
    XtFree((char *) tags) ;

Freeing a Render Table

Once a render table is no longer required, the table should be deallocated using XmRenderTableFree(). The routine decrements the reference count associated with the render table: it is not actually freed until the reference count reaches zero. It is important to use this routine instead of XtFree() because the table is a shared resource, shared across all the widget contexts where it is applied. The routine is formally specified as follows:

	
    void
    XmRenderTableFree (XmRenderTable table)

Specifying a Widget's Render Table

All widgets which used to support in Motif 1.2 the XmNfontList resource now support an XmNrenderTable equivalent. Using a render table is simply a matter of setting the appropriate resource. The only thing to bear in mind is that the widget SetValues methods increment the reference count on the supplied render table, and so the table can safely be "freed" after applying the table in the last required context. The following code fragment outlines the general scheme of operations:

    extern Widget widget;
    XmRenderTable render_table;

    /* Create the necessary renditions, render tables, etc */
    render_table = XmRenderTableAddRenditions(widget, ...);

    /* Apply the render table to the required widget(s) */
    XtVaSetValues (widget, XmNrenderTable, render_table, NULL);

    /* The widget routines update the render table reference count internally */
    /* Since we are no longer using it ourselves, we decrement the counter    */
    /* We should also decrement the reference of any contained renditions     */
    /* which we also construct for the render table. The example below makes  */
    /* this point more clear.                                                 */
    XmRenderTableFree (render_table);
    ...

The XmStringGenerate routine

Before proceeding into the example code, the only additional routine which needs specifying is the XmStringGenerate() function, which makes obsolete the Motif 1.2 XmStringCreate() routines. This function is aware of the new rendition capability, and it is formally specified as follows:

    XmString
    XmStringGenerate (XtPointer   input,
		      XmStringTag tag,
		      XmTextType  input_type,
		      XmStringTag rendition_tag)

The routine converts the input into a compound string, where input can be ordinary character-based text, or in multi-byte or indeed in wide-character format. Which is the case is specified through the input_type parameter, which should be one of XmCHARSET_TEXT, XmMULTIBYTE_TEXT, or XmWIDECHAR_TEXT. For an ordinary C string, input_type will be the value XmCHARSET_TEXT.

The tag parameter allows the programmer to associate a name with the created compound string; if tag is NULL, the default is XmFONTLIST_DEFAULT_TAG.

The rendition_tag parameter associates the compound string with a particular named rendition: in effect, the compound string is placed within XmSTRING_COMPONENT_RENDITION_BEGIN and XmSTRING_COMPONENT_RENDITION_END string segments, which are new in Motif 2.0 and later. If the rendition_tag is NULL, the compound string will match against any rendition with the tag _MOTIF_DEFAULT_LOCALE. This is the default tag for a rendition object. Furthermore, compound strings with the default tag XmFONTLIST_DEFAULT_TAG also match against rendition objects with the tag _MOTIF_DEFAULT_LOCALE.

There are a number of new compound string utilities and features available in Motif 2.0 and later, and these will be covered in a further topic at a later date. For the purposes of this paper, XmStringGenerate() is all that we require.

An Example

The following code example creates a multi-colored, multi-font List. Multi-column aspects of rendition are covered in the later sections on the XmTabList object. The widget hierarchy in the example is extremely simple: a SessionShell, a RowColumn, and a Motif ScrolledList.

    /* colored_list.c: illustrates the basic features of
    ** render tables and renditions by creating a
    ** multi-font, multi-color List widget.
    */

In order to see the full source code listing (in a new window) click here. To then save the code in a file use 'Save As' from the 'File' menu of that window.

The output from the program is as given in the following figure:

Tab Lists

An XmTabList is the means whereby Motif achieves a multi-column layout of compound strings. The XmTabList is an opaque data type: it represents an ordered set of XmTab objects. Each XmTab object represents an offset across the screen. The offset may be either at an absolute coordinate, or relative to the previous tab setting. The XmTab object, which describes a single tab stop, is described first.

The way it works is as follows: inside each compound string there can be a segment of type XmSTRING_COMPONENT_TAB. This segment is a new type in Motif 2.0 and later: it informs the toolkit that any following text segment in the compound string needs to be drawn with respect to tab stop information. The XmTabList associated with the current render table provides this tab stop data to the rendering process. The first XmTab in the current tab list is associated with the first XmSTRING_COMPONENT_TAB component in the compound string, the second XmTab controls the location of text after the second XmSTRING_COMPONENT_TAB segment, and so forth.

In other words, the actual location of the tabs (the column start locations) is separate from the column request embedded in the compound string itself: it is deduced from the current render table for the widget where the compound string is to be rendered.

The XmTab Object

Like the XmRendition object, the XmTab object is a kind of pseudo-widget. It is a free-standing, reference counted object which can be shared across multiple tab lists. The interface to the XmTab object is rather less like a widget than the XmRendition object, however: it does not support a resource-style programming interface, but rather the attributes must be fetched and set through specific parameters to specific routines.

Creating a Tab Object

An XmTab object is created through the following routine:

    XmTab
    XmTabCreate (float  value,
		 unsigned char units,
		 XmOffsetModel offset_model,
		 unsigned char alignment,
		 char *        decimal)

The value parameter specifies an offset across the widget, expressed in terms of units. units may be one of the following:

    XmPIXELS              XmCENTIMETERS
    Xm100TH_MILLIMETERS   XmMILLIMETERS
    Xm1000TH_INCHES       XmINCHES
    Xm100TH_FONT_UNITS    XmFONT_UNITS
    Xm100TH_POINTS        XmPOINTS

The offset_model specifies whether this tab object is at an absolute value across the current widget (XmABSOLUTE), or whether this tab is calculated relative to the previous tab in the current tab list (XmRELATIVE).

The alignment resource is supposed to specify how text is aligned within the current column; at present, only XmALIGNMENT_BEGINNING has effect.

The decimal parameter is supposed to be an indicator of the multi-byte character in the current locale to be used as a decimal point. Again, this is not fully implemented.

As an example, the following code creates two tab stops, one at an absolute value from the start of the (as yet unspecified) widget, the second at a relative position to the first tab stop (under the assumption that they are subsequently inserted into an XmTabList in this order:

    XmTab tabA;
    XmTab tabB;

    tabA = XmTabCreate ((float) 1.5, XmINCHES, XmABSOLUTE, XmALIGNMENT_BEGINNING, ".") ;
    ...
    tabB = XmTabCreate ((float) 1.0, XmINCHES, XmRELATIVE, XmALIGNMENT_BEGINNING, ".") ;
    ...

Querying the Attributes of a Tab

The attributes of an XmTab object can be queried using the following toolkit routine:

    float
    XmTabGetValues (XmTab   tab,
		    unsigned char *units,
		    XmOffsetModel *offset_model,
		    unsigned char *alignment,
		    char **        decimal)

For example, the following code fragment queries all the attributes of an unspecified tab object:

    extern XmTab  tab;

    float         value ;
    unsigned char units ;
    XmOffsetModel offset_model ;
    unsigned char alignment ;
    char          *decimal ;

    value = XmTabGetValues (tab, &units, &offset_model, &alignment, &decimal) ;

Unusually for a Motif convenience function, the routine does not return allocated memory at the decimal address, but sets the pointer directly into data within the tab object. You should therefore not manipulate this data, but treat it as strictly read-only in case the address space of the object is corrupted.

Setting the Tab Value

Only the value of an XmTab object may be modified once it has been created. The offset model, alignment, decimal character, and so forth are all create-only attributes. The following routine exists for changing the size of the offset within the parameters laid down by the initial tab creation state: the supplied value is constrained such that it is positive, otherwise a warning message is displayed by the toolkit:

    void
    XmTabSetValue (XmTab tab, float value)

It follows that once a tab has been specified as an absolute stop, it cannot be turned into a relative one. If this is what is required, the tab must be removed entirely from the current tab list, and a new tab with the requisite attributes must be inserted in its place. How to manipulate tabs in a tab list is described shortly.

Freeing an XmTab Object

XmTabCreate() allocates dynamic memory. It is the responsibility of the programmer to reclaim the space at an appropriate point using the following routine:

    void
    XmTabFree (XmTab tab)

The XmTabList Object

An XmTabList is an ordered set of XmTab objects. However, just as an XmRenderTable is not just an array of XmRendition objects, an XmTabList is more than an array of XmTabs. The XmTabList is a distinct, opaque data type which must be manipulated using the convenience routines provided for the purpose.

Adding Tabs to a Tab List

The routine XmTabListInsertTabs() inserts tabs into a tab list at specified positions. It can also be used to create a new tab list. The routine is formally specified as follows:

    XmTabList
    XmTabListInsertTabs (XmTabList old_list,
			 XmTab    *new_tabs,
			 Cardinal  new_count,
			 int       position)

The head of the list is at position zero: specifying a position of zero therefore prepends the new_tabs into the old_list, the position 1 places the new tabs after the first existing tab, and so forth. If old_list is NULL, a new XmTabList is formed out of the supplied tabs.

If position is negative, the tabs are inserted in reverse order at the end of the tab list.

In all cases, the routine allocates and returns a new tab list. The following code example is the simple case of creating two new XmTab objects, and forming a new XmTabList out of the objects:

    XmTabList tablist;
    XmTab     tabs[2];

    tabs[0] = XmTabCreate ((float) 1.5, XmINCHES, XmABSOLUTE, XmALIGNMENT_BEGINNING, ".") ;
    tabs[1] = XmTabCreate ((float) 1.0, XmINCHES, XmRELATIVE, XmALIGNMENT_BEGINNING, ".") ;

    tablist = XmTabListInsertTabs (NULL, tabs, XtNumber(tabs), 0) ;

Removing Tabs from a Tab List

Tabs are removed from a Tab List by specifying a list of indexes (positions) where the tabs are to be excised. The routine to do this is XmTabListRemoveTabs(), which is formally specified as follows:

    XmTabList
    XmTabListRemoveTabs (XmTabList old_list,
			 Cardinal *positions,
			 Cardinal  position_count)

Positions are, as in the case of inserting tabs, indexed from zero. The following code therefore removes the first, third, and fifth tabs from an unspecified tab list:

    extern XmTabList tablist;
    Cardinal         positions[3];
    XmTabList        new_tablist;

    positions[0] = 0 ; /* The first item is at position zero */
    positions[1] = 2 ; /* The third item is at position two  */
    positions[2] = 4 ; /* The fifth item is at position four */

    new_tablist = XmTabListRemoveTabs (tablist, positions, 3);

Replacing Tabs in a Tab List

Tabs are replaced within a Tab List by specifying a range of positions. The routine XmTabListReplacePositions() is used to perform this task, and is defined as follows:

    XmTabList
    XmTabListReplacePositions (XmTabList tablist,
			       Cardinal *position_list,
			       XmTab    *new_tabs,
			       Cardinal  new_tab_count)

The routine returns a newly allocated tab list, except that it replaces the tabs at the positions specified by the position_list parameter with the set of new XmTab objects in new_tabs. The number of positions in position_list and the number of tabs in tab_list must match. For example, the following code replaces the second and forth tabs with two newly created XmTab objects. As usual with XmTabLists, positions are indexed from zero.

    extern XmTabList old_tablist;
    XmTab            tabs[2];
    Cardinal         positions[2];
    XmTabList        new_tablist;

    positions[0] = 1; /* Second tab is at position 1 */
    positions[1] = 3; /* Fourth tab is at position 3 */

    tabs[0] = XmTabCreate ((float) 1.5, XmINCHES, XmABSOLUTE, XmALIGNMENT_BEGINNING, ".") ;
    tabs[1] = XmTabCreate ((float) 1.0, XmINCHES, XmRELATIVE, XmALIGNMENT_BEGINNING, ".") ;

    new_tablist = XmTabListReplacePositions (old_tablist, positions, tabs, XtNumber (tabs)) ;

Counting Tabs in a Tab List

The number of XmTab objects in an XmTabList can be retrieved easily enough: it is performed using the routine XmTabListTabCount(), defined thus:

    int
    XmTabListTabCount (XmTabList tablist)

Copying a Tab List

An XmTabList can be selectively copied using the routine XmTabListCopy(). The routine is defined as follows:

    XmTabList
    XmTabListCopy (XmTabList tablist,
		   int       offset,
		   Cardinal  count)

The offset parameter specifies an index into the tablist from which to start copying. If offset is zero, tabs are copied from the start of the tablist. If offset is negative, tabs are copied in reverse order from the end of the tablist. The number of tabs to copy is given by the count parameter: if this is zero, all tabs are copied from the given tab list.

Note that the current O'Reilly Volume 6B for Motif 2.1, Motif Reference Manual, lists this routine erroneously as XmTabListTabCopy(). Humble Apologies!.

Retrieving a Tab from a Tab List

The routine XmTabListGetTab() can be used to fetch an XmTab object from a tab list, if the position of the object is known. The routine is formally specified as follows:

    XmTab
    XmTabListGetTab (XmTabList tablist,
		     Cardinal  position)

Freeing a Tab List

When an XmTabList object is no longer required by the application, it should be deallocated using the routine XmTabListFree(). It is important to use this routine instead of XtFree() because the tab list is a shared resource, shared across all the render table contexts where it is applied. The routine maintains internal reference counts, and ensures that the object is not freed until the reference count is zero. XmTabListFree() is formally specified as follows:

    void
    XmTabListFree (XmTabList tablist)

Using a TabList in a Render Table

Using a Tab List involves a few short steps. We simply specify the tab list as the XmNtabList attribute of some rendition object, place the rendition object into a render table, and apply the render table to the widget which we want to appear in multi-column format. For example:

    XmTabList   tablist;
    Arg         args;
    Cardinal    n;
    XmRendition rendition;

    ...
    /* Construct some XmTab objects and insert into a new tablist */
    tablist = XmTabListInsertTabs (NULL, ...);

    /* Specify the tablist as an attribute of a rendition object */
    ...
    XtSetArg (args[n], XmNtabList, tablist); n++;
    rendition = XmRenditionCreate (widget, "my_tag", args, n);
    ...
    /* Add the rendition to a render table, and apply to the widget */
    ...

The example below does just this. It creates a single tablist, and applies it to the first rendition in a render table, thus ensuring that all renditions further down the list inherit the same tab stop information, because by default the value of their XmNtabList is XmAS_IS.

Another Example

The following code example extends upon the previous render table code program: it creates a multi-column, multi-font, multi-color List:

    /* columnar_list.c: illustrates all the features of
    ** render tables and renditions by creating a
    ** multi-column, multi-font, multi-color List widget.
    */

In order to see the full source code listing (in a new window) click here. To then save the code in a file use 'Save As' from the 'File' menu of that window.

The output from the program is as given in the following figure:



Sponsored by X-Designer - The Leading X/Motif GUI Builder - Click to download a FREE evaluation

 

Goto top of page

 

[IST Limited]
IST Limited is the
proud sponsor of motifdeveloper.com.
 

Thanks to all the contributors to these pages.

Privacy Policy

 
"Motif" is a registered trademark of The Open Group. All other trademarks are the property of their respective owners.

Some articles/papers here have their own copyright notice. All other information is copyright ©1999-2008 IST Limited

[CommerceOne] MW3 site originally by Ken Sall of Commerce One (formerly Century Computing).