What are Render Tables
and how are they used?
|
4-Dec-00 16:00 GMT
|
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.
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.
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:
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.
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.
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 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.
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.
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.
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.
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.
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.
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().
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) ;
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)
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);
...
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.
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:
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.
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.
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, ".") ;
...
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.
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.
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)
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.
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) ;
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);
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)) ;
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)
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!.
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)
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 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.
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
|