* gcustom-layout.c, gprefs.c: Make the preferences dialog
[midnight-commander.git] / gtkedit / propfont.c
blob020ccffd06004c74007a9901a2a88a9d900ce0d0
1 /* propfont.c - editor text drawing for proportional fonts.
2 Copyright (C) 1997 Paul Sheer
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #include <config.h>
19 #include "edit.h"
21 /* this file definatively relies on int being 32 bits or more */
23 int option_long_whitespace = 0;
25 #define MAX_LINE_LEN 1024
26 #define CACHE_WIDTH 256
27 #define CACHE_HEIGHT 128
30 struct cache_line {
31 int x0, x1;
32 cache_type data[CACHE_WIDTH];
35 extern unsigned char per_char[256];
37 /* background colors: marked is refers to mouse highlighting, highlighted refers to a found string. */
38 extern unsigned long edit_abnormal_color, edit_marked_abnormal_color;
39 extern unsigned long edit_highlighted_color, edit_marked_color;
40 extern unsigned long edit_normal_background_color;
42 /* foreground colors */
43 extern unsigned long edit_normal_foreground_color, edit_bold_color;
44 extern unsigned long edit_italic_color;
46 /* cursor color */
47 extern unsigned long edit_cursor_color;
49 extern int EditExposeRedraw;
50 extern int EditClear;
52 void set_style_color (
53 #ifdef GTK
54 Window win,
55 #endif
56 cache_type s, unsigned long *fg, unsigned long *bg)
58 int fgp, bgp;
59 fgp = (s & 0xFF000000UL) >> 24;
60 if (fgp < 255)
61 *fg = color_palette (fgp);
62 else
63 *fg = edit_normal_foreground_color;
64 bgp = (s & 0x00FF0000) >> 16;
65 if (bgp < 255)
66 *bg = color_palette (bgp);
67 else
68 *bg = edit_normal_background_color;
69 if (!(s & 0xFFFFFF00UL)) /* check this first as an optimization */
70 return;
71 if (s & (MOD_ABNORMAL * 256)) {
72 *bg = edit_abnormal_color;
73 if (s & (MOD_MARKED * 256))
74 *bg = edit_marked_abnormal_color;
75 } else if (s & (MOD_HIGHLIGHTED * 256)) {
76 *bg = edit_highlighted_color;
77 } else if (s & (MOD_MARKED * 256)) {
78 *bg = edit_marked_color;
80 if (s & (MOD_BOLD * 256))
81 *fg = edit_bold_color;
82 if (s & (MOD_ITALIC * 256))
83 *fg = edit_italic_color;
84 if (s & (MOD_INVERSE * 256)) {
85 unsigned long t;
86 t = *fg;
87 *fg = *bg;
88 *bg = t;
89 if (*bg == COLOR_BLACK)
90 *bg = color_palette (1);
94 #ifdef GTK
95 #define set_style_color(s,f,b) set_style_color(win,s,f,b)
96 #endif
98 int tab_width = 1;
100 static inline int next_tab_pos (int x)
102 return x += tab_width - x % tab_width;
105 /* For Ryan: */
106 /* converts a possibly unprintable character to a string,
107 returning the string's width in pixels, t must have space for 4 chars */
108 static inline int convert_to_long_printable (int c, unsigned char *t)
110 if (c > ' ') {
111 if (c <= '~') {
112 t[0] = c;
113 t[1] = 0;
114 return per_char[c];
116 if (c >= 160)
117 if (option_international_characters) {
118 t[0] = c;
119 t[1] = 0;
120 return per_char[c];
122 if (c > '~') {
123 t[0] = ("0123456789ABCDEF")[c >> 4];
124 t[1] = ("0123456789ABCDEF")[c & 0xF];
125 t[2] = 'h';
126 t[3] = 0;
127 return per_char[t[0]] + per_char[t[1]] + per_char[t[2]];
130 if (c == ' ') {
131 if (option_long_whitespace) {
132 t[0] = ' ';
133 t[1] = ' ';
134 t[2] = 0;
135 return per_char[' '] + per_char[' '];
136 } else {
137 t[0] = ' ';
138 t[1] = 0;
139 return per_char[' '];
142 t[0] = '^';
143 t[1] = c + '@';
144 t[2] = 0;
145 return per_char[t[0]] + per_char[t[1]];
148 /* same as above but just gets the length */
149 static inline int width_of_long_printable (int c)
151 if (c > ' ') {
152 if (c <= '~')
153 return per_char[c];
154 if (c >= 160)
155 if (option_international_characters)
156 return per_char[c];
157 if (c > '~')
158 return per_char[(unsigned char) ("0123456789ABCDEF")[c >> 4]] + per_char[(unsigned char) ("0123456789ABCDEF")[c & 0xF]] + per_char['h'];
160 if (c == ' ') {
161 if (option_long_whitespace)
162 return per_char[' '] + per_char[' '];
163 else
164 return per_char[' '];
166 return per_char['^'] + per_char[c + '@'];
169 int edit_width_of_long_printable (int c)
171 return width_of_long_printable (c);
174 /* returns x pixel pos of char at offset *q with x not more than l */
175 int calc_text_pos (WEdit * edit, long b, long *q, int l)
177 int x = 0, c, xn;
178 for (;;) {
179 c = edit_get_byte (edit, b);
180 switch (c) {
181 case '\n':
182 *q = b;
183 if (x > edit->max_column)
184 edit->max_column = x;
185 return x;
186 case '\t':
187 xn = next_tab_pos (x);
188 break;
189 default:
190 xn = x + width_of_long_printable (c);
191 break;
193 if (xn > l)
194 break;
195 x = xn;
196 b++;
198 *q = b;
199 if (x > edit->max_column)
200 edit->max_column = x;
201 return x;
205 /* calcs pixel length of the line beginning at b up to upto */
206 int calc_text_len (WEdit * edit, long b, long upto)
208 int x = 0, c;
209 for (;;) {
210 if (b == upto) {
211 if (x > edit->max_column)
212 edit->max_column = x;
213 return x;
215 c = edit_get_byte (edit, b);
216 switch (c) {
217 case '\n':{
218 if (x > edit->max_column)
219 edit->max_column = x;
220 return x;
222 case '\t':
223 x = next_tab_pos (x);
224 break;
225 default:
226 x += width_of_long_printable (c);
227 break;
229 b++;
233 /* If pixels is zero this returns the count of pixels from current to upto. */
234 /* If upto is zero returns index of pixels across from current. */
235 long edit_move_forward3 (WEdit * edit, long current, int pixels, long upto)
237 if (upto) {
238 return calc_text_len (edit, current, upto);
239 } else if (pixels) {
240 long q;
241 calc_text_pos (edit, current, &q, pixels);
242 return q;
244 return current;
247 extern int column_highlighting;
249 /* gets the characters style (eg marked, highlighted) from its position in the edit buffer */
250 static inline cache_type get_style (WEdit * edit, long q, int c, long m1, long m2, int x)
252 cache_type s = 0;
253 unsigned int fg, bg;
254 if (q == edit->curs1)
255 s |= MOD_CURSOR * 256;
256 if (q >= m1 && q < m2) {
257 if (column_highlighting) {
258 if ((x >= edit->column1 && x < edit->column2)
259 || (x >= edit->column2 && x < edit->column1))
260 s |= MOD_INVERSE * 256;
261 } else {
262 s |= MOD_MARKED * 256;
265 if (q == edit->bracket)
266 s |= MOD_BOLD * 256;
267 if (q >= edit->found_start && q < edit->found_start + edit->found_len)
268 s |= MOD_HIGHLIGHTED * 256;
269 if (option_international_characters) {
270 if ((c < ' ' || (c > '~' && c < 160)) && c != '\t' && c != '\n')
271 s |= MOD_ABNORMAL * 256;
272 } else {
273 if ((c < ' ' || c > '~') && c != '\t' && c != '\n')
274 s |= MOD_ABNORMAL * 256;
276 edit_get_syntax_color (edit, q, (int *) &fg, (int *) &bg);
277 return s | ((fg & 0xFF) << 24) | ((bg & 0xFF) << 16);
280 void convert_text (WEdit * edit, long q, cache_type *p, int x, int x_max)
282 int c;
283 cache_type s;
284 long m1, m2;
285 unsigned char *r, text[4];
286 eval_marks (edit, &m1, &m2);
287 for (;;) {
288 c = edit_get_byte (edit, q);
289 *p = get_style (edit, q, c, m1, m2, x);
290 switch (c) {
291 case '\n':
292 *p++ |= ' ';
293 *p = 0;
294 if (x > edit->max_column)
295 edit->max_column = x;
296 return;
297 case '\t':
298 if (fixed_font) {
299 int t;
300 t = next_tab_pos (x);
301 t = min (t, x_max);
302 s = *p;
303 while (x < t) {
304 x += per_char[' '];
305 *p++ = s | ' ';
307 } else {
308 *p++ |= '\t';
309 x = next_tab_pos (x);
311 break;
312 default:
313 x += convert_to_long_printable (c, text);
314 r = text;
315 s = *p;
316 *p++ = s | *r++;
317 if (*r) {
318 *p++ = s | *r++;
319 if (*r)
320 *p++ = s | *r++;
322 break;
324 if (x >= x_max)
325 break;
326 q++;
328 if (x > edit->max_column)
329 edit->max_column = x;
330 *p = 0;
333 void edit_set_cursor (Window win, int x, int y, int bg, int fg, int width, char t)
335 #ifdef GTK
336 gdk_gc_set_foreground (win->gc, &win->color[18]);
337 gdk_draw_rectangle (win->text_area, win->gc, 0, x, y + FONT_OVERHEAD, width - 1, FONT_HEIGHT - 1);
338 #else
339 CSetColor (edit_cursor_color);
340 CLine (win, x, y + FONT_OVERHEAD,
341 x, y + FONT_HEIGHT - 1); /* non focussed cursor form */
342 CLine (win, x + 1, y + FONT_OVERHEAD,
343 x + width - 1, y + FONT_OVERHEAD);
344 set_cursor_position (win, x, y, width, FONT_HEIGHT, CURSOR_TYPE_EDITOR, t, bg, fg); /* widget library's flashing cursor */
345 #endif
348 static inline int next_tab (int x, int scroll_right)
350 return next_tab_pos (x - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET) - x + scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET;
353 int draw_tab (Window win, int x, int y, cache_type s, int scroll_right)
355 int l;
356 #ifdef GTK
357 GdkColor fg, bg;
358 #else
359 unsigned long fg, bg;
360 #endif
361 l = next_tab (x, scroll_right);
362 #ifdef GTK
363 set_style_color (s, &fg.pixel, &bg.pixel);
364 gdk_gc_set_foreground (win->gc, &bg);
365 gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
366 /* if we printed a cursor: */
367 if (s & (MOD_CURSOR * 256))
368 edit_set_cursor (win, x, y, bg.pixel, fg.pixel, per_char[' '], ' ');
369 #else
370 set_style_color (s, &fg, &bg);
371 CSetColor (bg);
372 CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
373 /* if we printed a cursor: */
374 if (s & (MOD_CURSOR * 256))
375 edit_set_cursor (win, x, y, bg, fg, per_char[' '], ' ');
376 #endif
377 return x + l;
380 #ifdef GTK
381 #include <gdk/gdk.h>
382 #endif
384 static inline void draw_space (Window win, int x, int y, cache_type s, int l)
386 #ifdef GTK
387 GdkColor fg, bg;
388 #else
389 unsigned long fg, bg;
390 #endif
391 #ifdef GTK
392 set_style_color (s, &fg.pixel, &bg.pixel);
393 gdk_gc_set_foreground (win->gc, &bg);
394 gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
395 #else
396 set_style_color (s, &fg, &bg);
397 CSetColor (bg);
398 CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
399 /* if we printed a cursor: */
400 if (s & (MOD_CURSOR * 256))
401 edit_set_cursor (win, x, y, bg, fg, per_char[' '], ' ');
402 #endif
405 #ifdef GTK
407 void
408 gdk_draw_image_text (GdkDrawable *drawable,
409 GdkFont *font,
410 GdkGC *gc,
411 gint x,
412 gint y,
413 const gchar *text,
414 gint text_length)
416 GdkWindowPrivate *drawable_private;
417 GdkFontPrivate *font_private;
418 GdkGCPrivate *gc_private;
420 g_return_if_fail (drawable != NULL);
421 g_return_if_fail (font != NULL);
422 g_return_if_fail (gc != NULL);
423 g_return_if_fail (text != NULL);
425 drawable_private = (GdkWindowPrivate*) drawable;
426 if (drawable_private->destroyed)
427 return;
428 gc_private = (GdkGCPrivate*) gc;
429 font_private = (GdkFontPrivate*) font;
431 if (font->type == GDK_FONT_FONT)
433 XFontStruct *xfont = (XFontStruct *) font_private->xfont;
434 XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid);
435 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
437 XDrawImageString (drawable_private->xdisplay, drawable_private->xwindow,
438 gc_private->xgc, x, y, text, text_length);
440 else
442 XDrawImageString16 (drawable_private->xdisplay, drawable_private->xwindow,
443 gc_private->xgc, x, y, (XChar2b *) text, text_length / 2);
446 else if (font->type == GDK_FONT_FONTSET)
448 XFontSet fontset = (XFontSet) font_private->xfont;
449 XmbDrawImageString (drawable_private->xdisplay, drawable_private->xwindow,
450 fontset, gc_private->xgc, x, y, text, text_length);
452 else
453 g_error("undefined font type\n");
457 #endif
459 int draw_string (Window win, int x, int y, cache_type s, unsigned char *text, int length)
461 #ifdef GTK
462 GdkColor fg, bg;
463 #else
464 unsigned long fg, bg;
465 #endif
466 #ifdef GTK
467 set_style_color (s, &fg.pixel, &bg.pixel);
468 gdk_gc_set_background (win->gc, &bg);
469 gdk_gc_set_foreground (win->gc, &fg);
470 gdk_draw_image_text (win->text_area, GTK_WIDGET (win)->style->font, win->gc, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, text, length);
471 #else
472 set_style_color (s, &fg, &bg);
473 CSetBackgroundColor (bg);
474 CSetColor (fg);
475 CImageString (win, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, (char *) text, length);
476 #endif
478 /* if we printed a cursor: */
479 #ifdef GTK
480 if (s & (MOD_CURSOR * 256))
481 edit_set_cursor (win, x, y, bg.pixel, fg.pixel, per_char[*text], *text);
482 return x + gdk_text_width (GTK_WIDGET (win)->style->font, text, length);
483 #else
484 if (s & (MOD_CURSOR * 256))
485 edit_set_cursor (win, x, y, bg, fg, per_char[*text], *text);
486 return x + CTextWidth (win, (char *) text, length);
487 #endif
490 #define STYLE_DIFF (cache[i] != line[i] \
491 || ((cache[i] | line[i]) & (MOD_CURSOR * 256)) \
492 || !cache[i] || !line[i] \
495 int get_ignore_length (cache_type *cache, cache_type *line)
497 int i;
498 for (i = 0; i < CACHE_WIDTH; i++) {
499 if (STYLE_DIFF)
500 return i;
502 return CACHE_WIDTH;
505 static inline size_t lwstrnlen (const cache_type *s, size_t count)
507 const cache_type *sc;
508 for (sc = s; count-- && *sc != 0; ++sc);
509 return sc - s;
512 static inline size_t lwstrlen (const cache_type *s)
514 const cache_type *sc;
515 for (sc = s; *sc != 0; ++sc);
516 return sc - s;
519 int get_ignore_trailer (cache_type *cache, cache_type *line, int length)
521 int i;
522 int cache_len, line_len;
523 cache_len = lwstrnlen (cache, CACHE_WIDTH);
524 line_len = lwstrlen (line);
526 if (line_len > cache_len)
527 for (i = line_len - 1; i >= cache_len && i >= length; i--)
528 if (line[i] != ' ')
529 return i + 1;
531 for (i = cache_len - 1; i > length; i--)
532 if (STYLE_DIFF)
533 return i + 1;
535 return length + 1;
538 /* erases trailing bit of old line if a new line is printed over a longer old line */
539 void cover_trail (Window win, int x_new, int x_old, int y)
541 if (x_new < EDIT_TEXT_HORIZONTAL_OFFSET)
542 x_new = EDIT_TEXT_HORIZONTAL_OFFSET;
543 if (x_new >= x_old) /* no need to print */
544 return;
545 #ifdef GTK
546 gdk_gc_set_foreground (win->gc, &win->color[1]);
547 gdk_draw_rectangle (win->text_area, win->gc, 1, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT);
548 #else
549 CSetColor (edit_normal_background_color);
550 /* CSetColor (color_palette(12)); */
551 CRectangle (win, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT);
552 #endif
555 cache_type mode_spacing = 0;
557 #define NOT_VALID (-2000000000)
559 void edit_draw_proportional (void *data,
560 void (*converttext) (void *, long, cache_type *, int, int),
561 int calctextpos (void *, long, long *, int),
562 int scroll_right,
563 Window win,
564 int x_max,
565 long b,
566 int row,
567 int y,
568 int x_offset,
569 int tabwidth)
571 static struct cache_line lines[CACHE_HEIGHT];
572 static Window last = 0;
573 cache_type style, line[MAX_LINE_LEN], *p;
574 unsigned char text[128];
575 int x0, x, ignore_text = 0, ignore_trailer = 2000000000, j, i;
576 long q;
578 tab_width = tabwidth;
579 if (option_long_whitespace)
580 tab_width = tabwidth *= 2;
582 x_max -= 3;
584 /* if its not the same window, reset the screen rememberer */
585 if (last != win) {
586 last = win;
587 for (i = 0; i < CACHE_HEIGHT; i++) {
588 lines[i].x0 = NOT_VALID;
589 lines[i].x1 = x_max;
592 /* get point to start drawing */
593 x0 = (*calctextpos) (data, b, &q, -scroll_right + x_offset);
594 /* q contains the offset in the edit buffer */
596 /* translate this line into printable characters with a style (=color) high byte */
597 (*converttext) (data, q, line, x0, x_max - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET);
599 /* adjust for the horizontal scroll and border */
600 x0 += scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET;
601 x = x0;
603 /* is some of the line identical to that already printed so that we can ignore it? */
604 if (!EditExposeRedraw) {
605 if (lines[row].x0 == x0 && row < CACHE_HEIGHT) { /* i.e. also && lines[row].x0 != NOT_VALID */
606 ignore_text = get_ignore_length (lines[row].data, line);
607 if (fixed_font)
608 ignore_trailer = get_ignore_trailer (lines[row].data, line, ignore_text);
611 p = line;
612 j = 0;
613 while (*p) {
614 if (mode_spacing) {
615 if ((*p & 0x80) && (*p & mode_spacing)) {
616 #ifdef STILL_TO_BE_SUPPORTED
617 x += edit_insert_pixmap (win, x, y, *p & 0x7F);
618 /* the pixmap will be clipped, if it's taller than the
619 current font, else centred top to bottom */
620 #endif
621 p++;
622 continue;
624 goto do_text;
626 if ((*p & 0xFF) == '\t') {
627 j++;
628 if (j > ignore_text && j < ignore_trailer + 1)
629 x = draw_tab (win, x, y, *p, scroll_right);
630 else
631 x += next_tab (x, scroll_right);
632 p++;
633 } else {
634 do_text:
635 style = *p & 0xFFFFFF00UL;
636 i = 0;
637 do {
638 text[i++] = (unsigned char) *p++;
639 j++;
640 if (j == ignore_text || j == ignore_trailer)
641 break;
642 } while (i < 128 && *p && style == (*p & 0xFFFFFF00UL) && (*p & 0xFF) != '\t');
644 if (style & mode_spacing) {
645 int k;
646 for (k = 0; k < i; k++) {
647 draw_space (win, x, y, (0xFFFFFF00UL - mode_spacing) & style, text[k]);
648 x += text[k];
650 } else {
651 if (j > ignore_text && j < ignore_trailer + 1)
652 x = draw_string (win, x, y, style, text, i);
653 else
654 #ifdef GTK
655 x += gdk_text_width (GTK_WIDGET(win)->style->font, text, i);
656 #else
657 x += CTextWidth (win, (char *) text, i);
658 #endif
663 x = min (x, x_max);
664 if (!EditExposeRedraw || EditClear)
665 cover_trail (win, x, lines[row].x1, y);
666 memcpy (&(lines[row].data[ignore_text]),
667 &(line[ignore_text]),
668 (min (j, CACHE_WIDTH) - ignore_text) * sizeof (cache_type));
670 lines[row].data[min (j, CACHE_WIDTH)] = 0;
672 lines[row].x0 = x0;
673 lines[row].x1 = x;
674 if (EditExposeRedraw)
675 last = 0;
676 else
677 last = win;
681 void edit_draw_this_line_proportional (WEdit * edit, long b, int row, int start_column, int end_column)
683 int fg, bg;
684 if (row < 0 || row >= edit->num_widget_lines)
685 return;
687 if (row + edit->start_line > edit->total_lines)
688 b = 2000000000; /* force b out of range of the edit buffer for blanks lines */
690 if (end_column > CWidthOf (edit->widget))
691 end_column = CWidthOf (edit->widget);
693 edit_get_syntax_color (edit, b - 1, &fg, &bg);
695 edit_draw_proportional (edit,
696 (void (*) (void *, long, cache_type *, int, int)) convert_text,
697 (int (*) (void *, long, long *, int)) calc_text_pos,
698 edit->start_col, CWindowOf (edit->widget),
699 end_column, b, row, row * FONT_PIX_PER_LINE + EDIT_TEXT_VERTICAL_OFFSET,
700 EditExposeRedraw ? start_column : 0, per_char[' '] * TAB_SIZE);
704 /*********************************************************************************/
705 /* The remainder is for the text box widget */
706 /*********************************************************************************/
708 static inline int nroff_printable (int c)
710 return ((c >= ' ' && c <= '~') || c >= 160);
714 int calc_text_pos_str (unsigned char *text, long b, long *q, int l)
716 int x = 0, c = 0, xn = 0, d;
717 for (;;) {
718 d = c;
719 c = text[b];
720 switch (c) {
721 case '\0':
722 case '\n':
723 *q = b;
724 return x;
725 case '\t':
726 xn = next_tab_pos (x);
727 break;
728 case '\r':
729 break;
730 case '\b':
731 if (d)
732 xn = x - per_char[d];
733 break;
734 default:
735 if (!nroff_printable (c))
736 c = ' ';
737 xn = x + per_char[c];
738 break;
740 if (xn > l)
741 break;
742 x = xn;
743 b++;
745 *q = b;
746 return x;
749 int prop_font_strcolmove (unsigned char *str, int i, int column)
751 long q;
752 calc_text_pos_str (str, i, &q, column * FONT_MEAN_WIDTH);
753 return q;
756 #ifndef GTK
758 /* b is the beginning of the line. l is the length in pixels up to a point
759 on some character which is unknown. The character pos is returned in
760 *q and the characters pixel x pos from b is return'ed. */
761 int calc_text_pos2 (CWidget * w, long b, long *q, int l)
763 return calc_text_pos_str ((unsigned char *) w->text, b, q, l);
766 /* calcs pixel length of the line beginning at b up to upto */
767 int calc_text_len2 (CWidget *w, long b, long upto)
769 int x = 0, c = 0, d;
770 for (;;) {
771 if (b == upto)
772 return x;
773 d = c;
774 c = w->text[b];
775 switch (c) {
776 case '\n':
777 case '\0':
778 return x;
779 case '\t':
780 x = next_tab_pos (x);
781 break;
782 case '\r':
783 break;
784 case '\b':
785 if (d)
786 x -= per_char[d];
787 break;
788 default:
789 if (!nroff_printable (c))
790 c = ' ';
791 x += per_char[c];
792 break;
794 b++;
799 int highlight_this_line;
801 /* this is for the text widget (i.e. nroff formatting) */
802 void convert_text2 (CWidget * w, long q, cache_type *line, int x, int x_max)
804 int c = 0, d;
805 cache_type s, *p;
806 long m1, m2;
808 m1 = min (w->mark1, w->mark2);
809 m2 = max (w->mark1, w->mark2);
811 p = line;
812 *p = 0;
813 for (;;) {
814 d = c;
815 c = w->text[q];
816 *(p + 1) = 0;
817 *p |= 0xFFFF0000UL; /* default background colors */
818 if (highlight_this_line)
819 *p |= MOD_HIGHLIGHTED * 256;
820 if (q >= m1 && q < m2)
821 *p |= MOD_MARKED * 256;
822 switch (c) {
823 case '\0':
824 case '\n':
825 *p++ |= ' ';
826 if (highlight_this_line) {
827 q--;
828 x += per_char[' '];
829 } else
830 return;
831 break;
832 case '\t':
833 if (fixed_font) {
834 int i;
835 i = next_tab_pos (x) - x;
836 x += i;
837 s = *p;
838 while (i > 0) {
839 i -= per_char[' '];
840 *p++ = s | ' ';
841 *p = 0;
843 } else {
844 *p++ |= '\t';
845 x = next_tab_pos (x);
847 break;
848 case '\r':
849 break;
850 case '\b':
851 if (d) {
852 --p;
853 x -= per_char[d];
854 if (d == '_')
855 *p |= MOD_ITALIC * 256;
856 else
857 *p |= MOD_BOLD * 256;
859 break;
860 default:
861 if (!nroff_printable (c)) {
862 c = ' ';
863 *p |= MOD_ABNORMAL * 256;
865 x += per_char[c];
866 *p &= 0xFFFFFF00UL;
867 *p |= c;
868 p++;
869 break;
871 if (x > x_max)
872 break;
873 q++;
875 *p = 0;
879 #endif