make sure "S" is generated.
[AROS-Contrib.git] / bgui / textclass.c
blobb87be863a0efb339c873cdc305df2b10f1ec137d
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * textclass.c
7 * (C) Copyright 1998 Manuel Lemos.
8 * (C) Copyright 1996-1997 Ian J. Einman.
9 * (C) Copyright 1993-1996 Jaba Development.
10 * (C) Copyright 1993-1996 Jan van den Baard.
11 * All Rights Reserved.
13 * $Log$
14 * Revision 42.7 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.6 2003/01/18 19:10:02 chodorowski
18 * Instead of using the _AROS or __AROS preprocessor symbols, use __AROS__.
20 * Revision 42.5 2001/02/02 21:06:50 stegerg
21 * used TextFit() with strDirection param = 0, but it must be -1 or 1
22 * (autodocs)
24 * Revision 42.4 2001/01/28 04:53:21 bergers
25 * Fixed some compiler complaints (some casts were missing.).
27 * Revision 42.3 2000/08/09 11:45:57 chodorowski
28 * Removed a lot of #ifdefs that disabled the AROS_LIB* macros when not building on AROS. This is now handled in contrib/bgui/include/bgui_compilerspecific.h.
30 * Revision 42.2 2000/05/15 19:27:02 stegerg
31 * another hundreds of REG() macro replacements in func headers/protos.
33 * Revision 42.1 2000/05/14 23:32:48 stegerg
34 * changed over 200 function headers which all use register
35 * parameters (oh boy ...), because the simple REG() macro
36 * doesn't work with AROS. And there are still hundreds
37 * of headers left to be fixed :(
39 * Many of these functions would also work with stack
40 * params, but since i have fixed every single one
41 * I encountered up to now, I guess will have to do
42 * the same for the rest.
44 * Revision 42.0 2000/05/09 22:10:31 mlemos
45 * Bumped to revision 42.0 before handing BGUI to AROS team
47 * Revision 41.11 2000/05/09 19:55:21 mlemos
48 * Merged with the branch Manuel_Lemos_fixes.
50 * Revision 41.10.2.7 1999/08/10 22:38:03 mlemos
51 * Removed comments of escape sequences not implemented.
53 * Revision 41.10.2.6 1999/07/23 19:46:18 mlemos
54 * Added support to set draw mode to JAM1, JAM2 or complement in the text
55 * command sequences.
57 * Revision 41.10.2.5 1998/12/06 22:30:11 mlemos
58 * Fixed bug of using the wrong RastPort to compute XPos of text string.
60 * Revision 41.10.2.4 1998/05/22 03:51:25 mlemos
61 * Added new line characters to the assertion debug messages that warn about
62 * NULL text strings being passed to TotalWidth and TotalHeight.
64 * Revision 41.10.2.3 1998/03/01 18:46:12 mlemos
65 * Fixed short allocation for label text string.
67 * Revision 41.10.2.2 1998/03/01 15:39:39 mlemos
68 * Added support to track BaseInfo memory leaks.
70 * Revision 41.10.2.1 1998/02/28 02:42:26 mlemos
71 * Added debug assert code to trap attempts to pass NULL text pointers to TextHeight and TextWidth functions.
73 * Revision 41.10 1998/02/25 21:13:23 mlemos
74 * Bumping to 41.10
76 * Revision 1.1 1998/02/25 17:09:58 mlemos
77 * Ian sources
82 /// Class definitions.
83 #include "include/classdefs.h"
86 * Object instance data.
88 typedef struct td_ {
89 ULONG td_Flags; /* Flags. */
90 UBYTE *td_Text; /* The text itself. */
91 ULONG td_TextID; /* Text ID. */
92 RAWARG td_Args; /* Arguments for format string. */
93 } TD;
95 #define TEXTF_COPY (1<<0) /* Copy text. */
96 #define TEXTF_COPIED (1<<1) /* This text is a copy. */
98 ///
100 /// Text_Get
102 STATIC UBYTE *Text_Get(TD *td)
104 UBYTE *text;
106 if (td->td_Text && td->td_Args)
108 if ((text = BGUI_AllocPoolMem(CompStrlenF(td->td_Text, td->td_Args))))
110 DoSPrintF(text, td->td_Text, td->td_Args);
111 return text;
113 return NULL;
115 return td->td_Text;
118 /// Text_Clear
120 STATIC VOID Text_Clear(TD *td)
122 if (td->td_Flags & TEXTF_COPIED)
124 BGUI_FreePoolMem(td->td_Text);
125 td->td_Flags &= ~TEXTF_COPIED;
127 td->td_Text = NULL;
130 /// Text_Set
132 static void Text_Set(TD *td, char *text)
134 Text_Clear(td);
136 if (text && (td->td_Flags & TEXTF_COPY))
138 if ((td->td_Text = BGUI_AllocPoolMem(strlen(text)+1)))
140 strcpy(td->td_Text, text);
141 td->td_Flags |= TEXTF_COPIED;
144 else
146 td->td_Text = text;
150 /// OM_NEW
152 * Create a shiny new object.
154 METHOD(TextClassNew, struct opSet *, ops)
156 IPTR rc;
159 * First we let the superclass
160 * create an object.
162 if ((rc = AsmDoSuperMethodA(cl, obj, (Msg)ops)))
165 * Set attributes.
167 AsmCoerceMethod(cl, (Object *)rc, RM_SETM, ops->ops_AttrList, RAF_INITIAL);
169 return rc;
171 METHOD_END
173 /// RM_GETATTRFLAGS
175 * Get the flags of an attribute.
177 METHOD(TextClassGetAttrFlags, struct rmAttr *, ra)
179 static struct TagItem chart[] =
181 { TEXTA_Text, CHART_ATTR(td_, td_Text ) | RAF_CUSTOM | RAF_NOP | RAF_RESIZE, },
182 { TEXTA_TextID, CHART_ATTR(td_, td_TextID ), },
183 { TEXTA_Args, CHART_ATTR(td_, td_Args ) | RAF_RESIZE, },
185 { TEXTA_CopyText, CHART_FLAG(td_, td_Flags, TEXTF_COPY ) | RAF_CUSTOM, },
187 { TAG_DONE },
190 IPTR rc = GetTagData(ra->ra_Attr->ti_Tag, 0, chart);
192 return rc;
194 METHOD_END
196 /// RM_SET
198 * Set standard attributes.
200 METHOD(TextClassSet, struct rmAttr *, ra)
202 return (IPTR)BGUI_SetAttrChart(cl, obj, ra);
204 METHOD_END
206 /// RM_SETCUSTOM
208 * Set custom attributes.
210 METHOD(TextClassSetCustom, struct rmAttr *, ra)
212 TD *td = INST_DATA(cl, obj);
213 Tag attr = ra->ra_Attr->ti_Tag;
214 IPTR data = ra->ra_Attr->ti_Data;
216 switch (attr)
218 case TEXTA_Text:
219 Text_Set(td, (char *)data);
220 break;
222 case TEXTA_CopyText:
223 if (data && !(td->td_Flags & TEXTF_COPIED))
225 Text_Set(td, td->td_Text);
227 break;
229 return (IPTR)TRUE;
231 METHOD_END
233 /// RM_GET
235 * Get an attribute.
237 METHOD(TextClassGet, struct rmAttr *, ra)
239 return (IPTR)BGUI_GetAttrChart(cl, obj, ra);
241 METHOD_END
243 /// RM_GETCUSTOM
245 * Get custom attributes.
247 METHOD(TextClassGetCustom, struct rmAttr *, ra)
249 TD *td = INST_DATA(cl, obj);
250 Tag attr = ra->ra_Attr->ti_Tag;
251 IPTR *store = (IPTR *)ra->ra_Attr->ti_Data;
253 switch (attr)
255 case TEXTA_Text:
256 STORE td->td_Text;
257 break;
259 return (IPTR)TRUE;
261 METHOD_END
263 /// OM_DISPOSE
265 * Dispose of the object.
267 METHOD(TextClassDispose, Msg, msg)
269 TD *td = INST_DATA(cl, obj);
272 * Clear the text.
274 Text_Clear(td);
277 * The rest goes to the superclass.
279 return AsmDoSuperMethodA(cl, obj, msg);
281 METHOD_END
283 /// TEXTM_RENDER
285 * Render a text graphic.
287 METHOD(TextClassRender, struct tmRender *, tmr)
289 TD *td = INST_DATA(cl, obj);
290 UBYTE *text;
292 if ((text = Text_Get(td)))
294 RenderText(tmr->tmr_BInfo, text, tmr->tmr_Bounds);
295 if (td->td_Args) BGUI_FreePoolMem(text);
297 return (IPTR)TRUE;
299 METHOD_END
301 /// TEXTM_DIMENSIONS
303 * Render a text graphic.
305 METHOD(TextClassDimensions, struct tmDimensions *, tmd)
307 TD *td = INST_DATA(cl, obj);
308 UBYTE *text;
310 if ((text = Text_Get(td)))
312 if (tmd->tmd_Extent.Width) *(tmd->tmd_Extent.Width) = TotalWidth (tmd->tmd_RPort, text);
313 if (tmd->tmd_Extent.Height) *(tmd->tmd_Extent.Height) = TotalHeight(tmd->tmd_RPort, text);
315 if (td->td_Args) BGUI_FreePoolMem(text);
317 return (IPTR)TRUE;
319 METHOD_END
321 /// BASE_LOCALIZE
323 METHOD(TextClassLocalize, struct bmLocalize *, bml)
325 TD *td = INST_DATA(cl, obj);
326 ULONG rc = FALSE;
328 if (td->td_TextID)
330 Text_Set(td, BGUI_GetCatalogStr(bml->bml_Locale, td->td_TextID, td->td_Text));
331 rc = TRUE;
333 return (IPTR)rc;
335 METHOD_END
338 /// Class initialization.
341 * Class function table.
343 STATIC DPFUNC ClassFunc[] = {
344 { TEXTM_RENDER, TextClassRender },
345 { TEXTM_DIMENSIONS, TextClassDimensions },
347 { RM_GETATTRFLAGS, TextClassGetAttrFlags },
348 { RM_SET, TextClassSet },
349 { RM_SETCUSTOM, TextClassSetCustom },
350 { RM_GET, TextClassGet },
351 { RM_GETCUSTOM, TextClassGetCustom },
352 { OM_NEW, TextClassNew },
353 { OM_DISPOSE, TextClassDispose },
354 { BASE_LOCALIZE, TextClassLocalize },
355 { DF_END, NULL }
359 * Simple class initialization.
361 makeproto Class *InitTextClass(void)
363 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_ROOT_OBJECT,
364 CLASS_ObjectSize, sizeof(TD),
365 CLASS_DFTable, ClassFunc,
366 TAG_DONE);
376 * Figure out the total text width and height
377 * of an text with info-style command sequences.
379 #ifdef __AROS__
380 makearosproto
381 AROS_LH4(VOID, BGUI_InfoTextSize,
382 AROS_LHA(struct RastPort *, rp, A0),
383 AROS_LHA(UBYTE *, text, A1),
384 AROS_LHA(UWORD *, wi, A2),
385 AROS_LHA(UWORD *, wh, A3),
386 struct Library *, BGUIBase, 18, BGUI)
387 #else
388 makeproto SAVEDS ASM VOID BGUI_InfoTextSize(REG(a0) struct RastPort *rp, REG(a1) UBYTE *text, REG(a2) UWORD *wi, REG(a3) UWORD *wh)
389 #endif
391 AROS_LIBFUNC_INIT
393 if (wi) *wi = TotalWidth( rp, text);
394 if (wh) *wh = TotalHeight(rp, text);
396 AROS_LIBFUNC_EXIT
400 * Render the text with info-style command sequences
401 * inside the bounding box. Text is automatically
402 * trucated when out of bounds.
404 #ifdef __AROS__
405 makearosproto
406 AROS_LH4(VOID, BGUI_InfoText,
407 AROS_LHA(struct RastPort *, rp, A0),
408 AROS_LHA(UBYTE *, text, A1),
409 AROS_LHA(struct IBox *, bounds, A2),
410 AROS_LHA(struct DrawInfo *, dri, A3),
411 struct Library *, BGUIBase, 19, BGUI)
412 #else
413 makeproto SAVEDS ASM VOID BGUI_InfoText( REG(a0) struct RastPort *rp, REG(a1) UBYTE *text, REG(a2) struct IBox *bounds, REG(a3) struct DrawInfo *dri )
414 #endif
416 AROS_LIBFUNC_INIT
418 RenderInfoText(rp, text, PENS(dri), bounds, (UWORD)~0);
420 AROS_LIBFUNC_EXIT
424 * Alignment flags.
426 #define TF_CENTER (1<<0)
427 #define TF_RIGHT (1<<1)
428 #define TF_SHADOW (1<<2)
429 #define TF_UNDERLINE (1<<3)
430 #define TF_HIGHUNDERLINE (1<<4)
431 #define TF_KEEP (1<<5)
432 #define TF_WRAP (1<<6)
435 * Command sequences:
437 * \33b Switch to bold
438 * \33i Switch to italic
439 * \33u Switch to underlined
440 * \33n Switch to normal
441 * \33s Switch to shadow
442 * \33z Switch to underlined, offset 2
443 * \33Z Switch to highlight underlined, offset 2
444 * \33c Center this and the following lines
445 * \33r Right-align this and the following lines
446 * \33l Left-align this and the following lines
447 * \33k Keep style flags.
448 * \33w Wrap text.
449 * \33d<n> Switch to DrawInfo pen <n>
450 * \33p<n> Switch to pen <n>
451 * \33D<n> Switch to background DrawInfo pen <n>
452 * \33P<n> Switch to background pen <n>
456 /// ParseCommSeq
458 * Parse a command sequence.
460 STATIC UBYTE *ParseCommSeq(struct BaseInfo *bi, UBYTE *text, UWORD *old_style, UWORD *flags)
462 UWORD new_style = *old_style;
465 * Let's see what we have here...
467 switch (*text++)
469 case '-': /* Turn off. */
470 switch (*text++)
472 case 'b':
473 new_style &= ~FSF_BOLD;
474 break;
475 case 'i':
476 new_style &= ~FSF_ITALIC;
477 break;
478 case 'u':
479 new_style &= ~FSF_UNDERLINED;
480 break;
481 case 's':
482 *flags &= ~TF_SHADOW;
483 break;
484 case 'k':
485 *flags &= ~TF_KEEP;
486 break;
487 case 'w':
488 *flags &= ~TF_WRAP;
489 break;
490 case 'z':
491 *flags &= ~TF_UNDERLINE;
492 break;
493 case 'Z':
494 *flags &= ~TF_HIGHUNDERLINE;
495 break;
496 default:
497 text -= 2;
498 break;
500 break;
502 case 'b': /* Bold. */
503 new_style |= FSF_BOLD;
504 break;
506 case 'i': /* Italic. */
507 new_style |= FSF_ITALIC;
508 break;
510 case 'u': /* Underscore. */
511 new_style |= FSF_UNDERLINED;
512 break;
514 case 'n': /* Normal. */
515 new_style = FS_NORMAL;
516 *flags &= ~(TF_SHADOW|TF_UNDERLINE|TF_HIGHUNDERLINE);
517 break;
519 case 'k': /* Keep styles. */
520 *flags |= TF_KEEP;
521 break;
523 case 'w': /* Wrap text. */
524 *flags |= TF_WRAP;
525 break;
527 case 's': /* Shadowed. */
528 *flags |= TF_SHADOW;
529 break;
531 case 'z': /* Underlined offset = 2. */
532 *flags |= TF_UNDERLINE;
533 break;
535 case 'Z': /* Highlight underlined offset = 2. */
536 *flags |= TF_HIGHUNDERLINE;
537 break;
539 case 'c': /* Center. */
540 *flags &= ~TF_RIGHT;
541 *flags |= TF_CENTER;
542 break;
544 case 'r': /* Right. */
545 *flags &= ~TF_CENTER;
546 *flags |= TF_RIGHT;
547 break;
549 case 'l': /* Left. */
550 *flags &= ~(TF_RIGHT|TF_CENTER);
551 break;
553 case 'd': /* DriPen. */
554 BSetDPenA(bi, strtol(text, (char **)&text, 0));
555 break;
556 case 'D':
557 BSetDrMd(bi, JAM2);
558 BSetDPenB(bi, strtol(text, (char **)&text, 0));
559 break;
561 case 'p': /* Pen. */
562 BSetPenA(bi, strtol(text, (char **)&text, 0));
563 break;
564 case 'P':
565 BSetDrMd(bi, JAM2);
566 BSetPenB(bi, strtol(text, (char **)&text, 0));
567 break;
569 case '1':
570 BSetDrMd(bi, JAM1);
571 break;
572 case '2':
573 BSetDrMd(bi, JAM2);
574 break;
575 case 'C':
576 BSetDrMd(bi, COMPLEMENT);
577 break;
579 case '\33': /* Do nothing. */
580 break;
582 case '\0':
584 * EOL.
586 default:
587 text--;
588 break;
592 * Style changed?
594 if (new_style != *old_style)
596 *old_style = new_style;
597 BSetFontStyle(bi, new_style);
599 return text;
602 /// XPos
604 * Determine the x position
605 * where to render the line.
607 STATIC WORD XPos(struct BaseInfo *bi, UBYTE *text, UWORD *old_style, struct IBox *domain, UWORD *flags)
609 struct RastPort *rp = bi->bi_RPort;
610 struct RastPort rp2 = *rp;
611 struct BaseInfo bi2 = *bi;
612 ULONG line_len = 0;
613 UWORD new_style = *old_style;
614 WORD xpos, i;
616 bi2.bi_RPort = &rp2;
619 * Scan text.
621 while (*text && (*text != '\n'))
624 * What have we got...
626 switch (*text)
628 case '\33':
630 * Command sequence.
632 text = ParseCommSeq(&bi2, text + 1, &new_style, flags);
633 break;
635 default:
636 i = 0;
638 * Count non-action characters.
640 while (text[i] && (text[i] != '\33') && (text[i] != '\n')) i++;
642 if (i)
645 * Determine their length.
647 line_len += TextWidthNum(&rp2, text, i);
650 * Adjust pointer.
652 text += i;
654 break;
659 * Calculate x-position.
661 if (*flags & TF_CENTER) xpos = domain->Left + ((domain->Width - line_len) >> 1);
662 else if (*flags & TF_RIGHT) xpos = domain->Left + domain->Width - 1 - line_len;
663 else xpos = domain->Left;
666 * Don't pass the left edge.
668 if (xpos < domain->Left) xpos = domain->Left;
670 return xpos;
673 /// TotalHeight
675 * Determine the total height of the text.
677 makeproto UWORD ASM TotalHeight( REG(a0) struct RastPort *rp, REG(a1) UBYTE *text )
679 UWORD nl = 1;
680 UBYTE c;
683 * Count the number of lines.
685 if(text==NULL)
687 D(bug("*** NULL text pointer in TotalHeight function (%s,%ld)\n",__FILE__,__LINE__));
688 return(0);
690 while ((c = *text++))
692 if (c == '\n') nl++;
694 return (UWORD)(nl * rp->TxHeight);
697 /// TotalWidth
699 * Determine the total width
700 * of the information text.
702 makeproto UWORD ASM TotalWidth(REG(a0) struct RastPort *rp, REG(a1) UBYTE *text)
704 struct RastPort rport = *rp;
705 ULONG line_len = 0, len = 0;
706 UWORD new_style = FS_NORMAL, flags = 0, i;
708 struct BaseInfo bi;
710 bi.bi_Pens = DefDriPens;
711 bi.bi_RPort = &rport;
714 * Start as FS_NORMAL.
716 BSetFontStyle(&bi, FS_NORMAL);
719 * Scan text.
721 if(text==NULL)
723 D(bug("*** NULL text pointer in TotalWidth function (%s,%ld)\n",__FILE__,__LINE__));
724 return(0);
726 while (*text)
729 * What have we got.
731 switch (*text)
733 case '\33':
735 * Escape sequence.
737 text = ParseCommSeq(&bi, ++text, &new_style, &flags);
738 break;
740 default:
741 i = 0;
743 * Count the non-action characters.
745 while (text[i] && (text[i] != '\33') && (text[i] != '\n')) i++;
748 * Determine their length.
750 line_len += TextWidthNum(&rport, text, i);
753 * New line or end-of-line?
755 if (text[i] == '\n' || text[i] == '\0')
757 if (!(flags & TF_WRAP))
760 * Is it wider than the previous ones?
762 if (line_len > len)
763 len = line_len;
767 * Go on when this was a new line.
769 if (text[i] == '\n')
771 text++;
772 BSetFontStyle(&bi, FS_NORMAL);
776 * Set line_len to 0.
778 line_len = 0;
780 text += i;
781 break;
784 return (UWORD)len;
787 /// RenderInfoText
789 * Render the information text.
791 makeproto void RenderInfoText(struct RastPort *rp, UBYTE *text, UWORD *pens, struct IBox *domain, UWORD backpen)
793 struct BaseInfo *bi;
795 #ifdef DEBUG_BGUI
796 if ((bi = AllocBaseInfoDebug(__FILE__,__LINE__,BI_RastPort, rp, BI_Pens, pens, TAG_DONE)))
797 #else
798 if ((bi = AllocBaseInfo(BI_RastPort, rp, BI_Pens, pens, TAG_DONE)))
799 #endif
801 if (!pens) pens = DefDriPens;
803 BSetDrMd(bi, JAM1);
804 BClearAfPt(bi);
806 * First we fill the background.
808 if (backpen != (UWORD)~1)
810 if (backpen != (UWORD)~0)
812 BSetPenA(bi, backpen);
813 BBoxFillA(bi, domain);
817 * Set initial pen.
819 BSetDPenA(bi, (backpen == bi->bi_Pens[FILLPEN]) ? FILLTEXTPEN : TEXTPEN);
821 RenderText(bi, text, domain);
823 FreeBaseInfo(bi);
827 /// RenderText
829 * Render the information text.
831 makeproto void RenderText(struct BaseInfo *bi, UBYTE *text, struct IBox *domain)
833 struct RastPort *rp = bi->bi_RPort;
834 struct TextExtent extent;
835 WORD xpos, ypos = domain->Top + rp->TxBaseline;
836 UWORD style = FS_NORMAL, dubstyle = FS_NORMAL, flags = 0, i, nl, numc;
837 ULONG old_a = 0, old_m;
840 * Start as FS_NORMAL.
842 BSetFontStyle(bi, FS_NORMAL);
845 * Get the height of the text.
847 nl = TotalHeight(rp, text);
850 * Is it smaller than
851 * the domain?
853 if (nl < domain->Height)
855 * Yes. Adjust the top size
856 * so that it get's centered.
858 ypos += (domain->Height - nl) >> 1;
861 * Find out starting position.
863 xpos = XPos(bi, text, &dubstyle, domain, &flags);
865 BSetDrMd(bi, JAM1);
866 BSetFontStyle(bi, FS_NORMAL);
867 flags &= ~(TF_SHADOW|TF_UNDERLINE|TF_HIGHUNDERLINE);
870 * Scan text.
872 while (*text)
875 * What have we got...
877 switch (*text)
879 case '\33':
881 * Command sequence.
883 text = ParseCommSeq(bi, ++text, &style, &flags);
884 break;
886 case '\n':
888 * Newline.
890 text++;
893 * New position.
895 xpos = XPos(bi, text, &dubstyle, domain, &flags);
898 * Are we passing the bottom of the
899 * rendering area?
901 if ((ypos += rp->TxHeight ) > domain->Top + domain->Height - 1)
902 return;
904 Move(rp, xpos, ypos);
905 if (!(flags & TF_KEEP))
907 BSetFontStyle(bi, FS_NORMAL);
908 flags &= ~(TF_SHADOW|TF_UNDERLINE|TF_HIGHUNDERLINE);
910 break;
912 default:
914 * Count non-action characters.
916 i = 0;
917 while (text[i] && (text[i] != '\33') && (text[i] != '\n')) i++;
919 if (i)
922 * Render them.
924 if ((numc = TextFit(rp, text, i, &extent, NULL, 1, max((LONG)(domain->Width - (xpos - domain->Left)), 0), rp->TxHeight)))
926 if (flags & TF_SHADOW)
928 old_a = FGetAPen(rp);
929 old_m = FGetDrMd(rp);
930 BSetDPenA(bi, SHADOWPEN);
931 Move(rp, xpos + 1, ypos + 1);
932 Text(rp, text, numc);
933 BSetPenA(bi, old_a);
934 BSetDrMd(bi, JAM1);
935 Move(rp, xpos, ypos);
936 Text(rp, text, numc);
937 BSetDrMd(bi, old_m);
939 else
941 if (flags & (TF_UNDERLINE|TF_HIGHUNDERLINE))
943 if (flags & TF_HIGHUNDERLINE)
945 old_a = FGetAPen(rp);
946 BSetDPenA(bi, SHINEPEN);
948 Move(rp, xpos, ypos + 2);
949 Draw(rp, xpos + TextLength(rp, text, numc) - 2, ypos + 2);
950 if (flags & TF_HIGHUNDERLINE)
952 BSetPenA(bi, old_a);
955 Move(rp, xpos, ypos);
956 Text(rp, text, numc);
960 * Skip remainder of the line
961 * if possible.
963 if (numc < i)
965 while (text[i] && text[i] != '\n')
966 i++;
969 * Adjust x position.
971 xpos += TextWidthNum(rp, text, numc);
974 * Adjust pointer.
976 text += i;
978 break;