Complex Text Layout (CTL) extensions enable Motif APIs to support writing systems that require complex transformations between logical and physical text representations, such as Arabic, Hebrew, and Thai. CTL Motif provides character shaping, such as ligatures, diacritics, and segment ordering, and supports the transformation of static and dynamic text widgets. It also supports right-to-left and left-to-right text orientation and tabbing for dynamic text widgets. Since text rendering is handled through the rendition layer, other widget libraries can be easily extended to support CTL.
To leverage the new features, users must have the Portable Layout Services (PLS) library and the appropriate language engine. CTL uses PLS as the interface to the language engine, and uses the language engine to transform text before it is rendered. Applications that support CTL must include additional resources as described in the CTL documentation.
Specifically, XmCTL supports the following complex language shaping and reordering features provided by underlying locale-dependent PLS module transformations:
The CTL architecture is organized as shown in the diagram below. Dt Apps at the top of the stack employs Motif CTL functionality for rendering text. Motif in turn interfaces with locale-specific language engines using PLS and performs transformations to support positional variation, numeral shaping, and so on.
The CTL architecture is built to support new languages by simply adding a new locale-specific engine. In other words, support for Thai and Vietnamese can be added without altering Motif or Dt Apps.
The XmNlayoutDirection resource [See section 11.3 of the Motif Programmer's Guide (Release 2.1) for an overview of XmNlayoutDirection, and especially for a description of the interaction between XmStringDirection and XmNlayoutDirection.] controls object layout. It interacts with the orientation value of the LayoutObject in the following manner.
First, when XmNlayoutDirection is specified as XmDEFAULT_DIRECTION, then the widget's layout direction is set at creation time from the governing pseudo-XOC. In the case of dynamic text (XmText and XmTextField), the governing pseudo-XOC is the one that is associated with the XmRendition used for the widget. In the case of static text (XmList, XmLabel, XmLabelG), the layout direction is set from the first compound string component that specifies a direction. This specification happens in one of two ways:
Directly, if the component is of type XmSTRING_COMPONENT_LAYOUT_PUSH or XmSTRING_COMPONENT_DIRECTION
Indirectly, if the component is of type XmSTRING_COMPONENT_LOCALE_TEXT, XmSTRING_COMPONENT_WIDECHAR_TEXT, or XmSTRING_COMPONENT_TEXT, from the component's associated XmRendition's associated LayoutObject.
Second, if XmNlayoutDirection is not specified as XmDEFAULT_DIRECTION, and the XmNlayoutModifier @ls orientation value is not specified explicitly in the layout modifier string, then the XmNlayoutDirection value is passed through to the XOC and its LayoutObject.
If both XmNlayoutDirection and the XmNlayoutModifier @ls orientation value are explicitly specified, then the behavior is mixed; the XmNlayoutDirection controls widget object layout, and the XmNlayoutModifier @ls orientation value controls layout transformations.
For more information, see CAE Specification: Portable Layout Services: Context-dependent and Directional Text, The Open Group: Feb 1997; ISBN 1-85912-142-X; document number C616.
XmStringDirection is the data type used to specify the direction in which the system displays characters of a string.
The XmNlayoutDirection resource sets a default rendering direction for any compound string (XmString) that does not have a component specifying the direction of that string. Therefore, to set the layout direction, all that is required is to set the appropriate value for the XmNlayoutDirection resource. It is not required that you create compound strings with specific direction components. When the application renders an XmString, it should look to see if the string was created with an explicit direction( XmStringDirection). If there is no direction component, the application should check the value of the XmNlayoutDirection resource for the current widget and use that value as the default rendering direction for the XmString.
See also XmRendition and XmDirection.
CTL adds the following new pseudo resources to XmRendition:
Name |
Class/Type |
Access |
Default Value |
---|---|---|---|
XmNfontType |
XmCFontType/XmFontType |
CSG |
XmAS_IS |
XmNlayoutAttrObject |
XmClayoutAttrObject/String |
CG |
NULL |
XmNlayoutModifier |
XmCLayoutModifier/String |
CSG |
NULL |
Specifies the type of the Rendition font object. For CTL, the value of this resource must be the XmFONT_IS_XOC value. If it is not, then the XmNlayoutAttrObject and XmNlayoutModifier resources are ignored.
When the value of this resource is XmFont_IS_XOC, and if the XmNfont resource is not specified, then at create time the value of the XmNfontName resource gets converted into an XOC object in either the locale specified by the XmNlayoutAttrObject resource or the current locale. Furthermore, the value of the XmNlayoutModifier resource gets passed through to any LayoutObject associated with the XOC.
Specifies the layout AttrObject argument to be used to create the Layout Object associated with the XOC associated with this XmRendition. Refer to the Layout Services m_create_layout() specification for the syntax and semantics of this string. (See the description of XmNfontType above for an explanation of the interaction between the Layout Modifier Orientation output value and the XmNlayoutDirection widget resource.)
Specifies the layout values to be passed through to the Layout Object associated with the XOC associated with this XmRendition. For the syntax and semantics of this string, see CAE Specification.
Setting this resource using XmRendition{Retrieve,Update} causes the string to be passed through to the LayoutObject associated with the XOC associated with this Rendition. This is the mechanism for configuring layout services dynamically. Note that unpredictable behavior may result if the Orientation, Context, TypeOfText, TextShaping, or ShapeCharset are changed.
The XmNlayoutModifier affects the layout behavior of the text associated with the XmRendition. For example, if the layout default treatment of numerals is NUMERALS_NOMINAL, the user can change to NUMERALS_NATIONAL by setting XmNlayoutModifier to:
The layout values can be classified into the following groups:
Encoding description: TypeOfText, TextShaping, ShapeCharset (and locale codeset)
TypeOfText is essentially segment ordering, and can be illustrated with opaque blocks. It is usually not meaningful to modify these values dynamically through the Rendition object, and almost certain to result in unpredictable behavior.
Layout behavior: Orientation, Context, ImplicitAlg, Swapping, Numerals
Orientation and Context should not be modified dynamically; it is safe to modify ImplicitAlg, Swapping, and Numerals.
Xm CTL extends XmText and XmTextField by adding a parallel set of movement and deletion actions that operate visually, patterned after the Motif 2.0 CSText widget. The standard Motif 2.1 Text and TextField do not distinguish between logical and physical order: "next" and "forward" mean "to the right," and "previous" and "backward" mean "to the left." CSText, however, makes the proper distinction and defines a new set of actions with strictly physical names (for example, left-character(), delete-right-word(), and so on). All of these action routines are defined to be sensitive to the XmNlayoutDirection of the widget and to call the appropriate "next-" or "previous-" action. The Xm CTL extensions are slightly more complex than CSText's in that they are sensitive not to the global orientation of the widget, but to the specific directionality of the physical characters surrounding the cursor, as determined by the pseudo-XOC (including neutral stabilization).
There is also a new resource to control selection policy, to provide a rendition tag, and to control alignment.
The set of new Xm CTL actions is roughly the cross product of {Move,Delete,Kill} by {Left,Right} by {Character,Word}, and is listed below.
The following new resources are added to XmText and XmTextField:
Name |
Class/Type |
Access |
Default Value |
---|---|---|---|
XmNrenditionTag |
XmCRenditionTag/XmRString |
CSG |
XmFONTLIST_DEFAULT_TAG |
XmNalignment |
XmCAlignment/XmRAlignment |
CSG |
XmALIGNMENT_BEGINNING |
XmNeditPolicy |
XmCEditPolicy/XmREditPolicy |
CSG |
XmEDIT_LOGICAL |
Specifies the rendition tag of the XmRendition (in the XmNrenderTable resource) to be used for this widget.
Specifies the text alignment to be used in the widget. Only XmALIGNMENT_END and XmALIGNMENT_CENTER are supported.
Specifies the editing policy to be used for the widget, either XmEDIT_LOGICAL or XmEDIT_VISUAL. In the case of XmEDIT_VISUAL, selection, cursor movement, and deletion are in a visual style. Setting this resource also changes the translations for the standard keyboard movement and deletion events either to the new "visual" actions list below or to the existing logical actions.
All of the actions in the following list query the orientation of the character in the direction specified. If the direction is left-to-right, they call the corresponding next-/forward- or previous-/backward- variants.
delete-left-character()
delete-left-word()
delete-right-character()
delete-right-word()
kill-left-character()
kill-left-word()
kill-right-character()
kill-right-word()
left-character()
left-word()
prev-cell()
right-character()
right-word()
forward-cell()
The actions determine the orientation of characters by using the Layout Services transformation OutToInp and Property buffers (for the nesting level). The widget's behavior is therefore dependent on the locale-specific transformation. If the information in the OutToInp or, especially, Property buffers is inaccurate, the widget may behave unexpectedly. Moreover, as the locale-specific modules fall outside of the scope of this specification, bi-directional editing behavior may differ from platform to platform for the same text, application, resource values, and LayoutObject configuration.
The visual mode actions result in display cell-based behavior. The logical mode actions result in logical character-based behavior. For example, the delete-right-character() operation deletes the input buffer characters that correspond to the display cell (that is, one input buffer character whole LayoutObject transformation "property" byte "new cell indicator" is 1, and all of the succeeding characters whose "new cell indicator" [For more information on the Property buffer, see the specification for m_transform_layout() in CAE Specification.] is 0).
Similarly, for backward-character(), the insertion point is moved backward one character in the input buffer, and the cursor is redrawn at the visual location corresponding to the associated output buffer character. This means that several keystrokes are required to move across a composite display cell; the cursor does not actually change display location as the insertion point moves across input buffer characters whose "new cell indicator" is 0 (that is, diacritics or ligature fragments).
This means deletion operates either from the logical/input buffer side, or from the display cell level of the physical/output side. There is no mode for a strict, physical character-by-character deletion, since there is no one-to-one correspondence between the input and output buffers. A given physical character may represent only a fragment of a logical character, for example.
The XmText action routines are as follows:
If the XmNeditPolicy is XmEDIT_LOGICAL and is called without arguments, it moves the insertion cursor back logically by a character. If the insertion cursor is at the beginning of the line, it moves the insertion cursor to the logical last character of the previous line if one exists, otherwise the insertion cursor position doesn't change.
If the XmNeditPolicy is XmEDIT_VISUAL, then the cursor moves to the left of cursor position. If the insertion cursor is at the beginning of the line, then it moves to the end character of the previous line if one exists.
If it is called with an extend argument, it moves the insertion cursor as in the case of no argument and extends the current selection.
The left-character() action produces calls to the XmNmotionVerifyCallback procedures with the reason value XmCR_MOVING_INSERT_CURSOR. If called with an extend argument, this may produce calls to the XmNgainPrimaryCallback procedures. See the callback description in the Motif Programmer's Reference for more information.
If the XmNeditPolicy is XmEDIT_LOGICAL and is called without any arguments, and the insertion cursor is at the logical starting of the word, it moves the insertion cursor to the logical starting of the logical preceding word, if one exists, otherwise the insertion cursor position doesn't change. If the insertion cursor is in the word but not at the logical start of the word, it moves the insertion cursor to the logical start of the word. If the insertion cursor is at the logical start of the line, it moves the insertion cursor to the logical start of the logical last word in the previous line if one exists, otherwise the insertion cursor position doesn't change.
If the XmNeditPolicy is XmEDIT_VISUAL and is called without arguments, it moves the insertion cursor to the first non-white space character after the first white space character to the left or after the beginning of the line. If the insertion cursor is already at the beginning of the word, it moves the insertion cursor to the beginning of the previous word. If the insertion cursor is already at the beginning of the line, it moves to the starting of the last word in the previous line.
If called with an argument of extend, it moves the insertion cursor as in the case of no argument and extends the current selection.
The left-word() action produces calls to the XmNmotionVerifyCallback procedures with the reason value XmCR_MOVING_INSERT_CURSOR. If it is called with an extend argument, this may produce calls to the XmNgainPrimaryCallback procedures. See the callback description in the Motif Programmer's Reference for more information.
If the XmNeditPolicy is XmEDIT_LOGICAL and is called without any arguments, it moves the insertion cursor logically forward by a character. If the insertion cursor is at the logical end of the line, it moves the insertion cursor to the logical starting of the next line, if one exists.
If the XmNeditPolicy is XmEDIT_VISUAL, then the cursor moves to the right of cursor position. If the insertion cursor is at the end of the line, it moves the insertion cursor to the starting of the next line, if one exists.
If called with an argument of extend, it moves the insertion cursor as in the case of no argument and extends the current selection.
The right-character() action produces calls to the XmNmotionVerifyCallback procedures with the reason value XmCR_MOVING_INSERT_CURSOR. If called with extend argument, this may produce calls to the XmNgainPrimaryCallback procedures. See the callback description in the Motif Programmer's Reference for more information.
If the XmNeditPolicy is XmEDIT_LOGICAL and is called without any arguments, it moves the insertion cursor to the logical starting of the logical succeeding word if one exists, otherwise it moves to the logical end of the current word. If the insertion cursor is at the logical end of the line or in the logical last word of the line, it moves the cursor to the logical first word in the next line if one exists, otherwise it moves to the logical end of the current word.
If the XmNeditPolicy is XmEDIT_VISUAL and is called without arguments, it moves the insertion cursor to the first nonwhite space character after the first white space character to the right or after the end of the line.
If called with an argument of extend, it moves the insertion cursor as in the case of no argument and extends the current selection.
The left-word() action produces calls to the XmNmotionVerifyCallback procedures with the reason value XmCR_MOVING_INSERT_CURSOR. If called with extend argument, this may produce calls to the XmNgainPrimaryCallback procedures. See the callback description in the Motif Programmer's Reference for more information.
If the XmNeditPolicy is XmEDIT_LOGICAL, it is equivalent to delete-previous-char. If the XmNeditPolicy is XmEDIT_VISUAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise it deletes the character left of the insertion cursor. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection and XmNpendingDelete is set to True, it deletes the selection; otherwise it deletes the character left of the insertion cursor. This may impact the selection.
The delete-left-character() action produces calls to the XmNmodifyVerifyCallback procedures with reason value XmCR_MODIFYING_TEXT_VALUE and the XmNvalueChangedCallback procedures with reason value XmCR_VALUE_CHANGED.
If the XmNeditPolicy is XmEDIT_VISUAL, it is equivalent to delete-next-character. If the XmNeditPolicy is XmEDIT_VISUAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise, it deletes the character right of the insertion cursor. In add mode, if there is a non-null selection and the cursor is not disjointed from the selection, the XmNpendingDelete is set to True and the selection is deleted; otherwise, the character right of the insertion cursor is deleted. This may impact the selection.
The delete-right-character() action produces calls to the XmNmodifyVerify- Callback procedures with reason value XmCR_MODIFYING_TEXT_VALUE, and the XmNvalue- ChangedCallback procedures with reason value XmCR_VALUE_CHANGED.
If the XmNeditPolicy is XmEDIT_VISUAL, it is equivalent to delete-prev-word(). If the XmNeditPolicy is XmEDIT_LOGICAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise, it deletes the characters left of the insertion cursor to the next space, punctuation character, tab, or beginning-of-line character. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection; otherwise it deletes the characters left of the insertion cursor the right space, tab, or beginning-of-line character. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection, the XmNpendingDelete is set to True, and the selection is deleted; otherwise, it deletes the character left of the insertion cursor, the right space, tab, or beginning of new-line character. This may impact the selection.
If the XmNeditPolicy is XmEDIT_VISUAL, it is equivalent to delete-right-word(). If the XmNeditPolicy is XmEDIT_LOGICAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise, it deletes the characters right of the insertion cursor to the next space, punctuation character, tab, or end-of-line character. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection, XmNpendingDelete is set to True, and deletes the selection; otherwise, it deletes the characters right of the insertion cursor to the next space, tab, or end-of-line character. This may impact the selection.
If the XmNeditPolicy is XmEDIT_LOGICAL, it is equivalent to kill-prev-char. If the XmNeditPolicy is XmEDIT_VISUAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise, it kills the character left of the insertion cursor and stores the character in the cut buffer. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection, XmNpendingDelete is set to True, and deletes the selection; otherwise, it deletes the character left of the insertion cursor. This may impact the selection.
The kill-left-character() action produces calls to the XmNmodifyVerifyCallback procedures with the reason value XmCR_MODIFYING_TEXT_VALUE, and produces the XmNvalueChangedCallback procedures with the reason value XmCR_VALUE_CHANGED.
If the XmNeditPolicy is XmEDIT_VISUAL, it is equivalent to delete-next-character. If the XmNeditPolicy is XmEDIT_VISUAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise, it deletes the character right of the insertion cursor and stores it in the cut buffer. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection, the XmNpendingDelete is set to True and deletes the selection; otherwise, it deletes the character right of the insertion cursor. This may impact the selection.
The kill-right-character() action produces calls to the XmNmodifyVerify-Callback procedures with reason value XmCR_MODIFYING_TEXT_VALUE, and produces calls to the XmNvalue-ChangedCallback procedures with reason value XmCR_VALUE_CHANGED.
If the XmNeditPolicy is XmEDIT_VISUAL, it is equivalent to delete-prev-word(). If the XmNeditPolicy is XmEDIT_LOGICAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise, it deletes the characters left of the insertion cursor to the next space, punctuation character, tab, or beginning-of-line character. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection; otherwise it deletes the characters left of the insertion cursor the right space, tab, or beginning-of-line character and stores it in the cut buffer. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection, XmNpendingDelete is set to True and deletes the selection; otherwise it deletes the characters left of the insertion cursor the right space, tab, or beginning of new-line character. This may impact the selection.
If the XmNeditPolicy is XmEDIT_VISUAL, it is equivalent to delete-right-word(). If the XmNeditPolicy is XmEDIT_LOGICAL, then in normal mode, if there is a non-null selection, it deletes the selection; otherwise, it deletes the characters right of the insertion cursor to the next space, tab, or end-of-line character. In add mode, if there is a non-null selection, the cursor is not disjointed from the selection, XmNpendingDelete is set to True, and deletes the selection; otherwise, it deletes the characters right of the insertion cursor to the next space, punctuation character, tab, or end-of-line character and stores in the cut buffer. This may impact the selection.
A few cell-based routines are implemented to support character composition, ligatures, and diacritics. In other words, two or more characters might be represented by a single glyph occupying one presentation cell.
The XmText cell action routines are as follows:
Moves the insertion cursor back one cell. If the XmNeditPolicy is XmEDIT_LOGICAL, then the insertion cursor is moved to the start of the cell that precedes the current cell logically, if one exists; otherwise it moves to the start of the current cell.
If the XmNeditPolicy is XmEDIT_VISUAL, then the cursor moves to the start of cell to the left of the cursor, if one exists. The prev-cell() action produces calls to the XmNmotionVerifyCallback procedures with the reason value XmCR_MOVING_INSERT_CURSOR. If called with an extend argument, this may produce calls to the XmNgainPrimaryCallback procedures. See the callback description in the Motif Programmer's Reference for more information.
Moves the insertion cursor to the start of the logical next cell, if one exists; otherwise it moves it to the end of the cell. If the XmNeditPolicy is XmEDIT_LOGICAL, then the cursor moves forward one cell.
If the XmNeditPolicy is XmEDIT_VISUAL, then the cursor moves to the start of the cell to the right of the cursor position if one exits; otherwise it moves to the end of the current cell. The forward-cell() action produces calls to the XmNmotionVerifyCallback procedures with the reason value XmCR_MOVING_INSERT_CURSOR. If called with an extend argument, this may produce calls to the XmNgainPrimaryCallback procedures. See the callback description in the Motif Programmer's Reference for more information.
A TextField function that returns the layout modifier string that reflects the state of the layout object tied to its rendition.
#include <Xm/TextF.h>String XmTextFieldGetLayoutModifier(Widget widget)
XmTextFieldGetLayoutModifier accesses the value of the current layout object settings of the rendition associated with the widget. When the layout object modifier values are changed using a convenience function, the XmTextFieldGetLayoutModifier function returns the complete state of the layout object, not just the changed values.
Returns the layout object modifier values in the form of a String value.
A Text function that returns the layout modifier string that reflects the state of the layout object tied to its rendition.
#include <Xm/Text.h>String XmTextGetLayoutModifier(Widget widget)
XmTextGetLayoutModifier accesses the value of the current layout object settings of the rendition associated with the widget. When the layout object modifier values are changed using a convenience function, the XmTextGetLayoutModifier function returns the complete state of the layout object, not just the changed values.
Returns the layout object modifier values in the form of a String value.
XmText
A TextField function that sets the layout modifier values, which changes the behavior of the layout object tied to its rendition.
#include <Xm/TextF.h>void XmTextFieldSetLayoutModifier(Widget widget, string layout_modifier)
XmTextFieldSetLayoutModifier modifies the layout object settings of a rendition associated with the widget. When the layout object modifier values are set using this convenience function, only the attributes specified in the input parameter are changed; the rest of the attributes are left untouched.
XmTextField
A Text function that sets the layout modifier values, which changes the behavior of the layout object tied to its rendition.
#include <Xm/Text.h>void XmTextSetLayoutModifier(Widget widget, string layout_modifier)
XmTextSetLayoutModifier modifies the layout object settings of a rendition associated with the widget. When the layout object modifier values are set using this convenience function, only the attributes specified in the input parameter are changed; the rest of the attributes are left untouched.
XmText
#include <Xm/Xm.h>XmString XmStringDirectionCreate(direction)XmStringDirectiondirection
XmStringDirectionCreate creates a compound string with a single component, a direction with the given value. On the other hand, the XmNlayoutDirection resource sets a default rendering direction for any compound string (XmString) that does not have a component specifying the direction for that string. Therefore, to set the layout direction, all that is required is to set the appropriate value for the XmNlayoutDirection resource. It is not required to create compound strings with specific direction components. When the application renders an XmString, it should look to see if the string was created with an explicit direction (XmStringDirection). If there is no direction component, the application should check the value of the XmNlayoutDirection resource for the current widget and use that value as the default rendering direction for the XmString.
See also XmRendition, XmDirection.
UIL Argument Name |
Argument Type |
---|---|
XmNlayoutAttrObject |
String |
XmNlayoutModifier |
String |
XmNrenditionTag |
String |
XmNalignment |
Integer |
XmNeditPolicy |
Integer |
The direction of a compound string is stored so that the data structure will be equally useful for describing text in left-to-right languages such as English, Spanish, French, and German, as well as for text in right-to-left languages, such as Hebrew and Arabic. In Motif applications, you can set the layout direction using the XmNlayoutDirection resource from the VendorShell or MenuShell. Manager and Primitive widgets (as well as Gadgets) also have an XmNlayoutDirection resource. The default value is inherited from the closest ancestor that has the same resource.
In the case of an XmText widget, you need to specify the vertical direction as well. Setting the layoutDirection to XmRIGHT_TO_LEFT will result in the string direction from right-to-left, but the cursor will move vertically down. If the vertical direction is important and top to bottom is desired, be sure to specify XmRIGHT_TO_LEFT_TOP_TO_BOTTOM, which specifies that the components are laid out from right-to-left first and then top-to-bottom, and will result in the desired behavior.
Furthermore, the behavior of XmText and TextField widgets is influenced by the XmNalignment and XmNlayoutModifier resources of the XmRendition. These resources, in addition to XmNlayoutDirection, control the layout behavior of the Text widget. This can be illustrated using the example below.
The input string used in the illustration is
The XmNlayoutModifier string @ls orientation= setting values for this illustration are shown in the left column.
As the illustration shows, XmNAlignment dictates whether the text is flush-right or -left in conjunction with the layout direction. On the other hand, XmNlayoutModifier breaks the text into segments and arranges them left-to-right or right-to-left depending on the orientation value. In other words, if the XmNlayoutDirection is XmRIGHT_TO_LEFT, and the XmNAlignment value is XmALIGNMENT_BEGINNING, the string is flush-right.
The following code creates an XmLabel whose XmNlabelString is of the type XmCHARSET_TEXT, using the Rendition whose tag is "ArabicShaped." The Rendition is created with an XmNlayoutAttrObject of "ar" (corresponding to the locale name for the Arabic locale) and a layout modifier string that specifies for the output buffer a Numerals value of NUMERALS_CONTEXTUAL and a ShapeCharset value of "unicode-1."
The locale-specific layout module transforms its input text (in this example encoded in ISO 8859-6) in an output buffer of physical characters encoded using the 16-bit Unicode 2.0 codeset. Since an explicit layout locale has been specified, this text is rendered properly independent of the runtime locale setting.
int n; Arg args[10]; Widget w; XmString labelString; XmRendition rendition; XmStringTag renditionTag; XmRenderTable renderTable; /* alef lam baa noon taa - iso8859-6 */ labelString = XmStringGenerate("\307\344\310\346\312\", NULL XmCHARSET_TEXT, "ArabicShaped"); w = XtVaCreateManagedWidget("a label", xmLabelWidgetClass, parent, XmNlabelString, labelString, XmNlabelType, XmSTRING, NULL); n = 0; XtSetArg(args[n], XmNfontName, "-*-*-medium-r-normal-*-24-*-*-*-*-*-*-*"); n++; XtSetArg(args[n], XmNfontType, XmFONT_IS_XOC); n++; XtSetArg(args[n], XmNlayoutAttrObject, "ar"); n++; XtSetArg(args[n], XmNlayoutModifier, "@ls numerals=:contextual, shapecharset=iso8859-6"); n++; renditionTag = (XmStringTag) "ArabicShaped"; rendition = XmRenditionCreate(w, renditionTag, argcs s, n); renderTable = XmRenderTableAddRenditions(NULL, &rendition, 1, XmREPLACE_MERGE); XtVaSetValues(w, XmNrenderTable, renderTable, NULL);
The following code creates a TextField widget and a RenderTable with a single Rendition. Note that both the XmNlayoutAttrObject and XmNlayoutModifier pseudo resources have been left unspecified and therefore defaults to NULL. This means the LayoutObject associated with the Rendition is the default locale's, if one exists.
For this example to work properly, the locale must be set to one whose codeset is ISO 8859-6 and whose locale-specific layout module can support the IMPLICIT_BASIC algorithm. It then modifies the Rendition's LayoutObject's ImplicitAlg value via the Rendition's XmNlayoutModifier pseudo resource.
int n; Arg args[10]; Widget w; XmRendition rendition; XmStringTag renditionTag; XmRenderTable renderTable; w = XmCreateTextField(parent, "text field", args, 0); n = 0; XtSetArg(args[n], XmNfontName, "-*-*-medium-r-normal-*-24-*-*-*-*-*-*-*"); n++; XtSetArg(args[n], XmNfontType, XmFONT_IS_XOC); n++; renditionTag = (XmStringTag) "ArabicShaped"; rendition = XmRenditionCreate(w, renditionTag, args, n); renderTable = XmRenderTableAddRenditions(NULL, &rendition, 1, XmREPLACE_MERGE); XtVaSetValues(w, XmNrenderTable, renderTable, NULL); .... n = 0; XtSetArg(args[n], XmNlayoutModifier, "@ls implicitalg=basic"); n++; XmRenditionUpdate(rendition, args, n);
See also XmDirection, XmText.
Renditions and render tables may be specified in resource files. For properly internationalized application, in fact, this is the preferred method. When the render tables are specified in a file, the program binaries are made independent of the particular needs of a given locale, and may be easily customized to local needs.
Render tables are specified in resource files with the following syntax: resource_spec:[tag[,tag]*]
where tag is some string suitable for the XmNtag resource of a rendition.
This line creates an initial render table containing one or more renditions as specified. The renditions are attached to the specified tags
resource_spec[*|.] rendition[*|.]resource_name:value
The following examples illustrate the CTL resources related to XmRendition that can be set using resource files. The fontType must be set to FONT_IS_XOC for the layout object to take effect. The layoutModifier specified using @ls is passed on to the layout object by the rendition object.
For a complete list of resources that can be set on the layout object using layoutModifier, see CAE Specification: Portable Layout Services: Context-dependent and Directional Text, The Open Group: Feb 1997; ISBN 1-85912-142-X; document number C616.
Before creating a render table, an application program must first have created at least one of the renditions that is part of the table. The XmRenderTableAddRenditions function, as its name implies, is also used to augment a render table with new renditions. To create a new render table, call the XmRenderTableAddRenditions() function with a NULL argument in place of an existing render table.
The following code creates a render table using a rendition created with XmNfontType set to XmFONT_IS_XOC.
int n; Arg args[10]; Widget w; XmString labelString; XmRendition rendition; XmStringTag renditionTag; XmRenderTable renderTable; /* alef lam baa noon taa - iso8859-6 */ labelString = XmStringGenerate("\307\344\310\346\312\", NULL XmCHARSET_TEXT, "ArabicShaped"); w = XtVaCreateManagedWidget("a label", xmLabelWidgetClass, parent, XmNlabelString, labelString, XmNlabelType, XmSTRING, NULL); n = 0; XtSetArg(args[n], XmNfontName, "-*-*-medium-r-normal-*-24-*-*-*-*-*-*-*"); n++; XtSetArg(args[n], XmNfontType, XmFONT_IS_XOC); n++; XtSetArg(args[n], XmNlayoutAttrObject, "ar"); n++; XtSetArg(args[n], XmNlayoutModifier, "@ls numerals=nominal:contextual, shapecharset=iso8859-6"); n++; renditionTag = (XmStringTag) "ArabicShaped"; rendition = XmRenditionCreate(w, renditionTag, args, n); renderTable = XmRenderTableAddRenditions(NULL, &rendition, 1, XmREPLACE); XtVaSetValues(w, XmNrenderTable, renderTable, NULL);
To control the placement of text, a compound string can contain tab characters. To interpret those characters on display, a widget refers to the rendition in effect for that compound string, where it finds a list of tab stops. However, the dynamic widgets (TextField and XmText) do not use the tab resource of the rendition. Instead, they compute the tab width using the formula of 8*(width of character 0).
The tab measurement is the distance from the left margin of the compound string display, or from the right margin if the layout direction is right-to-left. It is important to note that regardless of the direction of the text (Arabic right-to-left or English left-to-right) the tab inserts space to the right or left as specified by the layout direction (XmNlayoutDirection).
The text following a tab is always aligned at the tab stop, and the tab stop is calculated from the start of the widget, which in turn is influenced by XmNlayoutDirection. The behavior of the tabs and their interaction with directionality of the text and the XmNlayoutDirection of the widget is illustrated in Table 10-1.
The input for this illustration is abc\tdef\tgh.
The user makes a primary selection with SELECT (the left mouse button). Pressing SELECT deselects any existing selection and moves the insertion cursor and the anchor to the position in the text where the button is pressed. Dragging SELECT selects all text between the anchor and the pointer position, deselecting any text outside the range.
The text selected is influenced by the resource XmNeditPolicy, which can be set to XmEDIT_LOGICAL or XmEDIT_VISUAL. If the XmNeditPolicy is set to XmEDIT_LOGICAL, and if the text selected is bi-directional, the selected text is not be contiguous visually and is a collection of segments. This is because the text in the logical buffer does not have a one-to-one correspondence with the display.
As a result, the contiguous buffer of logical characters of bi-directional text when rendered does not result in a continuous stream of characters. Conversely, when the XmNeditPolicy is set to XmEDIT_VISUAL, the text selected may be contiguous visually but is segmented in the logical buffer. So the sequence of selection, deletion, and insertion of bi-directional text at the same cursor point does not result in the same string.
The selection operation available with the mouse is also available with the keyboard. The combination of Shift-arrow keys allows the selection of text.
The text selected is influenced by the resource XmNeditPolicy, which can be set to XmEDIT_LOGICAL or XmEDIT_VISUAL. If the XmNeditPolicy is set to XmEDIT_LOGICAL, and if the text selected is bi-directional, the selected text will not be contiguous visually and will be a collection of segments. This is because the text in the logical buffer does not have one-to-one correspondence with the display. As a result, the contiguous buffer of logical characters of bi-directional text when rendered will not result in a continuous stream of characters.
Conversely, when the XmNeditPolicy is set to XmEDIT_VISUAL, the text selected may be contiguous visually but is segmented in the logical buffer. So the sequence of selection, deletion, and insertion of bi-directional text at the same cursor point does not result in the same string.
Text has several resources that relate to geometry, including the following:
The render table XmNrenderTable that the widget uses to select a font or font set and other attributes in which to display the text.
The Text and Textfield widgets can use only the font-related rendition resources, such as XmNfontType, and can also specify the attributes of the layout object, such as XmNlayoutAttrObject, usually a locale identifier, and XmNlayoutModifier, which specifies the layout values to be passed through to the Layout Object associated with the XOC associated with this XmRendition.
A resource (XmNwordWrap) that specifies whether lines are broken at word boundaries when the text would be wider than the widget.
Breaking a line at a word boundary does not insert a new line into the text. In the case of cursive languages like Arabic, if the word length is greater than the widget length, the word is wrapped to the next line, but the first character in the next line is shaped independently of the previous character in the logical buffer.
The new CTL enabled Motif library can be found in /usr/dt/lib/libXm.so.4. If your application links to libXm.so.3 (ldd app_name shows which library the application is linking to), then it will not support Complex Text Layout (CTL). In order to port the existing applications to enable CTL, you need to perform the following steps.
Add -DSUN_CTL to your Makefile. This flag is important and includes the necessary data structures to support CTL. This should be set during compilation.
Recompile the existing application. It will automatically link with the CTL enabled Motif library libXm.so.4.
Add the following resources to your application resource file. Without these resources the layout engine of the locale will not launch.
Refer to the sample application attached with your documentation.
Use the font name that is available and appropriate to your locale in the fontName resource.
If you want the cell-based character movement (Thai) in XmTextField or XmText widgets, set the translations of the corresponding widgets as follows. Refer to the documentation for further detailed explanation.
XmText.translations: #override \n\
<Key>osfRight:forward-cell() \n\
<Key>osfLeft:backward-cell() \n\
<Key>osfDelete:delete-next-cell() \n\
<Key>osfBackSpace:delete-previous-cell() \n\