1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 /**
20 * \file xtext.c
21 *
22 * This file is part of the XForms library package.
23 * Copyright (c) 1996-2002 T.C. Zhao and Mark Overmars
24 * All rights reserved.
25 *
26 * All text routines. There are rooms for speed ups. For one, font
27 * switching can be reduced somewhat.
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "include/forms.h"
35 #include "flinternal.h"
36
37 #include <string.h>
38 #include <ctype.h>
39
40
41 static int UL_thickness = -1;
42 static int UL_propwidth = 1; /* 1 for proportional, 0 for constant */
43
44 static void do_underline( FL_Coord,
45 FL_Coord,
46 const char *,
47 int );
48
49 static void do_underline_all( FL_Coord,
50 FL_Coord,
51 const char *,
52 int,
53 unsigned long *,
54 unsigned long * );
55
56 #define NUM_LINES_INCREMENT 64
57
58 static struct LINE_INFO {
59 char * str;
60 int len;
61 int index;
62 int underline_index;
63 int x;
64 int y;
65 } * lines = NULL;
66
67 static int nlines;
68
69 static int max_pixelline = 0;
70
71
72 /***************************************
73 ***************************************/
74
75 static int
extend_workmem(int nl)76 extend_workmem( int nl )
77 {
78 lines = fl_realloc( lines, nl * sizeof *lines );
79 return nlines = nl;
80 }
81
82
83 /***************************************
84 ***************************************/
85
86 void
fli_free_xtext_workmem(void)87 fli_free_xtext_workmem( void )
88 {
89 fli_safe_free( lines );
90 nlines = 0;
91 }
92
93
94 /***************************************
95 * Returns the index of the widest line drawn in a previous
96 * call of fli_draw_string() (only used by input.c)
97 ***************************************/
98
99 int
fli_get_max_pixels_line(void)100 fli_get_max_pixels_line( void )
101 {
102 return max_pixelline;
103 }
104
105
106 /* type fitting both XDrawString() and XDrawImageString() */
107
108 typedef int ( * DrawString )( Display * display,
109 Drawable d,
110 GC gc,
111 int x,
112 int y,
113 const char * string,
114 int length );
115
116
117 /***************************************
118 * Major text drawing routine. It draws text (possibly consisting of several
119 * lines) into the box specified via the coordinates and using the given
120 * alignment relative to that box. Also a cursor is drawn. For lines that
121 * contain a special character indicating underlining this is also handled.
122 * Finally, parts of the text can be shown as selected.
123 *
124 * Arguments:
125 * align Alignment of the text relative to the box
126 * x, ym w, h postion and size of box
127 * clip 0 = no clipping is to be used at all
128 * 1 = clipping is to be done by this function
129 * -1 = clipping is done but already has been set externally
130 * backcol color to be used for selected text
131 * forecol color for (unselected) text
132 * curscol color for cursor
133 * style text font style
134 * size text font size
135 * curspos index into string where cursor is to be drawn (if negative or
136 * non-zero and there's no text no cursor is drawn)
137 * selstart index into string where selection starts
138 * selend index into string where selection ends (to get selection this
139 * must be larger than 'selstart')
140 * istr pointer to the text to be drawn
141 * img if non-zero also draw background (use XDrawImageString()
142 * instead of XDrawString() to draw the text)
143 * topline first line of the text to be actually shown (counting starts
144 * at 1)
145 * endline last line to be shown (if less than 1 or too large is replaced
146 * by the number of lines in the text)
147 * bkcol background color (used when 'img' is true)
148 *
149 * Returns the width (in pixel) of the widest line of the text drawn.
150 ***************************************/
151
152 int
fli_draw_string(int align,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,int clip,FL_COLOR backcol,FL_COLOR forecol,FL_COLOR curscol,int style,int size,int curspos,int selstart,int selend,const char * istr,int img,int topline,int endline,FL_COLOR bkcol)153 fli_draw_string( int align,
154 FL_Coord x,
155 FL_Coord y,
156 FL_Coord w,
157 FL_Coord h,
158 int clip,
159 FL_COLOR backcol,
160 FL_COLOR forecol,
161 FL_COLOR curscol,
162 int style,
163 int size,
164 int curspos,
165 int selstart,
166 int selend,
167 const char * istr,
168 int img,
169 int topline,
170 int endline,
171 FL_COLOR bkcol )
172 {
173 int i;
174 int lnumb = 0; /* number of lines in string */
175 int max_pixels = 0;
176 int horalign,
177 vertalign;
178 char * str = NULL,
179 * p = NULL;
180 DrawString drawIt = img ? XDrawImageString : XDrawString;
181
182 /* Check if anything has to be drawn at all - do nothing if we either
183 have no window or the cursor is to be drawn somewhere else than in
184 the very first position and there's no string to output. It would
185 be tempting to also bail out if the height 'h' is 0 or even negative
186 but there are some code paths were this actually may happen and we
187 wouldn't output a string even though it is needed (I know, it's a
188 bloody mess but fixing it right now would probably take a few weeks
189 and even might break existing code...) */
190
191 if ( flx->win == None
192 || ( curspos > 0 && ! ( istr && *istr ) ) )
193 return 0;
194
195 /* We operate only on a copy of the input string */
196
197 if ( istr && *istr )
198 p = str = fl_strdup( istr );
199
200 /* Split the string into lines, store the index where each of them begins
201 in the original string as well as the length */
202
203 while ( p )
204 {
205 /* Make sure we have enough memory */
206
207 if ( lnumb >= nlines )
208 extend_workmem( nlines + NUM_LINES_INCREMENT );
209
210 /* Get pointer to the start of the line and it's index in the
211 complete string */
212
213 lines[ lnumb ].str = p;
214 lines[ lnumb ].index = p - str; /* where line begins in str */
215
216 /* Try to find the next new line and replace the '\n' with '\0' */
217
218 if ( ( p = strchr( p, '\n' ) ) )
219 *p++ = '\0';
220
221 /* Calculate the length of the string */
222
223 lines[ lnumb ].len = p ? ( p - lines[ lnumb ].str - 1 ) :
224 ( int ) strlen( lines[ lnumb ].str );
225 ++lnumb;
226 }
227
228 /* Correct values for the top and end line to be shown (they are given
229 starting at 1) */
230
231 if ( --topline < 0 || topline >= lnumb )
232 topline = 0;
233
234 if ( --endline >= lnumb || endline < 0 )
235 endline = lnumb;
236
237 /* Calculate coordinates of all lines (for y the baseline position),
238 for that make sure the correct font is set up */
239
240 fl_set_font( style, size );
241 fli_get_hv_align( align, &horalign, &vertalign );
242
243 for ( i = topline; i < endline; i++ )
244 {
245 struct LINE_INFO *line = lines + i;
246 int width;
247
248 /* Check for the special character which indicates underlining (all
249 the line if it's in the very first position, otherwise just after
250 the character to underline), remove it from the string but remember
251 were it was and correct the selection positions if necessary (i.e.
252 if they are in the line after the character to be underlined).
253 Same for the cursor position if it's in the line. */
254
255 if ( ( p = strchr( line->str, *fl_ul_magic_char ) ) )
256 {
257 line->underline_index = p - line->str;
258
259 if ( selstart < line->index + line->len
260 && selstart > line->index + line->underline_index )
261 --selstart;
262 if ( selend < line->index + line->len
263 && selend > line->index + line->underline_index )
264 --selend;
265 if ( curspos >= line->index + line->underline_index
266 && selstart < line->index + line->len )
267 --curspos;
268
269 memmove( p, p + 1, line->len-- - line->underline_index );
270 }
271 else
272 line->underline_index = -1;
273
274 /* Determine the width (in pixel) of the line) */
275
276 width = XTextWidth( flx->fs, line->str, line->len );
277
278 if ( width > max_pixels )
279 {
280 max_pixels = width;
281 max_pixelline = i;
282 }
283
284 /* Calculate the x- and y- positon of where to print the text */
285
286 switch ( horalign )
287 {
288 case FL_ALIGN_LEFT :
289 line->x = x;
290 break;
291
292 case FL_ALIGN_CENTER :
293 line->x = x + 0.5 * ( w - width );
294 break;
295
296 case FL_ALIGN_RIGHT :
297 line->x = x + w - width;
298 break;
299
300 default :
301 M_err( "fli_draw_string", "This is impossible" );
302 return 0;
303 }
304
305 switch ( vertalign )
306 {
307 case FL_ALIGN_TOP :
308 line->y = y + i * flx->fheight + flx->fasc;
309 break;
310
311 case FL_ALIGN_CENTER :
312 line->y = y + 0.5 * h + ( i - 0.5 * lnumb ) * flx->fheight
313 + flx->fasc;
314 break;
315
316 case FL_ALIGN_BOTTOM :
317 line->y = y + h - 1 + ( i - lnumb ) * flx->fheight + flx->fasc;
318 break;
319
320 default :
321 M_err( "fli_draw_string", "This is impossible" );
322 return 0;
323 }
324 }
325
326 /* Set clipping if we got asked to */
327
328 if ( clip > 0 )
329 fl_set_text_clipping( x, y, w, h );
330
331 /* Set foreground and background color for text */
332
333 fli_textcolor( forecol );
334 fli_bk_textcolor( bkcol );
335
336 /* Draw all the lines requested */
337
338 for ( i = topline; i < endline; i++ )
339 {
340 struct LINE_INFO *line = lines + i;
341 FL_COLOR underline_col = forecol;
342 int xsel = 0, /* start position of selected text */
343 wsel = 0; /* and its length (in pixel) */
344
345 /* Skip lines that can't be visile due to clipping */
346
347 if ( clip != 0 )
348 {
349 if ( line->y + flx->fdesc < y )
350 continue;
351 if ( line->y - flx->fasc >= y + h )
352 break;
353 }
354
355 /* Draw the text */
356
357 drawIt( flx->display, flx->win, flx->textgc,
358 line->x, line->y, line->str, line->len );
359
360 /* Draw selection area if required - for this we need to draw
361 the selection background and then redraw the text in this
362 region (in the clor that was used for the background before).
363 Of course all this only needs to be done if the selection started
364 before or in this line and didn't end before it. */
365
366 if ( selstart < selend
367 && selstart <= line->index + line->len
368 && selend > line->index )
369 {
370 int start, /* start index of selected text */
371 end, /* end index */
372 len; /* its length (in chars) */
373
374 /* The selection may have started before the line we're just
375 dealing with and may end after it. Find the start and end
376 position in this line */
377
378 if ( selstart <= line->index )
379 start = 0;
380 else
381 start = selstart - line->index;
382
383 if ( selend >= line->index + line->len )
384 end = line->len;
385 else
386 end = selend - line->index;
387
388 len = end - start;
389
390 /* Get the start position and width (in pixels) of the selected
391 region (the -1 in the calculation of wsel is a fudge factor
392 to make it look a bit better) */
393
394 xsel = line->x + XTextWidth( flx->fs, line->str, start );
395
396 wsel = XTextWidth( flx->fs, line->str + start, len ) - 1;
397 if ( xsel + wsel > x + w )
398 wsel = x + w - xsel;
399
400 /* Draw in the selection color */
401
402 fl_rectf( xsel, line->y - flx->fasc, wsel,
403 flx->fheight, forecol );
404
405 fli_textcolor( backcol );
406 drawIt( flx->display, flx->win, flx->textgc, xsel,
407 line->y, line->str + start, len );
408 fli_textcolor( forecol );
409
410 if ( line->underline_index > 0 )
411 underline_col = backcol;
412 }
413
414 /* Next do underlining */
415
416 if ( line->underline_index > 0 )
417 {
418 fl_color( underline_col );
419 do_underline( line->x, line->y, line->str,
420 line->underline_index - 1 );
421 }
422 else if ( line->underline_index == 0 )
423 {
424 unsigned long offset,
425 thickness;
426
427 fl_color( forecol );
428 do_underline_all( line->x, line->y, line->str,
429 line->len, &offset, &thickness );
430
431 /* If wsel is larger than 0 some part of the underlined
432 string is selected and then we need to draw underine of
433 the part of the string that is selected in the color used
434 for drawing that part of the string. */
435
436 if ( wsel > 0 && thickness > 0 )
437 {
438 fl_color( underline_col );
439 XFillRectangle( flx->display, flx->win, flx->gc, xsel,
440 line->y + offset, wsel, thickness);
441 }
442 }
443
444 /* Finally, we also may have to draw a cursor */
445
446 if ( curspos >= line->index
447 && curspos <= line->index + line->len )
448 {
449 int tt = XTextWidth( flx->fs, line->str,
450 curspos - line->index );
451
452 fl_rectf( line->x + tt, line->y - flx->fasc,
453 2, flx->fheight, curscol );
454 }
455 }
456
457 /* One possiblity remains: there's no text but the cursor is to be set
458 at the very first position */
459
460 if ( curspos == 0 && lnumb == 0 && w >= 2 )
461 {
462 int xc,
463 yc;
464
465 if ( horalign == FL_ALIGN_LEFT )
466 xc = x;
467 else if ( horalign == FL_ALIGN_CENTER )
468 xc = x + 0.5 * w - 1;
469 else
470 xc = x + w - 2;
471
472 if ( vertalign == FL_ALIGN_BOTTOM )
473 yc = y + h - 1 - flx->fasc;
474 else if ( vertalign == FL_ALIGN_CENTER )
475 yc = y + 0.5 * ( h - flx->fheight );
476 else
477 yc = y;
478
479 fl_rectf( xc, yc, 2, flx->fheight, curscol );
480 }
481
482 /* Free our copy of the string */
483
484 fli_safe_free( str );
485
486 /* Reset clipping if required */
487
488 if ( clip > 0 )
489 fl_unset_text_clipping( );
490
491 return max_pixels;
492 }
493
494
495 /***************************************
496 * Function returns the index of the character in the label of the object
497 * the mouse is over or -1 if it's not over the label. Note that the function
498 * has some limitations: it can only be used on labels inside of the object
499 * and the label string may not contain underline characters (and the label
500 * can't be a symbol) - if you try to use it on labels that don't satisfy
501 * these requirements -1 is returned.
502 ***************************************/
503
504 int
fl_get_label_char_at_mouse(FL_OBJECT * obj)505 fl_get_label_char_at_mouse( FL_OBJECT * obj )
506 {
507 int x,
508 y,
509 xp,
510 yp,
511 pos,
512 outside;
513 unsigned int dummy;
514
515 if ( ! obj
516 || ! obj->form
517 || ! fl_is_inside_lalign( obj->align )
518 || ! obj->label || ! *obj->label
519 || strchr( obj->label, *fl_ul_magic_char )
520 || ( obj->label[ 0 ] == '@' && obj->label[ 1 ] != '@' ) )
521 return -1;
522
523 if ( fl_get_form_mouse( obj->form, &x, &y, &dummy ) != obj->form->window
524 || x < obj->x || x >= obj->x + obj->w
525 || y < obj->y || y >= obj->y + obj->h )
526 return -1;
527
528 x += 2;
529
530 pos = fli_get_pos_in_string( obj->align, obj->x, obj->y, obj->w, obj->h,
531 obj->lstyle, obj->lsize, x, y, obj->label,
532 &xp, &yp, &outside ) - 1;
533
534 if ( outside )
535 return -1;
536
537 return pos;
538 }
539
540
541 /***************************************
542 * Routine returns the index of the character the mouse is on in a string
543 * via the return value and the line number and character position in the
544 * line via 'yp' and 'xp' (note: they count starting at 1, 0 indicates the
545 * mouse is to the left of the start of the line)
546 * The function expects a string that doesn't contain mon-printable characters
547 * (except '\n' for starts a new lines)
548 * This function is supposed to work on text drawn using fli_draw_string()
549 * using the same relevant arguments (alignment, box, font style and size
550 * and string) as passed to this function.
551 *
552 * Arguments:
553 * align: alignment of the text in the box
554 * x, y, w, h: box the text is to be found in
555 * style: font style used when drawing the text
556 * size: font size used when drawing the text
557 * xpos: x-position of the mouse
558 * ypos: y-position of the mouse
559 * str: pointer to the text itself
560 * xp: pointer for returning the index in the line where the mouse is
561 * (tarts at 1 with 0 meaning before the start of the string)
562 * yp: pointer for returning the line number (starting at 1)
563 * outside: set if the mouse wasn't directly within the string
564 ***************************************/
565
566 int
fli_get_pos_in_string(int align,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,int style,int size,FL_Coord xpos,FL_Coord ypos,const char * str,int * xp,int * yp,int * outside)567 fli_get_pos_in_string( int align,
568 FL_Coord x,
569 FL_Coord y,
570 FL_Coord w,
571 FL_Coord h,
572 int style,
573 int size,
574 FL_Coord xpos,
575 FL_Coord ypos,
576 const char * str,
577 int * xp,
578 int * yp,
579 int * outside )
580 {
581 int lnumb = 0; /* number of lines */
582 int horalign,
583 vertalign;
584 struct LINE_INFO * line;
585 int width; /* string width of that line... */
586 int xstart; /* start x-coordinate of this line */
587 int toppos; /* y-coord of the top line */
588 const char *p = str;
589 int xlen;
590 int fheight;
591 int dummy;
592
593 /* Give the user some slack in hitting the mark - he might try to place
594 the cursor between two characters and accidentally has the mouse a
595 bit too far to the right. */
596
597 xpos -= 2;
598 *outside = 0;
599
600 /* Nothing to be done if there's no string */
601
602 if ( ! str || ! *str )
603 return 0;
604
605 /* No need to actually set the font (we're not drawing anything), all
606 required is its height */
607
608 fheight = fl_get_char_height( style, size, &dummy, &dummy );
609
610 /* Find all the lines starts etc. in the string */
611
612 while ( p )
613 {
614 if ( lnumb + 1 >= nlines )
615 extend_workmem( nlines + NUM_LINES_INCREMENT );
616
617 lines[ lnumb ].str = ( char * ) p;
618 lines[ lnumb++ ].index = p - str;
619 if ( ( p = strchr( p, '\n' ) ) )
620 ++p;
621 }
622
623 /* Find the line in which the mouse is */
624
625 fli_get_hv_align( align, &horalign, &vertalign );
626
627 switch ( vertalign )
628 {
629 case FL_ALIGN_TOP :
630 toppos = y;
631 break;
632
633 case FL_ALIGN_CENTER :
634 toppos = y + 0.5 * ( h - lnumb * fheight );
635 break;
636
637 case FL_ALIGN_BOTTOM :
638 toppos = y + h - 1 - fheight;
639 break;
640
641 default :
642 M_err( "fli_get_pos_in_string", "This is impossible" );
643 return 0;
644 }
645
646 *yp = ( ypos - toppos ) / fheight;
647
648 if ( *yp < 0 )
649 {
650 *outside = 1;
651 *yp = 0;
652 }
653 else if ( *yp >= lnumb )
654 {
655 *outside = 1;
656 *yp = lnumb - 1;
657 }
658
659 line = lines + *yp;
660
661 if ( *yp == lnumb - 1 )
662 line->len = strlen( line->str );
663 else
664 line->len = lines[ *yp + 1 ].str - line->str - 1;
665
666 /* Calculate width and start x-coordinate of the line */
667
668 width = XTextWidth( flx->fs, line->str, line->len );
669
670 switch ( horalign )
671 {
672 case FL_ALIGN_LEFT :
673 xstart = x;
674 break;
675
676 case FL_ALIGN_CENTER :
677 xstart = x + 0.5 * ( w - width );
678 break;
679
680 case FL_ALIGN_RIGHT :
681 xstart = x + w - width;
682 break;
683
684 default :
685 M_err( "fli_get_pos_in_string", "This is impossible" );
686 return 0;
687 }
688
689 xpos -= xstart;
690
691 /* If the mouse is before or behind the string things are simple.... */
692
693 if ( xpos <= 0 )
694 {
695 *xp = 0;
696 *yp += 1;
697 *outside = 1;
698 return line->index;
699 }
700 else if ( xpos >= width )
701 {
702 *xp = line->len;
703 *yp += 1;
704 *outside = 1;
705 return line->index + line->len;
706 }
707
708 /* ...otherwise take a guess at the offset in the string where the mouse
709 is, assuming all chars have the same width */
710
711 *xp = ( double ) ( xpos * line->len ) / width;
712
713 xlen = XTextWidth( flx->fs, line->str, ++*xp );
714
715 /* If we don't have hit it directly search to the left or right */
716
717 if ( xlen > xpos )
718 {
719 do
720 {
721 *xp -= 1;
722 xlen = XTextWidth( flx->fs, line->str, *xp );
723 }
724 while ( *xp > 0 && xlen > xpos );
725 *xp += 1;
726 }
727 else if ( xlen < xpos )
728 do
729 {
730 *xp += 1;
731 xlen = XTextWidth( flx->fs, line->str, *xp );
732 }
733 while ( *xp < lines->len && xlen < xpos );
734
735 *yp += 1;
736
737 return line->index + *xp;
738 }
739
740
741 /***
742 Miscellaneous text drawing routines
743 ***/
744
745 /***************************************
746 * Draw text with cursor and, if 'bk' is set, also the background
747 * (but with no highlighting)
748 ***************************************/
749
750 static void
fli_draw_text_cursor(int align,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * str,int style,int size,FL_COLOR c,FL_COLOR bc,FL_COLOR cc,int bk,int pos)751 fli_draw_text_cursor( int align, /* alignment in box */
752 FL_Coord x, /* box geometry */
753 FL_Coord y,
754 FL_Coord w,
755 FL_Coord h,
756 const char * str, /* string to draw */
757 int style, /* font style and size */
758 int size,
759 FL_COLOR c, /* color for text */
760 FL_COLOR bc, /* background color */
761 FL_COLOR cc, /* color for cursor */
762 int bk, /* draws background when set */
763 int pos ) /* index of cursor position */
764 {
765 fli_draw_string( align, x, y, w, h, 0, FL_NOCOLOR, c, cc,
766 style, size, pos, 0, -1, str, bk, 0, 0, bc );
767 }
768
769
770 /***************************************
771 * Draws a (multi-line) text with a cursor (no background, no highlighting)
772 ***************************************/
773
774 void
fl_draw_text_cursor(int align,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,FL_COLOR c,int style,int size,const char * str,FL_COLOR cc,int pos)775 fl_draw_text_cursor( int align, /* alignment in box */
776 FL_Coord x, /* box geometry */
777 FL_Coord y,
778 FL_Coord w,
779 FL_Coord h,
780 FL_COLOR c, /* text color */
781 int style, /* font style and size */
782 int size,
783 const char * str, /* the text to draw */
784 FL_COLOR cc, /* cursor color */
785 int pos ) /* cursor position */
786 {
787 fli_draw_text_cursor( align, x, y, w, h, str, style, size,
788 c, FL_NOCOLOR, cc, 0, pos );
789 }
790
791
792 /***************************************
793 ***************************************/
794
795 #define D( x, y, c ) \
796 fli_draw_text_cursor( align, x, y, w, h, str, \
797 style,size, c, bc, 0, bk, -1 )
798
799 void
fli_draw_text_inside(int align,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * str,int style,int size,FL_COLOR c,FL_COLOR bc,int bk)800 fli_draw_text_inside( int align,
801 FL_Coord x,
802 FL_Coord y,
803 FL_Coord w,
804 FL_Coord h,
805 const char * str,
806 int style,
807 int size,
808 FL_COLOR c,
809 FL_COLOR bc,
810 int bk )
811 {
812 int special = 0;
813 int xoff,
814 yoff;
815 int sw = w,
816 sh = h,
817 sx = x,
818 sy = y;
819
820 if ( ! str || ! *str )
821 return;
822
823 if ( str[ 0 ] == '@' && str[ 1 ] != '@' )
824 {
825 if ( w < 5 && h < 5 )
826 {
827 sw = sh = 6 + 1.1 * size;
828 sx -= sw / 2;
829 sy -= sh / 2;
830 }
831
832 if ( fl_draw_symbol( str, sx, sy, sw, sh, c ) )
833 return;
834 else
835 str++;
836 }
837 else if ( str[ 0 ] == '@' && str[ 1 ] == '@' )
838 str++;
839
840 xoff = 5;
841 yoff = 4;
842
843 x += xoff;
844 w -= 2 * xoff;
845 y += yoff;
846 h -= 2 * yoff;
847
848 if ( special_style( style ) )
849 {
850 special = ( style / FL_SHADOW_STYLE ) * FL_SHADOW_STYLE;
851 style %= FL_SHADOW_STYLE;
852 }
853
854 /* Take care of special effects stuff */
855
856 if ( special == FL_SHADOW_STYLE )
857 D( x + 2, y + 2, FL_BOTTOM_BCOL );
858 else if ( special == FL_ENGRAVED_STYLE )
859 {
860 D( x - 1, y, FL_RIGHT_BCOL );
861 D( x, y - 1, FL_RIGHT_BCOL );
862 D( x - 1, y - 1, FL_RIGHT_BCOL );
863 D( x + 1, y, FL_TOP_BCOL );
864 D( x, y + 1, FL_TOP_BCOL );
865 D( x + 1, y + 1, FL_TOP_BCOL );
866 }
867 else if ( special == FL_EMBOSSED_STYLE )
868 {
869 D( x - 1, y, FL_TOP_BCOL );
870 D( x, y - 1, FL_TOP_BCOL );
871 D( x - 1, y - 1, FL_TOP_BCOL );
872 D( x + 1, y, FL_RIGHT_BCOL );
873 D( x, y + 1, FL_RIGHT_BCOL );
874 D( x + 1, y + 1, FL_RIGHT_BCOL );
875 }
876
877 fli_draw_text_cursor( align, x, y, w, h, str, style, size,
878 c, bc, FL_NOCOLOR, special ? 0 : bk, -1 );
879 }
880
881
882 /***************************************
883 * Draws a text inside a box.
884 ***************************************/
885
886 void
fl_draw_text(int align,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,FL_COLOR c,int style,int size,const char * str)887 fl_draw_text( int align,
888 FL_Coord x,
889 FL_Coord y,
890 FL_Coord w,
891 FL_Coord h,
892 FL_COLOR c,
893 int style,
894 int size,
895 const char * str )
896 {
897 fli_draw_text_inside( align, x, y, w, h, str, style, size, c, 0, 0 );
898 }
899
900
901 /***************************************
902 ***************************************/
903
904 void
fl_draw_text_beside(int align,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,FL_COLOR c,int style,int size,const char * str)905 fl_draw_text_beside( int align,
906 FL_Coord x,
907 FL_Coord y,
908 FL_Coord w,
909 FL_Coord h,
910 FL_COLOR c,
911 int style,
912 int size,
913 const char * str )
914 {
915 int newa,
916 newx,
917 newy,
918 dx = 0,
919 dy = 0;
920
921 if ( ! str || ! *str || w <= 0 || h <= 0 )
922 return;
923
924 if ( fl_is_inside_lalign( align ) && ! fl_is_center_lalign( align ) )
925 M_warn( "drw_text_beside", "align request is inside" );
926
927 if ( align & FL_ALIGN_LEFT )
928 {
929 if ( align & FL_ALIGN_BOTTOM || align & FL_ALIGN_TOP )
930 dx = - 4;
931 else
932 dx = 1;
933 }
934 else if ( align & FL_ALIGN_RIGHT )
935 {
936 if ( align & FL_ALIGN_BOTTOM || align & FL_ALIGN_TOP )
937 dx = 4;
938 else
939 dx = - 1;
940 }
941
942 if ( align & FL_ALIGN_BOTTOM )
943 dy = - 2;
944 else if ( align & FL_ALIGN_TOP )
945 dy = 2;
946
947 x += dx;
948 y += dy;
949
950 fli_get_outside_align( align, x, y, w, h, &newa, &newx, &newy );
951 fl_draw_text( newa, newx, newy, w, h, c, style, size, str );
952 }
953
954
955 /***************************************
956 * Do underlined text, single character only
957 * if underline width to be proportional or fixed width
958 ***************************************/
959
960 void
fli_set_ul_property(int prop,int thickness)961 fli_set_ul_property( int prop,
962 int thickness )
963 {
964 UL_propwidth = prop;
965 if ( thickness > 0 )
966 UL_thickness = thickness;
967 }
968
969
970 #define DESC( c ) ( c == 'g' || c == 'j' || c == 'q' || c == 'y' || c == 'p' )
971 #define NARROW( c ) ( c == 'i' || c == 'j' || c == 'l' || c == 'f' || c == '1' )
972
973 /***************************************
974 ***************************************/
975
976 XRectangle *
fli_get_underline_rect(XFontStruct * fs,FL_Coord x,FL_Coord y,const char * cstr,int n)977 fli_get_underline_rect( XFontStruct * fs,
978 FL_Coord x,
979 FL_Coord y,
980 const char * cstr,
981 int n )
982 {
983 static XRectangle xr;
984 int ul_width,
985 ul_rwidth,
986 xoff;
987 unsigned long ul_pos,
988 ul_thickness = 0;
989 char *str = ( char * ) cstr;
990 int ch = *( str + n );
991 int pre; /* stuff in front of the string, such as ^H */
992
993 if ( UL_thickness < 0 )
994 XGetFontProperty( flx->fs, XA_UNDERLINE_THICKNESS, &ul_thickness );
995 else
996 ul_thickness = UL_thickness;
997
998 if ( ul_thickness == 0 || ul_thickness > 100 )
999 ul_thickness = strstr( fli_curfnt, "bold" ) ? 2 : 1;
1000
1001 if ( ! XGetFontProperty( fs, XA_UNDERLINE_POSITION, &ul_pos ) )
1002 ul_pos = DESC( ch ) ? ( 1 + flx->fdesc ) : 1;
1003
1004 /* If the character is narrow, use the width of g otherwise use the width
1005 of D. Of course, if UL_width == proportional, this really does not
1006 matter */
1007
1008 ul_width = XTextWidth( fs, NARROW( ch ) ? "h" : "D", 1 );
1009 ul_rwidth = XTextWidth( fs, str + n, 1 );
1010
1011 pre = str[ 0 ] == *fl_ul_magic_char;
1012
1013 xoff = fli_get_string_widthTABfs( fs, str + pre, n - pre );
1014
1015 /* Try to center the underline on the correct character */
1016
1017 if ( UL_propwidth )
1018 x = x + xoff;
1019 else
1020 x = x + xoff + ( ul_rwidth - ul_width ) / 2;
1021
1022 xr.x = x;
1023 xr.y = y + ul_pos;
1024 xr.width = UL_propwidth ? ul_rwidth : ul_width;
1025 xr.height = ul_thickness;
1026 return &xr;
1027 }
1028
1029
1030 /***************************************
1031 ***************************************/
1032
1033 static void
do_underline(FL_Coord x,FL_Coord y,const char * cstr,int n)1034 do_underline( FL_Coord x,
1035 FL_Coord y,
1036 const char * cstr,
1037 int n )
1038 {
1039 XRectangle *xr = fli_get_underline_rect( flx->fs, x, y, cstr, n );
1040
1041 if ( flx->win == None || xr->width <= 0 || xr->height <= 0 )
1042 return;
1043
1044 XFillRectangle( flx->display, flx->win, flx->gc, xr->x, xr->y,
1045 xr->width, xr->height );
1046 }
1047
1048
1049 #define has_desc( s ) ( strchr( s, 'g' ) \
1050 || strchr( s, 'j' ) \
1051 || strchr( s, 'q' ) \
1052 || strchr( s, 'y' ) \
1053 || strchr( s, 'p' ) )
1054
1055
1056 /***************************************
1057 * Underline whole string
1058 ***************************************/
1059
1060 static void
do_underline_all(FL_Coord x,FL_Coord y,const char * str,int n,unsigned long * ul_pos,unsigned long * ul_thickness)1061 do_underline_all( FL_Coord x,
1062 FL_Coord y,
1063 const char * str,
1064 int n,
1065 unsigned long * ul_pos,
1066 unsigned long * ul_thickness )
1067 {
1068 int ul_width;
1069
1070 if ( flx->win == None )
1071 return;
1072
1073 if ( UL_thickness < 0 )
1074 XGetFontProperty( flx->fs, XA_UNDERLINE_THICKNESS, ul_thickness );
1075 else
1076 *ul_thickness = UL_thickness;
1077
1078 if ( *ul_thickness == 0 || *ul_thickness > 100 )
1079 *ul_thickness = strstr( fli_curfnt, "bold" ) ? 2 : 1;
1080
1081 if ( ! XGetFontProperty( flx->fs, XA_UNDERLINE_POSITION, ul_pos ) )
1082 *ul_pos = has_desc( str ) ? ( 1 + flx->fdesc ) : 1;
1083
1084 ul_width = XTextWidth( flx->fs, str, n );
1085
1086 /* Draw it */
1087
1088 if ( ul_width > 0 && *ul_thickness > 0 )
1089 XFillRectangle( flx->display, flx->win, flx->gc, x, y + *ul_pos,
1090 ul_width, *ul_thickness );
1091 }
1092
1093
1094 /***************************************
1095 * Draw a single line string possibly with embedded tabs
1096 ***************************************/
1097
1098 int
fli_draw_stringTAB(Window win,GC gc,int x,int y,int style,int size,const char * s,int len,int img)1099 fli_draw_stringTAB( Window win,
1100 GC gc,
1101 int x,
1102 int y,
1103 int style,
1104 int size,
1105 const char * s,
1106 int len,
1107 int img )
1108 {
1109 int w, tab;
1110 const char *p,
1111 *q;
1112 XFontStruct *fs = fl_get_font_struct( style, size );
1113 DrawString drawIt = img ? XDrawImageString : XDrawString;
1114
1115 if ( win == 0 )
1116 return 0;
1117
1118 tab = fli_get_tabpixels( fs );
1119
1120 XSetFont( flx->display, gc, fs->fid );
1121
1122 for ( w = 0, q = s; *q && ( p = strchr( q, '\t' ) ) && p - s < len;
1123 q = p + 1 )
1124 {
1125 drawIt( flx->display, win, gc, x + w, y, ( char * ) q, p - q );
1126 w += XTextWidth( fs, q, p - q );
1127 w = ( w / tab + 1 ) * tab;
1128 }
1129
1130 drawIt( flx->display, win, gc, x + w, y, ( char * ) q, s - q + len );
1131
1132 return 0;
1133 }
1134
1135
1136 /*
1137 * Local variables:
1138 * tab-width: 4
1139 * indent-tabs-mode: nil
1140 * End:
1141 */
1142