ru.po: Heavily updated translation
[midnight-commander.git] / gtkedit / propfont.c
blobc115a1619eb527f2125916c7158f727b10ae2333
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., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307, USA.
20 #include <config.h>
21 #include "edit.h"
22 #if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)
23 #include "mad.h"
24 #endif
26 /* this file definatively relies on int being 32 bits or more */
28 int option_long_whitespace = 0;
30 #define MAX_LINE_LEN 1024
31 #define CACHE_WIDTH 256
32 #define CACHE_HEIGHT 128
35 struct cache_line {
36 int x0, x1;
37 cache_type data[CACHE_WIDTH];
40 extern unsigned char per_char[256];
42 /* background colors: marked is refers to mouse highlighting, highlighted refers to a found string. */
43 extern unsigned long edit_abnormal_color, edit_marked_abnormal_color;
44 extern unsigned long edit_highlighted_color, edit_marked_color;
45 extern unsigned long edit_normal_background_color;
47 /* foreground colors */
48 extern unsigned long edit_normal_foreground_color, edit_bold_color;
49 extern unsigned long edit_italic_color;
51 /* cursor color */
52 extern unsigned long edit_cursor_color;
54 extern int EditExposeRedraw;
55 extern int EditClear;
57 int set_style_color (
58 #ifdef GTK
59 Window win,
60 #endif
61 cache_type s, unsigned long *fg, unsigned long *bg)
63 int fgp, bgp, underlined = 0;
64 fgp = (s & 0xFF000000UL) >> 24;
65 /* NO_COLOR would give fgp == 255 */
66 if (fgp < 0xFF)
67 *fg = color_palette (fgp);
68 else
69 *fg = edit_normal_foreground_color;
70 bgp = (s & 0x00FF0000) >> 16;
71 if (bgp == 0xFE)
72 underlined = 1;
73 if (bgp < 0xFD)
74 *bg = color_palette (bgp);
75 else
76 *bg = edit_normal_background_color;
77 if (!(s & 0xFFFFFF00UL)) /* check this first as an optimization */
78 return underlined;
79 if (s & (MOD_ABNORMAL * 256)) {
80 *bg = edit_abnormal_color;
81 if (s & (MOD_MARKED * 256))
82 *bg = edit_marked_abnormal_color;
83 } else if (s & (MOD_HIGHLIGHTED * 256)) {
84 *bg = edit_highlighted_color;
85 } else if (s & (MOD_MARKED * 256)) {
86 *bg = edit_marked_color;
88 if (s & (MOD_BOLD * 256))
89 *fg = edit_bold_color;
90 if (s & (MOD_ITALIC * 256))
91 *fg = edit_italic_color;
92 if (s & (MOD_INVERSE * 256)) {
93 unsigned long t;
94 t = *fg;
95 *fg = *bg;
96 *bg = t;
97 if (*bg == COLOR_BLACK)
98 *bg = color_palette (1);
100 return underlined;
103 #ifdef GTK
104 #define set_style_color(s,f,b) set_style_color(win,s,f,b)
105 #endif
107 int tab_width = 1;
109 static inline int next_tab_pos (int x)
111 return x += tab_width - x % tab_width;
114 /* this now properly uses ctypes */
115 static inline int convert_to_long_printable (int c, unsigned char *t)
117 if (isgraph (c)) {
118 t[0] = c;
119 t[1] = 0;
120 return per_char[c];
122 if (c == ' ') {
123 if (option_long_whitespace) {
124 t[0] = ' ';
125 t[1] = ' ';
126 t[2] = 0;
127 return per_char[' '] + per_char[' '];
128 } else {
129 t[0] = ' ';
130 t[1] = 0;
131 return per_char[' '];
134 if (option_international_characters && per_char[c]) {
135 t[0] = c;
136 t[1] = 0;
137 return per_char[c];
139 if (c > '~') {
140 t[0] = ("0123456789ABCDEF")[c >> 4];
141 t[1] = ("0123456789ABCDEF")[c & 0xF];
142 t[2] = 'h';
143 t[3] = 0;
144 return per_char[t[0]] + per_char[t[1]] + per_char[t[2]];
146 t[0] = '^';
147 t[1] = c + '@';
148 t[2] = 0;
149 return per_char[t[0]] + per_char[t[1]];
152 /* same as above but just gets the length */
153 static inline int width_of_long_printable (int c)
155 if (isgraph (c))
156 return per_char[c];
157 if (c == ' ') {
158 if (option_long_whitespace)
159 return per_char[' '] + per_char[' '];
160 else
161 return per_char[' '];
163 if (option_international_characters && per_char[c])
164 return per_char[c];
165 if (c > '~')
166 return per_char[(unsigned char) ("0123456789ABCDEF")[c >> 4]] + per_char[(unsigned char) ("0123456789ABCDEF")[c & 0xF]] + per_char[(unsigned char) 'h'];
167 return per_char['^'] + per_char[c + '@'];
170 int edit_width_of_long_printable (int c)
172 return width_of_long_printable (c);
175 /* returns x pixel pos of char at offset *q with x not more than l */
176 int calc_text_pos (WEdit * edit, long b, long *q, int l)
178 int x = 0, c, xn;
179 for (;;) {
180 c = edit_get_byte (edit, b);
181 switch (c) {
182 case '\n':
183 *q = b;
184 if (x > edit->max_column)
185 edit->max_column = x;
186 return x;
187 case '\t':
188 xn = next_tab_pos (x);
189 break;
190 default:
191 xn = x + width_of_long_printable (c);
192 break;
194 if (xn > l)
195 break;
196 x = xn;
197 b++;
199 *q = b;
200 if (x > edit->max_column)
201 edit->max_column = x;
202 return x;
206 /* calcs pixel length of the line beginning at b up to upto */
207 int calc_text_len (WEdit * edit, long b, long upto)
209 int x = 0, c;
210 for (;;) {
211 if (b == upto) {
212 if (x > edit->max_column)
213 edit->max_column = x;
214 return x;
216 c = edit_get_byte (edit, b);
217 switch (c) {
218 case '\n':{
219 if (x > edit->max_column)
220 edit->max_column = x;
221 return x;
223 case '\t':
224 x = next_tab_pos (x);
225 break;
226 default:
227 x += width_of_long_printable (c);
228 break;
230 b++;
234 /* If pixels is zero this returns the count of pixels from current to upto. */
235 /* If upto is zero returns index of pixels across from current. */
236 long edit_move_forward3 (WEdit * edit, long current, int pixels, long upto)
238 if (upto) {
239 return calc_text_len (edit, current, upto);
240 } else if (pixels) {
241 long q;
242 calc_text_pos (edit, current, &q, pixels);
243 return q;
245 return current;
248 extern int column_highlighting;
250 /* gets the characters style (eg marked, highlighted) from its position in the edit buffer */
251 static inline cache_type get_style_fast (WEdit * edit, long q, int c)
253 cache_type s = 0;
254 unsigned int fg, bg;
255 if (!(isprint (c) || (option_international_characters && per_char[c])))
256 if (c != '\n' && c != '\t')
257 s |= MOD_ABNORMAL * 256;
258 edit_get_syntax_color (edit, q, (int *) &fg, (int *) &bg);
259 return s | ((fg & 0xFF) << 24) | ((bg & 0xFF) << 16);
262 /* gets the characters style (eg marked, highlighted) from its position in the edit buffer */
263 static inline cache_type get_style (WEdit * edit, long q, int c, long m1, long m2, int x)
265 cache_type s = 0;
266 unsigned int fg, bg;
267 if (q == edit->curs1)
268 s |= MOD_CURSOR * 256;
269 if (q >= m1 && q < m2) {
270 if (column_highlighting) {
271 if ((x >= edit->column1 && x < edit->column2)
272 || (x >= edit->column2 && x < edit->column1))
273 s |= MOD_INVERSE * 256;
274 } else {
275 s |= MOD_MARKED * 256;
278 if (q == edit->bracket)
279 s |= MOD_BOLD * 256;
280 if (q >= edit->found_start && q < edit->found_start + edit->found_len)
281 s |= MOD_HIGHLIGHTED * 256;
282 if (!(isprint (c) || (option_international_characters && per_char[c])))
283 if (c != '\n' && c != '\t')
284 s |= MOD_ABNORMAL * 256;
285 edit_get_syntax_color (edit, q, (int *) &fg, (int *) &bg);
286 return s | ((fg & 0xFF) << 24) | ((bg & 0xFF) << 16);
289 void convert_text (WEdit * edit, long q, cache_type * p, int x, int x_max, int row)
291 int c;
292 cache_type s;
293 long m1, m2, last;
294 unsigned char *r, text[4];
295 int book_mark_colors[10], book_mark;
296 eval_marks (edit, &m1, &m2);
297 book_mark = book_mark_query_all (edit, edit->start_line + row, book_mark_colors);
298 last = q + (x_max - x) / 2 + 2; /* for optimization, we say that the last character
299 of this line cannot have an offset greater than this.
300 This can be used to rule out uncommon text styles,
301 like a character with a cursor, or selected text */
302 if (book_mark) {
303 int the_end = 0, book_mark_cycle = 0;
304 for (;;) {
305 c = edit_get_byte (edit, q);
306 if (!the_end)
307 *p = get_style (edit, q, c, m1, m2, x);
308 if (the_end)
309 *p = 0;
310 *p = (*p & 0x0000FFFF) | (book_mark_colors[book_mark_cycle++ % book_mark] << 16);
311 switch (c) {
312 case '\n':
313 the_end = 1;
314 c = ' ';
315 q--;
316 goto the_default;
317 case '\t':
318 if (fixed_font) {
319 int t;
320 t = next_tab_pos (x);
321 t = min (t, x_max);
322 s = *p;
323 while (x < t) {
324 x += per_char[' '];
325 *p++ = s | ' ';
327 } else {
328 *p++ |= '\t';
329 x = next_tab_pos (x);
331 break;
332 default:
333 the_default:
334 x += convert_to_long_printable (c, text);
335 r = text;
336 s = *p;
337 *p++ = s | *r++;
338 if (!*r)
339 break;
340 *p++ = s | *r++;
341 if (!*r)
342 break;
343 *p++ = s | *r++;
344 break;
346 if (x >= x_max)
347 break;
348 q++;
350 } else if ((m2 < q || m1 > last) && (edit->curs1 < q || edit->curs1 > last) && \
351 (edit->found_start + edit->found_len < q || edit->found_start > last) &&
352 (edit->bracket < q || edit->bracket > last)) {
353 for (;;) {
354 c = edit_get_byte (edit, q);
355 *p = get_style_fast (edit, q, c);
356 switch (c) {
357 case '\n':
358 *p++ |= ' ';
359 *p = 0;
360 if (x > edit->max_column)
361 edit->max_column = x;
362 return;
363 case '\t':
364 if (fixed_font) {
365 int t;
366 t = next_tab_pos (x);
367 t = min (t, x_max);
368 s = *p;
369 while (x < t) {
370 x += per_char[' '];
371 *p++ = s | ' ';
373 } else {
374 *p++ |= '\t';
375 x = next_tab_pos (x);
377 break;
378 default:
379 x += convert_to_long_printable (c, text);
380 r = text;
381 s = *p;
382 *p++ = s | *r++;
383 if (!*r)
384 break;
385 *p++ = s | *r++;
386 if (!*r)
387 break;
388 *p++ = s | *r++;
389 break;
391 if (x >= x_max)
392 break;
393 q++;
395 } else {
396 for (;;) {
397 c = edit_get_byte (edit, q);
398 *p = get_style (edit, q, c, m1, m2, x);
399 switch (c) {
400 case '\n':
401 *p++ |= ' ';
402 *p = 0;
403 if (x > edit->max_column)
404 edit->max_column = x;
405 return;
406 case '\t':
407 if (fixed_font) {
408 int t;
409 t = next_tab_pos (x);
410 t = min (t, x_max);
411 s = *p;
412 while (x < t) {
413 x += per_char[' '];
414 *p++ = s | ' ';
416 } else {
417 *p++ |= '\t';
418 x = next_tab_pos (x);
420 break;
421 default:
422 x += convert_to_long_printable (c, text);
423 r = text;
424 s = *p;
425 *p++ = s | *r++;
426 if (!*r)
427 break;
428 *p++ = s | *r++;
429 if (!*r)
430 break;
431 *p++ = s | *r++;
432 break;
434 if (x >= x_max)
435 break;
436 q++;
439 if (x > edit->max_column)
440 edit->max_column = x;
441 *p = 0;
444 void edit_set_cursor (Window win, int x, int y, int bg, int fg, int width, char t)
446 #ifdef GTK
447 gdk_gc_set_foreground (win->gc, &win->color[18]);
448 gdk_draw_rectangle (win->text_area, win->gc, 0, x, y + FONT_OVERHEAD, width - 1, FONT_HEIGHT - 1);
449 #else
450 CSetColor (edit_cursor_color);
451 CLine (win, x, y + FONT_OVERHEAD,
452 x, y + FONT_HEIGHT - 1); /* non focussed cursor form */
453 CLine (win, x + 1, y + FONT_OVERHEAD,
454 x + width - 1, y + FONT_OVERHEAD);
455 set_cursor_position (win, x, y, width, FONT_HEIGHT, CURSOR_TYPE_EDITOR, t, bg, fg); /* widget library's flashing cursor */
456 #endif
459 static inline int next_tab (int x, int scroll_right)
461 return next_tab_pos (x - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET) - x + scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET;
464 int draw_tab (Window win, int x, int y, cache_type s, int scroll_right)
466 int l;
467 #ifdef GTK
468 GdkColor fg, bg;
469 #else
470 unsigned long fg, bg;
471 #endif
472 l = next_tab (x, scroll_right);
473 #ifdef GTK
474 set_style_color (s, &fg.pixel, &bg.pixel);
475 gdk_gc_set_foreground (win->gc, &bg);
476 gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
477 /* if we printed a cursor: */
478 if (s & (MOD_CURSOR * 256))
479 edit_set_cursor (win, x, y, bg.pixel, fg.pixel, per_char[' '], ' ');
480 #else
481 set_style_color (s, &fg, &bg);
482 CSetColor (bg);
483 CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
484 /* if we printed a cursor: */
485 if (s & (MOD_CURSOR * 256))
486 edit_set_cursor (win, x, y, bg, fg, per_char[' '], ' ');
487 #endif
488 return x + l;
491 #ifdef GTK
492 #include <gdk/gdk.h>
493 #endif
495 static inline void draw_space (Window win, int x, int y, cache_type s, int l)
497 #ifdef GTK
498 GdkColor fg, bg;
499 #else
500 unsigned long fg, bg;
501 #endif
502 #ifdef GTK
503 set_style_color (s, &fg.pixel, &bg.pixel);
504 gdk_gc_set_foreground (win->gc, &bg);
505 gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
506 #else
507 set_style_color (s, &fg, &bg);
508 CSetColor (bg);
509 CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
510 /* if we printed a cursor: */
511 if (s & (MOD_CURSOR * 256))
512 edit_set_cursor (win, x, y, bg, fg, per_char[' '], ' ');
513 #endif
516 #ifdef GTK
518 void
519 gdk_draw_image_text (GdkDrawable *drawable,
520 GdkFont *font,
521 GdkGC *gc,
522 gint x,
523 gint y,
524 const gchar *text,
525 gint text_length)
527 GdkWindowPrivate *drawable_private;
528 GdkFontPrivate *font_private;
529 GdkGCPrivate *gc_private;
531 g_return_if_fail (drawable != NULL);
532 g_return_if_fail (font != NULL);
533 g_return_if_fail (gc != NULL);
534 g_return_if_fail (text != NULL);
536 drawable_private = (GdkWindowPrivate*) drawable;
537 if (drawable_private->destroyed)
538 return;
539 gc_private = (GdkGCPrivate*) gc;
540 font_private = (GdkFontPrivate*) font;
542 if (font->type == GDK_FONT_FONT)
544 XFontStruct *xfont = (XFontStruct *) font_private->xfont;
545 XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid);
546 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
548 XDrawImageString (drawable_private->xdisplay, drawable_private->xwindow,
549 gc_private->xgc, x, y, text, text_length);
551 else
553 XDrawImageString16 (drawable_private->xdisplay, drawable_private->xwindow,
554 gc_private->xgc, x, y, (XChar2b *) text, text_length / 2);
557 else if (font->type == GDK_FONT_FONTSET)
559 XFontSet fontset = (XFontSet) font_private->xfont;
560 XmbDrawImageString (drawable_private->xdisplay, drawable_private->xwindow,
561 fontset, gc_private->xgc, x, y, text, text_length);
563 else
564 g_error("undefined font type\n");
568 #endif
570 int draw_string (Window win, int x, int y, cache_type s, unsigned char *text, int length)
572 #ifdef GTK
573 GdkColor fg, bg;
574 #else
575 unsigned long fg, bg;
576 int underlined, l;
577 #endif
578 #ifdef GTK
579 set_style_color (s, &fg.pixel, &bg.pixel);
580 gdk_gc_set_background (win->gc, &bg);
581 gdk_gc_set_foreground (win->gc, &fg);
582 gdk_draw_image_text (win->text_area, GTK_WIDGET (win)->style->font, win->gc, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, text, length);
583 #else
584 underlined = set_style_color (s, &fg, &bg);
585 CSetBackgroundColor (bg);
586 CSetColor (fg);
587 CImageString (win, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, (char *) text, length);
588 l = CTextWidth (win, (char *) text, length);
589 if (underlined) {
590 int i, h, inc;
591 inc = FONT_MEAN_WIDTH * 2 / 3;
592 CSetColor (color_palette (18));
593 h = (x / inc) & 1;
594 CLine (win, x, y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h, x + min (l, inc - (x % inc) - 1), y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h);
595 h = h ^ 1;
596 for (i = inc - min (l, (x % inc)); i < l; i += inc) {
597 CLine (win, x + i, y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h, x + min (l, i + inc - 1), y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h);
598 h = h ^ 1;
601 #endif
602 /* if we printed a cursor: */
603 #ifdef GTK
604 if (s & (MOD_CURSOR * 256))
605 edit_set_cursor (win, x, y, bg.pixel, fg.pixel, per_char[*text], *text);
606 return x + gdk_text_width (GTK_WIDGET (win)->style->font, text, length);
607 #else
608 if (s & (MOD_CURSOR * 256))
609 edit_set_cursor (win, x, y, bg, fg, per_char[*text], *text);
610 return x + l;
611 #endif
614 #define STYLE_DIFF (*cache != *line \
615 || ((*cache | *line) & (MOD_CURSOR * 256)) \
616 || !*cache || !*line)
618 int get_ignore_length (cache_type *cache, cache_type *line)
620 int i;
621 for (i = 0; i < CACHE_WIDTH; i++, line++, cache++) {
622 if (STYLE_DIFF)
623 return i;
625 return CACHE_WIDTH;
628 static inline size_t lwstrnlen (const cache_type *s, size_t count)
630 const cache_type *sc;
631 for (sc = s; count-- && *sc != 0; ++sc);
632 return sc - s;
635 static inline size_t lwstrlen (const cache_type *s)
637 const cache_type *sc;
638 for (sc = s; *sc != 0; ++sc);
639 return sc - s;
642 int get_ignore_trailer (cache_type *cache, cache_type *line, int length)
644 int i;
645 int cache_len, line_len;
646 cache_len = lwstrnlen (cache, CACHE_WIDTH);
647 line_len = lwstrlen (line);
649 if (line_len > cache_len)
650 for (i = line_len - 1; i >= cache_len && i >= length; i--)
651 if (line[i] != ' ')
652 return i + 1;
654 for (i = cache_len - 1, line = line + i, cache = cache + i; i > length; i--, line--, cache--)
655 if (STYLE_DIFF)
656 return i + 1;
658 return length + 1;
661 /* erases trailing bit of old line if a new line is printed over a longer old line */
662 static void cover_trail (Window win, int x_start, int x_new, int x_old, int y)
664 if (x_new < EDIT_TEXT_HORIZONTAL_OFFSET)
665 x_new = EDIT_TEXT_HORIZONTAL_OFFSET;
666 if (x_new < x_old) { /* no need to print */
667 #ifdef GTK
668 gdk_gc_set_foreground (win->gc, &win->color[1]);
669 gdk_draw_rectangle (win->text_area, win->gc, 1, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT);
670 #else
671 CSetColor (edit_normal_background_color);
672 CRectangle (win, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT + (FONT_OVERHEAD != 0 && !fixed_font));
673 #endif
674 } else {
675 #ifdef GTK
676 gdk_gc_set_foreground (win->gc, &win->color[1]);
677 #else
678 CSetColor (edit_normal_background_color);
679 #endif
681 /* true type fonts print stuff out of the bounding box (aaaaaaaaarrrgh!!) */
682 if (!fixed_font)
683 if (FONT_OVERHEAD && x_new > EDIT_TEXT_HORIZONTAL_OFFSET)
684 #ifdef GTK
685 gdk_draw_line (win->text_area, win->gc, max (x_start, EDIT_TEXT_HORIZONTAL_OFFSET), y + FONT_HEIGHT + FONT_OVERHEAD, x_new - 1, y + FONT_HEIGHT + FONT_OVERHEAD);
686 #else
687 CLine (win, max (x_start, EDIT_TEXT_HORIZONTAL_OFFSET), y + FONT_HEIGHT + FONT_OVERHEAD, x_new - 1, y + FONT_HEIGHT + FONT_OVERHEAD);
688 #endif
691 cache_type mode_spacing = 0;
693 #define NOT_VALID (-2000000000)
695 void edit_draw_proportional (void *data,
696 void (*converttext) (void *, long, cache_type *, int, int, int),
697 int calctextpos (void *, long, long *, int),
698 int scroll_right,
699 Window win,
700 int x_max,
701 long b,
702 int row,
703 int y,
704 int x_offset,
705 int tabwidth)
707 static struct cache_line lines[CACHE_HEIGHT];
708 static Window last = 0;
709 cache_type style, line[MAX_LINE_LEN], *p;
710 unsigned char text[128];
711 int x0, x, ignore_text = 0, ignore_trailer = 2000000000, j, i;
712 long q;
714 tab_width = tabwidth;
715 if (option_long_whitespace)
716 tab_width = tabwidth *= 2;
718 x_max -= 3;
720 /* if its not the same window, reset the screen rememberer */
721 if (last != win) {
722 last = win;
723 for (i = 0; i < CACHE_HEIGHT; i++) {
724 lines[i].x0 = NOT_VALID;
725 lines[i].x1 = x_max;
728 /* get point to start drawing */
729 x0 = (*calctextpos) (data, b, &q, -scroll_right + x_offset);
730 /* q contains the offset in the edit buffer */
732 /* translate this line into printable characters with a style (=color) high byte */
733 (*converttext) (data, q, line, x0, x_max - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET, row);
735 /* adjust for the horizontal scroll and border */
736 x0 += scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET;
737 x = x0;
739 /* is some of the line identical to that already printed so that we can ignore it? */
740 if (!EditExposeRedraw) {
741 if (lines[row].x0 == x0 && row < CACHE_HEIGHT) { /* i.e. also && lines[row].x0 != NOT_VALID */
742 ignore_text = get_ignore_length (lines[row].data, line);
743 if (fixed_font)
744 ignore_trailer = get_ignore_trailer (lines[row].data, line, ignore_text);
747 p = line;
748 j = 0;
749 while (*p) {
750 if (mode_spacing) {
751 if ((*p & 0x80) && (*p & mode_spacing)) {
752 #ifdef STILL_TO_BE_SUPPORTED
753 x += edit_insert_pixmap (win, x, y, *p & 0x7F);
754 /* the pixmap will be clipped, if it's taller than the
755 current font, else centred top to bottom */
756 #endif
757 p++;
758 continue;
760 goto do_text;
762 if ((*p & 0xFF) == '\t') {
763 j++;
764 if (j > ignore_text && j < ignore_trailer + 1)
765 x = draw_tab (win, x, y, *p, scroll_right);
766 else
767 x += next_tab (x, scroll_right);
768 p++;
769 } else {
770 do_text:
771 style = *p & 0xFFFFFF00UL;
772 i = 0;
773 do {
774 text[i++] = (unsigned char) *p++;
775 j++;
776 if (j == ignore_text || j == ignore_trailer)
777 break;
778 } while (i < 128 && *p && style == (*p & 0xFFFFFF00UL) && (*p & 0xFF) != '\t');
780 if (style & mode_spacing) {
781 int k;
782 for (k = 0; k < i; k++) {
783 draw_space (win, x, y, (0xFFFFFF00UL - mode_spacing) & style, text[k]);
784 x += text[k];
786 } else {
787 if (j > ignore_text && j < ignore_trailer + 1)
788 x = draw_string (win, x, y, style, text, i);
789 else
790 #ifdef GTK
791 x += gdk_text_width (GTK_WIDGET(win)->style->font, text, i);
792 #else
793 x += CTextWidth (win, (char *) text, i);
794 #endif
799 x = min (x, x_max);
800 if (!EditExposeRedraw || EditClear)
801 cover_trail (win, x0, x, lines[row].x1, y);
802 memcpy (&(lines[row].data[ignore_text]),
803 &(line[ignore_text]),
804 (min (j, CACHE_WIDTH) - ignore_text) * sizeof (cache_type));
806 lines[row].data[min (j, CACHE_WIDTH)] = 0;
808 lines[row].x0 = x0;
809 lines[row].x1 = x;
810 if (EditExposeRedraw)
811 last = 0;
812 else
813 last = win;
817 void edit_draw_this_line_proportional (WEdit * edit, long b, int row, int start_column, int end_column)
819 int fg, bg;
820 if (row < 0 || row >= edit->num_widget_lines)
821 return;
823 if (row + edit->start_line > edit->total_lines)
824 b = edit->last_byte + 1; /* force b out of range of the edit buffer for blanks lines */
826 if (end_column > CWidthOf (edit->widget))
827 end_column = CWidthOf (edit->widget);
829 edit_get_syntax_color (edit, b - 1, &fg, &bg);
831 edit_draw_proportional (edit,
832 (void (*) (void *, long, cache_type *, int, int, int)) convert_text,
833 (int (*) (void *, long, long *, int)) calc_text_pos,
834 edit->start_col, CWindowOf (edit->widget),
835 end_column, b, row, row * FONT_PIX_PER_LINE + EDIT_TEXT_VERTICAL_OFFSET,
836 EditExposeRedraw ? start_column : 0, per_char[' '] * TAB_SIZE);
840 /*********************************************************************************/
841 /* The remainder is for the text box widget */
842 /*********************************************************************************/
844 static inline int nroff_printable (int c)
846 return isprint (c);
850 int calc_text_pos_str (unsigned char *text, long b, long *q, int l)
852 int x = 0, c = 0, xn = 0, d;
853 for (;;) {
854 d = c;
855 c = text[b];
856 switch (c) {
857 case '\0':
858 case '\n':
859 *q = b;
860 return x;
861 case '\t':
862 xn = next_tab_pos (x);
863 break;
864 case '\r':
865 break;
866 case '\b':
867 if (d)
868 xn = x - per_char[d];
869 break;
870 default:
871 if (!nroff_printable (c))
872 c = ' ';
873 xn = x + per_char[c];
874 break;
876 if (xn > l)
877 break;
878 x = xn;
879 b++;
881 *q = b;
882 return x;
885 int prop_font_strcolmove (unsigned char *str, int i, int column)
887 long q;
888 calc_text_pos_str (str, i, &q, column * FONT_MEAN_WIDTH);
889 return q;
892 #ifndef GTK
894 /* b is the beginning of the line. l is the length in pixels up to a point
895 on some character which is unknown. The character pos is returned in
896 *q and the characters pixel x pos from b is return'ed. */
897 int calc_text_pos2 (CWidget * w, long b, long *q, int l)
899 return calc_text_pos_str ((unsigned char *) w->text, b, q, l);
902 /* calcs pixel length of the line beginning at b up to upto */
903 int calc_text_len2 (CWidget *w, long b, long upto)
905 int x = 0, c = 0, d;
906 for (;;) {
907 if (b == upto)
908 return x;
909 d = c;
910 c = w->text[b];
911 switch (c) {
912 case '\n':
913 case '\0':
914 return x;
915 case '\t':
916 x = next_tab_pos (x);
917 break;
918 case '\r':
919 break;
920 case '\b':
921 if (d)
922 x -= per_char[d];
923 break;
924 default:
925 if (!nroff_printable (c))
926 c = ' ';
927 x += per_char[c];
928 break;
930 b++;
935 int highlight_this_line;
937 /* this is for the text widget (i.e. nroff formatting) */
938 void convert_text2 (CWidget * w, long q, cache_type *line, int x, int x_max, int row)
940 int c = 0, d;
941 cache_type s, *p;
942 long m1, m2;
944 m1 = min (w->mark1, w->mark2);
945 m2 = max (w->mark1, w->mark2);
947 p = line;
948 *p = 0;
949 for (;;) {
950 d = c;
951 c = w->text[q];
952 *(p + 1) = 0;
953 *p |= 0xFFFF0000UL; /* default background colors */
954 if (highlight_this_line)
955 *p |= MOD_HIGHLIGHTED * 256;
956 if (q >= m1 && q < m2)
957 *p |= MOD_MARKED * 256;
958 switch (c) {
959 case '\0':
960 case '\n':
961 *p++ |= ' ';
962 if (highlight_this_line) {
963 q--;
964 x += per_char[' '];
965 } else
966 return;
967 break;
968 case '\t':
969 if (fixed_font) {
970 int i;
971 i = next_tab_pos (x) - x;
972 x += i;
973 s = *p;
974 while (i > 0) {
975 i -= per_char[' '];
976 *p++ = s | ' ';
977 *p = 0;
979 } else {
980 *p++ |= '\t';
981 x = next_tab_pos (x);
983 break;
984 case '\r':
985 break;
986 case '\b':
987 if (d) {
988 --p;
989 x -= per_char[d];
990 if (d == '_')
991 *p |= MOD_ITALIC * 256;
992 else
993 *p |= MOD_BOLD * 256;
995 break;
996 default:
997 if (!nroff_printable (c)) {
998 c = ' ';
999 *p |= MOD_ABNORMAL * 256;
1001 x += per_char[c];
1002 *p &= 0xFFFFFF00UL;
1003 *p |= c;
1004 p++;
1005 break;
1007 if (x > x_max)
1008 break;
1009 q++;
1011 *p = 0;
1015 #endif