/* $TOG: String.c /main/10 1997/04/16 10:00:15 dbl $ */ /* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * 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 /* private header file for the XmPrimitive widget */ #include /* header file for MB_CUR_MAX */ #include /* private header file for the ExmString widget */ #include /* header file for representation type facility */ #include /* header file for installing traits */ #include /* header file for AccessTextual trait */ #include /* header file for XmLABEL_RENDER_TABLE */ #include /* header file for screen information */ #include /* 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[] = ": PrimitiveEnter()\n\ : PrimitiveLeave()\n\ :osfActivate: PrimitiveParentActivate()\n\ :osfCancel: PrimitiveParentCancel()\n\ :osfHelp: PrimitiveHelp()\n\ ~s ~m ~a 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)); }