/* $TOG: String.c /main/10 1997/04/16 10:00:15 dbl $ */
/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* HISTORY
*/
/************************************ WARNING **********************************
*
* ExmString is a demonstration widget. OSF provides this widget
* solely to teach programmers how to write their own Motif widgets.
* OSF does not support this widget in any way
************************************ WARNING *********************************/
/*******************************************************************************
*
* String.c - ExmString widget. This widget renders a compound string.
* The ExmString widget demonstrates how to work with strings
* in Motif widgets. Functionally, the widget is similar to
* XmLabel, except that XmLabel can render both pixmaps and
* compound strings. The ExmString widget manipulates the
* resources and traits used by other Motif string-oriented
* widgets. See the "OSF/Motif Widget Writer's Guide" for details.
*
******************************************************************************/
/* Include appropriate header files. */
#include <Xm/XmP.h> /* private header file for the XmPrimitive widget */
#include <Xm/XmosP.h> /* header file for MB_CUR_MAX */
#include <Exm/StringP.h> /* private header file for the ExmString widget */
#include <Xm/RepType.h> /* header file for representation type facility */
#include <Xm/TraitP.h> /* header file for installing traits */
#include <Xm/AccTextT.h> /* header file for AccessTextual trait */
#include <Xm/SpecRenderT.h> /* header file for XmLABEL_RENDER_TABLE */
#include <Xm/Screen.h> /* header file for screen information */
#include <Xm/DrawP.h> /* header file for Draw routines */
/* Declare all static functions. */
static void DefaultFont (
Widget w,
int offset,
XrmValue *value
);
static void GetValuesCompoundString(
Widget w,
int resource,
XtArgVal *value);
static void ClassInitialize(void);
static void ClassPartInitialize(
WidgetClass widgetclass);
static void Initialize(
Widget request_w,
Widget new_w,
ArgList args,
Cardinal *num_args );
static void Destroy (
Widget w );
static void Resize (
Widget w );
static void AlignmentDirection(
Widget w );
static Boolean SetValues (
Widget old_w,
Widget request_w,
Widget new_w,
ArgList args,
Cardinal *num_args );
static XtGeometryResult QueryGeometry (
Widget w,
XtWidgetGeometry *request,
XtWidgetGeometry *reply);
static void DrawVisual (
Widget w );
static void CalcVisualSize (
Widget w );
static void CreateGC (
Widget w );
static Boolean WidgetBaselines (
Widget w,
Dimension **baselines,
int *line_count);
static Boolean WidgetDisplayRect (
Widget w,
XRectangle *displayrect);
static void StringSetValue(
Widget w,
XtPointer s,
int format);
static XtPointer StringGetValue(
Widget w,
int format);
static int StringPreferredFormat(
Widget w);
/* Define constants here. */
static XmConst int FIND_NATURAL_SIZE = 0;
#define UNSUPPORTED_FORMAT "Someone is trying to get or set a value for \n\
ExmNcompoundString; however, the specified format is undefined.\n"
/* Define the translations string for the ExmString widget.
All six actions will be handled by the XmPrimitive widget. */
static char defaultTranslations[] =
"<EnterWindow>: PrimitiveEnter()\n\
<LeaveWindow>: PrimitiveLeave()\n\
:<Key>osfActivate: PrimitiveParentActivate()\n\
:<Key>osfCancel: PrimitiveParentCancel()\n\
:<Key>osfHelp: PrimitiveHelp()\n\
~s ~m ~a <Key>Return: PrimitiveParentActivate()";
/* No actions array needed. */
/* Define the resources for the ExmString widget. */
static XtResource resources[] =
{
{
XmNtraversalOn,
XmCTraversalOn,
XmRBoolean,
sizeof (Boolean),
XtOffsetOf( XmPrimitiveRec, primitive.traversal_on),
XmRImmediate,
(XtPointer) False /* override the default. */
},
{
ExmNcompoundString,
ExmCCompoundString,
XmRXmString,
sizeof(XmString),
XtOffsetOf( ExmStringRec,string.compound_string),
XmRImmediate,
(XtPointer) NULL
},
{
XmNrenderTable,
XmCRenderTable,
XmRRenderTable,
sizeof(XmRenderTable),
XtOffsetOf( ExmStringRec,string.render_table),
XtRCallProc,
(XtPointer) DefaultFont
},
{
XmNalignment,
XmCAlignment,
XmRAlignment,
sizeof(unsigned char),
XtOffsetOf( ExmStringRec,string.alignment),
XmRImmediate,
(XtPointer) XmALIGNMENT_CENTER
},
{
XmNrecomputeSize,
XmCRecomputeSize,
XmRBoolean,
sizeof(Boolean),
XtOffsetOf( ExmStringRec,string.recompute_size),
XmRImmediate,
(XtPointer) True
},
};
/* Provide a synthetic resource for ExmNcompoundString. */
static XmSyntheticResource syn_resources[] =
{
{
ExmNcompoundString,
sizeof(XmString),
XtOffsetOf(ExmStringRec, string.compound_string),
GetValuesCompoundString,
NULL
}
};
/* Here is the primitive class extension record. */
static XmPrimitiveClassExtRec primClassExtRec = {
/* next_extension */ NULL,
/* record_type */ NULLQUARK,
/* version */ XmPrimitiveClassExtVersion,
/* record_size */ sizeof(XmPrimitiveClassExtRec),
/* widget_baseline */ WidgetBaselines,
/* widget_display_rect */ WidgetDisplayRect,
/* widget_margins */ NULL,
};
externaldef (exmstringclassrec) ExmStringClassRec exmStringClassRec = {
{
/* superclass */ (WidgetClass)&exmSimpleClassRec,
/* class_name */ "ExmString",
/* widget_size */ sizeof(ExmStringRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize */ ClassPartInitialize,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ XtExposeCompressMaximal,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resize,
/* expose */ XtInheritExpose,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ QueryGeometry,
/* display_accelerator */ NULL,
/* extension */ NULL,
},
{ /* XmPrimitive */
/* border_highlight */ XmInheritBorderHighlight,
/* border_unhighlight */ XmInheritBorderUnhighlight,
/* translations */ XtInheritTranslations,
/* arm_and_activate */ NULL,
/* syn_resources */ syn_resources,
/* num_syn_resources */ XtNumber(syn_resources),
/* extension */ (XtPointer)&primClassExtRec,
},
{ /* ExmSimple */
/* draw_visual */ DrawVisual,
/* draw_shadow */ ExmInheritDrawShadow,
/* create_text_gc */ CreateGC,
/* destroy_text_gc */ ExmInheritDestroyGC,
/* select_text_gc */ ExmInheritSelectGC,
/* calc_visual_size */ CalcVisualSize,
/* calc_widget_size */ ExmInheritCalcWidgetSize,
/* reconfigure */ ExmInheritReconfigure,
/* extension */ NULL,
},
{ /* ExmString */
/* default_render_table_type */ XmLABEL_RENDER_TABLE,
/* extension */ NULL,
}
};
/* Establish the widget class name as an externally accessible symbol.
Use the "externaldef" macro for OS-independent global definitions. */
externaldef( exmstringwidgetclass) WidgetClass exmStringWidgetClass =
(WidgetClass) &exmStringClassRec;
/* Define static representation type variables here. */
static XmRepTypeId alignmentId;
/* Define trait structure variables here. */
/* Since ExmString displays a primary parcel of text, the ExmString
widget must install the XmQTaccessTextual trait. The following
declaration is of a trait structure variable named StringATT. */
static XmConst XmAccessTextualTraitRec StringATT = {
0, /* version */
StringGetValue,
StringSetValue,
StringPreferredFormat,
};
/*******************************************************************************
*
* DefaultFont:
* Called by the Intrinsics to establish a default value for the
* XmNrenderTable resource.
*
******************************************************************************/
static void
DefaultFont (
Widget w,
int offset,
XrmValue *value
)
{
ExmStringWidgetClass wc = (ExmStringWidgetClass)XtClass(w);
static XmRenderTable f1;
/* Find the default render table associated with the default
render table type. */
f1 = XmeGetDefaultRenderTable (w,
wc->string_class.default_render_table_type);
value->addr = (XtPointer)&f1;
value->size = sizeof(f1);
}
/************************************************************************
*
* GetValuesCompoundString
* This is a synthetic resource function called by Motif when
* an application calls XtGetValues to access the value of
* ExmNcompoundString.
*
***********************************************************************/
/*ARGSUSED*/
static void
GetValuesCompoundString(
Widget w,
int resource, /* unused */
XtArgVal *value)
{
ExmStringWidget sw = (ExmStringWidget) w;
XmString string;
/* All Motif widgets are responsible for making a copy of an XmString
resource whenever an application accesses the resource through a call
to XtGetValues. */
string = XmStringCopy(sw->string.compound_string);
*value = (XtArgVal) string;
}
/*******************************************************************************
*
* ClassInitialize
* Called by the Intrinsics the first time a widget of this class is
* instantiated.
*
******************************************************************************/
static void
ClassInitialize(void)
{
/* Use existing Motif representation types for XmNalignment. */
alignmentId = XmRepTypeGetId (XmRAlignment);
if (alignmentId == XmREP_TYPE_INVALID)
XmeWarning(NULL, "The value of XmNalignment is illegal.");
}
/************************************************************************
*
* ClassPartInitialize
* Called by the Intrinsics when this widget or a subclass of this
* widget is instantiated.
*
************************************************************************/
static void
ClassPartInitialize(
WidgetClass widgetclass )
{
/* Install the XmQTaccessTextual trait on the ExmString class and all
its subclasses. */
XmeTraitSet((XtPointer) widgetclass, XmQTaccessTextual,
(XtPointer) &StringATT);
}
/*******************************************************************************
*
* Initialize
* Called when this widget is instantiated.
*
******************************************************************************/
static void
Initialize (
Widget request_w,
Widget new_w,
ArgList args,
Cardinal *num_args
)
{
ExmStringWidgetClass wc = (ExmStringWidgetClass)XtClass(new_w);
ExmStringWidget nw = (ExmStringWidget)new_w;
unsigned char stringDirection;
Arg dirArgs[1];
/* Copy the compound string and render table. */
nw->string.compound_string = XmStringCopy(nw->string.compound_string);
nw->string.render_table = XmRenderTableCopy(nw->string.render_table,
NULL, 0);
/* Validate XmNalignment */
if (!XmRepTypeValidValue (alignmentId, nw->string.alignment, (Widget)nw))
nw->string.alignment = XmALIGNMENT_CENTER;
/* If the XmNstringDirection resource is set to XmSTRING_DIRECTION_DEFAULT,
then we need to figure out what the default string direction is.
If the parent is a manager, then we'll set the string direction of
ExmString to the string direction of the manager. */
AlignmentDirection((Widget)nw);
if (wc->simple_class.calc_visual_size)
(*(wc->simple_class.calc_visual_size))(new_w);
if (wc->simple_class.reconfigure)
(*(wc->simple_class.reconfigure))(exmStringWidgetClass, new_w, NULL);
}
/*******************************************************************************
*
* Destroy
* Called by the Intrinsics whenever this widget is deallocated.
*
******************************************************************************/
static void
Destroy (
Widget w
)
{
ExmStringWidget sw = (ExmStringWidget)w;
/* Free the memory used to hold the ExmNcompound_string and
XmNrenderTable resource values. */
if (sw->string.compound_string != NULL)
XmStringFree (sw->string.compound_string);
if (sw->string.render_table != NULL)
XmRenderTableFree (sw->string.render_table);
}
/*******************************************************************************
*
* Resize
*
******************************************************************************/
static void
Resize (
Widget w
)
{
ExmStringWidget sw = (ExmStringWidget)w;
Dimension mw, mh;
Dimension window_decoration_thickness;
/* Configure internal geometry using current size */
if ((sw->simple.visual.width == FIND_NATURAL_SIZE) ||
(sw->simple.visual.height == FIND_NATURAL_SIZE))
return;
window_decoration_thickness = sw->primitive.highlight_thickness +
sw->primitive.shadow_thickness;
/* Determine where the string's bounding box should start. */
/* First determine the X coordinate of the bounding box. */
mw = window_decoration_thickness + sw->simple.margin_width;
switch (sw->string.text_starts_here)
{
case ExmSTART_STRING_LEFT_SIDE :
sw->simple.visual.x = mw;
break;
case ExmSTART_STRING_RIGHT_SIDE :
sw->simple.visual.x = sw->core.width - (mw + sw->simple.visual.width +
window_decoration_thickness);
break;
case ExmCENTER_STRING :
sw->simple.visual.x = ((int)(sw->core.width - sw->simple.visual.width))/2;
break;
};
/* Now do the same for the vertical dimension. */
mh = window_decoration_thickness + sw->simple.margin_height;
/* If the widget has enough vertical space to display all the lines in
the string, then center the string. */
if ((int)sw->core.height >
(int)((2 * window_decoration_thickness) + sw->simple.visual.height)) {
sw->simple.visual.y = ((int)(sw->core.height - sw->simple.visual.height))/2;
}
else if ((int)sw->core.height > ((int)(2 * window_decoration_thickness))) {
/* Space is very tight. We will eliminate the top margin altogether and
start the first line of the compound string snug against the bottom of
the top edge of the window decorations. */
sw->simple.visual.y = window_decoration_thickness;
}
else
/* Space is so tight that we do not have enough space to display even
one pixel of the visual. */
sw->simple.visual.y = window_decoration_thickness;
}
/*******************************************************************************
*
* AlignmentDirection:
* Called by Initialize and by SetValues.
*
******************************************************************************/
static void
AlignmentDirection(
Widget w
)
{
ExmStringWidget sw = (ExmStringWidget)w;
/* This method determines where the text starts. The text could
* be centered.
* start at the left side of the widget.
* start at the right side of the widget.
*/
if (sw->string.alignment == XmALIGNMENT_CENTER)
/* The string will be centered. */
sw->string.text_starts_here = ExmCENTER_STRING;
else if (
(XmDirectionMatch(sw->primitive.layout_direction, XmLEFT_TO_RIGHT) &&
sw->string.alignment == XmALIGNMENT_BEGINNING)
||
(XmDirectionMatch(sw->primitive.layout_direction, XmRIGHT_TO_LEFT) &&
sw->string.alignment == XmALIGNMENT_END)
)
/* The string will start at the left side of the widget. */
sw->string.text_starts_here = ExmSTART_STRING_LEFT_SIDE;
else if (
(XmDirectionMatch(sw->primitive.layout_direction, XmLEFT_TO_RIGHT) &&
sw->string.alignment == XmALIGNMENT_END)
||
(XmDirectionMatch(sw->primitive.layout_direction, XmRIGHT_TO_LEFT) &&
sw->string.alignment == XmALIGNMENT_BEGINNING)
)
/* The string will start at the right side of the widget. */
sw->string.text_starts_here = ExmSTART_STRING_RIGHT_SIDE;
}
/*******************************************************************************
*
* SetValues
*
******************************************************************************/
static Boolean
SetValues (
Widget old_w,
Widget request_w,
Widget new_w,
ArgList args,
Cardinal *num_args
)
{
ExmStringWidgetClass wc = (ExmStringWidgetClass)XtClass(new_w);
ExmStringWidget cw = (ExmStringWidget)old_w;
ExmStringWidget nw = (ExmStringWidget)new_w;
Boolean redisplayFlag = False;
/* Copy ExmNcompoundString if its value has changed */
if (nw->string.compound_string != cw->string.compound_string) {
nw->string.compound_string = XmStringCopy(nw->string.compound_string);
XmStringFree(cw->string.compound_string);
cw->string.compound_string = (XmString) NULL;
nw->simple.need_to_reconfigure = True;
}
/* Update XmNcompound_string whenever XmNrenderTable changes */
if (nw->string.render_table != cw->string.render_table) {
nw->string.render_table = XmRenderTableCopy(nw->string.render_table,
NULL, 0);
XmRenderTableFree (cw->string.render_table);
cw->string.render_table = (XmRenderTable) NULL;
nw->simple.need_to_reconfigure = True;
}
/* Validate any changes to the value of the XmNalignment resource.
If the requested new value is not valid, then reset the value of the
XmNalignment resource to the old value. */
if (nw->string.alignment != cw->string.alignment) {
if (!XmRepTypeValidValue(alignmentId, nw->string.alignment, (Widget)nw))
nw->string.alignment = cw->string.alignment;
else nw->simple.need_to_reconfigure = True;
}
/* If the XmNrecomputeSize resource used to be False but is now True, then
we will have to set in motion the series of calls that will lead to
an appropriate resize of the widget. */
if ((nw->string.recompute_size == True) &&
(cw->string.recompute_size == False)) {
nw->simple.need_to_reconfigure = True;
if (nw->core.width == cw->core.width)
nw->core.width = FIND_NATURAL_SIZE;
if (nw->core.height == cw->core.height)
nw->core.height = FIND_NATURAL_SIZE;
}
/* If the Alignment has changed or the layout direction has changed,
then the widget needs to determine a new starting position for
the bounding text box. */
if ( nw->string.alignment != cw->string.alignment ||
nw->primitive.layout_direction != cw->primitive.layout_direction)
AlignmentDirection((Widget)nw);
/* Determine whether or not the widget needs to be reconfigured. Just
about any change to a resource will necessitate a reconfiguration.
If the widget does need to be reconfigured, call Reconfigure. */
if (nw->simple.need_to_reconfigure == True) {
if (wc->simple_class.reconfigure)
(*(wc->simple_class.reconfigure))(exmStringWidgetClass, new_w, old_w);
redisplayFlag = True;
}
return (redisplayFlag);
}
/*******************************************************************************
*
* QueryGeometry
* Called by the Intrinsics in response to a proposed changed in geometry.
*
******************************************************************************/
static XtGeometryResult
QueryGeometry(
Widget w,
XtWidgetGeometry *request,
XtWidgetGeometry *reply )
{
ExmStringWidgetClass swc = (ExmStringWidgetClass)XtClass(w);
ExmStringWidget sw = (ExmStringWidget) w ;
if (!XtIsRealized(w)) {
/* Widget has not been realized yet. */
reply->width = XtWidth(w); /* might be 0 */
reply->height = XtHeight(w); /* might be 0 */
} else {
if (sw->string.recompute_size) {
/* The user will allow the ExmString widget to change size, so
let's call CalcWidgetSize to calculate the widget's
preferred size. */
int save_w, save_h;
save_w = XtWidth(w);
save_h = XtHeight(w);
if (swc->simple_class.calc_widget_size)
(*(swc->simple_class.calc_widget_size))((Widget)sw);
sw -> simple.pref_width = XtWidth(w);
sw -> simple.pref_height = XtHeight(w);
XtWidth(w) = save_w;
XtHeight(w) = save_h;
}
reply->width = sw -> simple.pref_width;
reply->height = sw -> simple.pref_height;
}
/* Return our preferred size */
return XmeReplyToQueryGeometry(w, request, reply);
}
/*******************************************************************************
*
* DrawVisual
*
******************************************************************************/
static void
DrawVisual (
Widget w
)
{
ExmStringWidgetClass wc = (ExmStringWidgetClass)XtClass(w);
ExmStringWidget sw = (ExmStringWidget)w;
/* If the compound string is not NULL and if there is enough space in the
widget to draw at least a little portion of the compound string, then
render the string with XmStringDraw. */
if (sw->string.compound_string &&
(sw->simple.visual.width != 0) &&
(sw->simple.visual.height != 0)) {
XmStringDraw (XtDisplay(sw), XtWindow(sw),
sw->string.render_table,
sw->string.compound_string,
wc->simple_class.select_gc(w),
sw->simple.visual.x, sw->simple.visual.y,
sw->simple.visual.width, sw->string.alignment,
sw->primitive.layout_direction, NULL);
XmeClearBorder(XtDisplay(sw), XtWindow(sw),
(int)0, (int)0,
(Dimension)sw->core.width, (Dimension)sw->core.height,
(Dimension)(sw->primitive.highlight_thickness +
sw->primitive.shadow_thickness)
);
}
}
/*******************************************************************************
*
* CreateGC:
* Called by the Initialize method of the base class (ExmSimple).
*
******************************************************************************/
static void
CreateGC (
Widget w
)
{
ExmStringWidget sw = (ExmStringWidget)w;
XGCValues values;
XtGCMask valueMask;
XFontStruct *fs = (XFontStruct *) NULL;
Arg args[2];
Pixmap insensitiveStippleBitmap;
/* This function creates two GC's: one to render a sensitive widget
and the other to render an insensitive widget. */
/* First, create the sensitive GC (named normal_gc). */
valueMask = GCForeground | GCBackground | GCGraphicsExposures;
values.foreground = sw->primitive.foreground;
values.background = sw->core.background_pixel;
values.graphics_exposures = False;
/* In order to set the GCFont field of the GC, we must gather XFontStruct
information out of the render table. This is only to get a reasonable
initial value. XmStringDraw will pick the necessary fonts from the
render table, so we will not need to update the GC when the render
table changes. */
if (XmeRenderTableGetDefaultFont(sw->string.render_table, &fs)) {
values.font = fs->fid;
valueMask |= GCFont;
}
sw->simple.normal_gc = XtGetGC ((Widget)sw, valueMask, &values);
/* Next, create the insensitive GC. This GC will share the same
foreground, background, font, and graphics exposures as the sensitive
GC, but will hold a different fill style and stipple pattern. */
valueMask |= GCFillStyle | GCStipple;
values.fill_style = FillStippled;
/* Gather the Motif-appropriate insensitive stipple bitmap. */
XtSetArg(args[0], XmNinsensitiveStippleBitmap, &insensitiveStippleBitmap);
XtGetValues(XmGetXmScreen(XtScreen(w)), args, 1);
values.stipple = insensitiveStippleBitmap;
sw->simple.insensitive_gc = XtGetGC((Widget) sw, valueMask, &values);
}
/*******************************************************************************
*
* CalcVisualSize
*
******************************************************************************/
static void
CalcVisualSize (
Widget w
)
{
ExmStringWidget sw = (ExmStringWidget)w;
/* Ideally, how much space would the compound string require? */
if (sw->string.compound_string && !XmStringEmpty(sw->string.compound_string))
XmStringExtent (sw->string.render_table, sw->string.compound_string,
&(sw->simple.visual.width), &(sw->simple.visual.height));
else {
/* The string is empty, so it requires no space. */
sw->simple.visual.width = 0;
sw->simple.visual.height = 0;
}
}
/*******************************************************************************
*
* WidgetBaselines:
* Called by manager widgets needing to align text-based visuals.
* This method can also be called directly by an application through
* the XmWidgetGetBaselines function.
*
******************************************************************************/
static Boolean
WidgetBaselines(
Widget w,
Dimension **baselines,
int *line_count)
{
XmStringContext context = NULL;
XmString current_string;
XmString string1 = NULL;
char* text1;
char* text2;
XmStringCharSet char_set1, char_set2;
XmStringDirection direction1, direction2;
/* XmFontList FontList; */
XmRenderTable RenderTable;
Boolean separator1, separator2;
Dimension *base_array;
Dimension Offset;
int index;
ExmStringWidget sw = (ExmStringWidget)w;
/* This function returns True to indicate that the widget is displaying
text, or False to indicate that the widget is not displaying text.
If the widget is displaying text, this function calculates the baseline
of each displayed line of text. */
index = 0;
RenderTable = sw->string.render_table;
/* Initialize the string context. If the XmStringInitContext call returns
False, then no string context could be found which suggests that no
text is being displayed in the widget. */
current_string = sw->string.compound_string;
if (!XmStringInitContext (&context, current_string))
return (False);
/* Determine how many lines are in the displayed string. */
*line_count = XmStringLineCount(current_string);
base_array = (Dimension *)XtMalloc((sizeof(Dimension) * (*line_count)));
/* Offset = ((ExmStringWidget) w)->string.visual.y; */
Offset = sw->simple.visual.y;
/* Go through the compound string, segment by segment. */
while (XmStringGetNextSegment (context, &text1, &char_set1, &direction1,
&separator1)) {
if (string1)
XmStringFree(string1);
string1 = XmStringCreate(text1, char_set1);
XtFree(text1);
if (separator1)
{
while (XmStringPeekNextComponent(context)== XmSTRING_COMPONENT_SEPARATOR) {
XmStringGetNextComponent (context, &text1, &char_set1, &direction1,
NULL, NULL, NULL);
base_array[index++] = Offset + XmStringBaseline (RenderTable, string1);
Offset += XmStringHeight (RenderTable, string1);
}
}
else if (XmStringGetNextSegment (context, &text2, &char_set2, &direction2,
&separator2)) {
XmString string2;
if (separator2)
{
string2 = XmStringCreate(text2, char_set2);
string1 = XmStringConcat(string1, string2);
base_array[index++] = Offset + XmStringBaseline (RenderTable, string1);
Offset += XmStringHeight (RenderTable, string1);
}
else
{
string2 = XmStringCreate(text2, char_set2);
string1 = XmStringConcat(string1, string2);
}
XtFree(text2);
XmStringFree(string2);
XtFree(char_set2);
}
else
{
XtFree(char_set1);
break;
}
XtFree(char_set1);
} /* end of outer while loop */
base_array[index++] = Offset + XmStringBaseline (RenderTable, string1);
XmStringFree(string1);
*baselines = base_array;
XmStringFreeContext(context);
return (True);
}
/*******************************************************************************
*
* WidgetDisplayRect:
* Called by several Motif managers to determine how to align the visuals
* drawn by primitives. In addition, an application can access this
* method by calling XmWidgetGetDisplayRect.
*
******************************************************************************/
static Boolean
WidgetDisplayRect(
Widget w,
XRectangle *displayrect
)
{
ExmStringWidget my_widget = (ExmStringWidget) w;
if ((my_widget->simple.visual.width > 0 &&
my_widget->simple.visual.height > 0)) {
displayrect->x = my_widget->simple.visual.x;
displayrect->y = my_widget->simple.visual.y;
displayrect->width = my_widget->simple.visual.width;
displayrect->height = my_widget->simple.visual.height;
return True; /* Yes, this widget contains something displayable. */
}
else {
return False; /* this widget is not currently displaying a visual. */
}
}
/*******************************************************************************
*
* Trait Methods:
* We now provide the code for the three methods defined by the
* XmQTaccessTextual trait.
*
******************************************************************************/
/*******************************************************************************
*
* StringGetValue: Called by another widget (generally a parent of
* an ExmString). This trait method must return the currently
* displayed text string in the format that the caller requests.
*
******************************************************************************/
static XtPointer
StringGetValue(
Widget w,
int format)
{
ExmStringWidget string_w = (ExmStringWidget) w;
XmString value;
int n;
Arg args[4];
XmParseTable map[2];
XmString separator;
XtPointer result;
XmTextType output_type;
/* Get the string that the ExmString widget is currently displaying. */
value = XmStringCopy(string_w -> string.compound_string);
/* The "value" variable know holds the string in XmString format. */
switch (format) {
case XmFORMAT_XmSTRING:
/* If the caller wants "value" returned as a
compound string, no conversion is necessary. */
return (XtPointer) value;
case XmFORMAT_MBYTE:
case XmFORMAT_WCS:
/* If the caller wants "value" returned as a multibyte string
or as a wide character string, then we have to convert it. */
if (format == XmFORMAT_MBYTE)
output_type = XmMULTIBYTE_TEXT;
else
output_type = XmWIDECHAR_TEXT;
/* Create a very simple parse table consisting of two
parse mappings. */
separator = XmStringSeparatorCreate();
n = 0;
XtSetArg( args[n], XmNpattern, "\n"); n++;
XtSetArg( args[n], XmNpatternType, output_type ); n++;
XtSetArg( args[n], XmNsubstitute, separator ); n++;
XtSetArg( args[n], XmNincludeStatus, XmINSERT ); n++;
map[0] = (XmParseMapping *) XmParseMappingCreate( args, n );
XmStringFree(separator);
separator = XmStringComponentCreate(
XmSTRING_COMPONENT_TAB, 0, NULL);
n = 0;
XtSetArg( args[n], XmNpattern, "\t"); n++;
XtSetArg( args[n], XmNpatternType, output_type ); n++;
XtSetArg( args[n], XmNsubstitute, separator ); n++;
XtSetArg( args[n], XmNincludeStatus, XmINSERT ); n++;
map[1] = (XmParseMapping *) XmParseMappingCreate( args, n );
XmStringFree(separator);
/* Unparse "value" into either MULTIBYTE or WCS format. */
result = XmStringUnparse (value,
(XmStringTag) NULL,
(XmTextType)NULL,
(XmTextType)output_type,
(XmParseTable)map,
XtNumber(map),
XmOUTPUT_ALL);
/* Variable "result" now holds the text of the string in either
MULTIBYTE or WCS format. */
return (XtPointer)result;
default:
XmeWarning((Widget)w, UNSUPPORTED_FORMAT);
return NULL;
}
}
/*******************************************************************************
*
* StringSetValue:
* Called by another widget to set the value of the ExmNcompoundString
* resource.
*
******************************************************************************/
static void
StringSetValue(
Widget w,
XtPointer string,
int format)
{
Arg args[1];
XmString temp;
Boolean freetemp;
int length;
char *str;
wchar_t *str2;
/* The caller will pass a new value for ExmNcompoundString. This new
value will be passed in the "string" argument. However, there is
no guarantee that the input "string" will be passed in XmString format.
If the input "string" is passed in WCS or MULTIBYTE format, then we
must convert the "string" into XmString format. Once the "string"
is in XmString format, we can use it as the new value of
ExmNcompoundString. */
switch (format) {
case XmFORMAT_XmSTRING: temp = (XmString) string;
freetemp = False;
break;
case XmFORMAT_WCS: str2 = (wchar_t *) string;
/* How long is str2? */
length = 0;
while (str2[length] != 0)
length++;
/* malloc enough space to hold str */
str = (char*) XtMalloc(MB_CUR_MAX * (length+1));
wcstombs(str, str2, MB_CUR_MAX * (length+1));
XtFree((char *) string);
string = str;
case XmFORMAT_MBYTE: temp = XmStringCreateLocalized(string);
freetemp = True;
break;
default: XmeWarning((Widget)w, UNSUPPORTED_FORMAT);
return;
}
XtSetArg(args[0], ExmNcompoundString, temp);
XtSetValues(w, args, 1);
if (freetemp)
XmStringFree(temp);
}
/*******************************************************************************
*
* StringPreferredFormat
* Called by another widget to determine the preferred string format of
* this widget. The possible returned formats are:
* * XmFORMAT_XmSTRING (Motif compound string format)
* * XmFORMAT_MBYTE (Multibyte format)
* * XmFORMAT_WCS (Wide character string format)
*
******************************************************************************/
static int
StringPreferredFormat(
Widget w)
{
/* Choose XmFORMAT_XmSTRING because the ExmString widget holds its displayed
text in XmString format (as opposed to Multibyte or WCS format). */
return(XmFORMAT_XmSTRING);
}
/*******************************************************************************
*
* ExmCreateString
* Externally accessable function for creating a String widget
*
******************************************************************************/
Widget
ExmCreateString (
Widget parent,
char *name,
Arg *arglist,
Cardinal argCount
)
{
return (XtCreateWidget(name,exmStringWidgetClass,parent,arglist,argCount));
}