my homework was late :-)
[midnight-commander.git] / gtkedit / propfont.c
blobd1e57f817476123ad5b98e9b6fb548a45795d549
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];
41 /* background colors: marked is refers to mouse highlighting, highlighted refers to a found string. */
42 extern unsigned long edit_abnormal_color, edit_marked_abnormal_color;
43 extern unsigned long edit_highlighted_color, edit_marked_color;
44 extern unsigned long edit_normal_background_color;
46 /* foreground colors */
47 extern unsigned long edit_normal_foreground_color, edit_bold_color;
48 extern unsigned long edit_italic_color;
50 /* cursor color */
51 extern unsigned long edit_cursor_color;
53 extern int EditExposeRedraw;
54 extern int EditClear;
56 int set_style_color (
57 #ifdef GTK
58 Window win,
59 #endif
60 cache_type s, unsigned long *fg, unsigned long *bg)
62 int fgp, bgp, underlined = 0;
63 fgp = (s & 0xFF000000UL) >> 24;
64 /* NO_COLOR would give fgp == 255 */
65 if (fgp < 0xFF)
66 *fg = color_palette (fgp);
67 else
68 *fg = edit_normal_foreground_color;
69 bgp = (s & 0x00FF0000) >> 16;
70 if (bgp == 0xFE)
71 underlined = 1;
72 if (bgp < 0xFD)
73 *bg = color_palette (bgp);
74 else
75 *bg = edit_normal_background_color;
76 if (!(s & 0xFFFFFF00UL)) /* check this first as an optimization */
77 return underlined;
78 if (s & (MOD_ABNORMAL * 256)) {
79 *bg = edit_abnormal_color;
80 if (s & (MOD_MARKED * 256))
81 *bg = edit_marked_abnormal_color;
82 } else if (s & (MOD_HIGHLIGHTED * 256)) {
83 *bg = edit_highlighted_color;
84 } else if (s & (MOD_MARKED * 256)) {
85 *bg = edit_marked_color;
87 if (s & (MOD_BOLD * 256))
88 *fg = edit_bold_color;
89 if (s & (MOD_ITALIC * 256))
90 *fg = edit_italic_color;
91 if (s & (MOD_INVERSE * 256)) {
92 unsigned long t;
93 t = *fg;
94 *fg = *bg;
95 *bg = t;
96 if (*bg == COLOR_BLACK)
97 *bg = color_palette (1);
99 return underlined;
102 #ifdef GTK
103 #define set_style_color(s,f,b) set_style_color(win,s,f,b)
104 #endif
106 int tab_width = 1;
108 static inline int next_tab_pos (int x)
110 return x += tab_width - x % tab_width;
113 /* this now properly uses ctypes */
114 static inline int convert_to_long_printable (int c, unsigned char *t)
116 if (isgraph (c)) {
117 t[0] = c;
118 t[1] = 0;
119 return FONT_PER_CHAR[c];
121 if (c == ' ') {
122 if (option_long_whitespace) {
123 t[0] = ' ';
124 t[1] = ' ';
125 t[2] = 0;
126 return FONT_PER_CHAR[' '] + FONT_PER_CHAR[' '];
127 } else {
128 t[0] = ' ';
129 t[1] = 0;
130 return FONT_PER_CHAR[' '];
133 if (option_international_characters && FONT_PER_CHAR[c]) {
134 t[0] = c;
135 t[1] = 0;
136 return FONT_PER_CHAR[c];
138 if (c > '~') {
139 t[0] = ("0123456789ABCDEF")[c >> 4];
140 t[1] = ("0123456789ABCDEF")[c & 0xF];
141 t[2] = 'h';
142 t[3] = 0;
143 return FONT_PER_CHAR[t[0]] + FONT_PER_CHAR[t[1]] + FONT_PER_CHAR[t[2]];
145 t[0] = '^';
146 t[1] = c + '@';
147 t[2] = 0;
148 return FONT_PER_CHAR[t[0]] + FONT_PER_CHAR[t[1]];
151 /* same as above but just gets the length */
152 static inline int width_of_long_printable (int c)
154 if (isgraph (c))
155 return FONT_PER_CHAR[c];
156 if (c == ' ') {
157 if (option_long_whitespace)
158 return FONT_PER_CHAR[' '] + FONT_PER_CHAR[' '];
159 else
160 return FONT_PER_CHAR[' '];
162 if (option_international_characters && FONT_PER_CHAR[c])
163 return FONT_PER_CHAR[c];
164 if (c > '~')
165 return FONT_PER_CHAR[(unsigned char) ("0123456789ABCDEF")[c >> 4]] + FONT_PER_CHAR[(unsigned char) ("0123456789ABCDEF")[c & 0xF]] + FONT_PER_CHAR[(unsigned char) 'h'];
166 return FONT_PER_CHAR['^'] + FONT_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 static 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 static 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 CPushFont ("editor", 0);
238 if (upto) {
239 current = calc_text_len (edit, current, upto);
240 } else if (pixels) {
241 long q;
242 calc_text_pos (edit, current, &q, pixels);
243 current = q;
245 CPopFont ();
246 return current;
249 extern int column_highlighting;
251 /* gets the characters style (eg marked, highlighted) from its position in the edit buffer */
252 static inline cache_type get_style_fast (WEdit * edit, long q, int c)
254 cache_type s = 0;
255 unsigned int fg, bg;
256 if (!(isprint (c) || (option_international_characters && FONT_PER_CHAR[c])))
257 if (c != '\n' && c != '\t')
258 s |= MOD_ABNORMAL * 256;
259 edit_get_syntax_color (edit, q, (int *) &fg, (int *) &bg);
260 return s | ((fg & 0xFF) << 24) | ((bg & 0xFF) << 16);
263 /* gets the characters style (eg marked, highlighted) from its position in the edit buffer */
264 static inline cache_type get_style (WEdit * edit, long q, int c, long m1, long m2, int x)
266 cache_type s = 0;
267 unsigned int fg, bg;
268 if (q == edit->curs1)
269 s |= MOD_CURSOR * 256;
270 if (q >= m1 && q < m2) {
271 if (column_highlighting) {
272 if ((x >= edit->column1 && x < edit->column2)
273 || (x >= edit->column2 && x < edit->column1))
274 s |= MOD_INVERSE * 256;
275 } else {
276 s |= MOD_MARKED * 256;
279 if (q == edit->bracket)
280 s |= MOD_BOLD * 256;
281 if (q >= edit->found_start && q < edit->found_start + edit->found_len)
282 s |= MOD_HIGHLIGHTED * 256;
283 if (!(isprint (c) || (option_international_characters && FONT_PER_CHAR[c])))
284 if (c != '\n' && c != '\t')
285 s |= MOD_ABNORMAL * 256;
286 edit_get_syntax_color (edit, q, (int *) &fg, (int *) &bg);
287 return s | ((fg & 0xFF) << 24) | ((bg & 0xFF) << 16);
290 static void convert_text (WEdit * edit, long q, cache_type * p, int x, int x_max, int row)
292 int c;
293 cache_type s;
294 long m1, m2, last;
295 unsigned char *r, text[4];
296 int book_mark_colors[10], book_mark;
297 eval_marks (edit, &m1, &m2);
298 book_mark = book_mark_query_all (edit, edit->start_line + row, book_mark_colors);
299 last = q + (x_max - x) / 2 + 2; /* for optimization, we say that the last character
300 of this line cannot have an offset greater than this.
301 This can be used to rule out uncommon text styles,
302 like a character with a cursor, or selected text */
303 if (book_mark) {
304 int the_end = 0, book_mark_cycle = 0;
305 for (;;) {
306 c = edit_get_byte (edit, q);
307 if (!the_end)
308 *p = get_style (edit, q, c, m1, m2, x);
309 if (the_end)
310 *p = 0;
311 *p = (*p & 0x0000FFFF) | (book_mark_colors[book_mark_cycle++ % book_mark] << 16);
312 switch (c) {
313 case '\n':
314 the_end = 1;
315 c = ' ';
316 q--;
317 goto the_default;
318 case '\t':
319 if (FIXED_FONT) {
320 int t;
321 t = next_tab_pos (x);
322 t = min (t, x_max);
323 s = *p;
324 while (x < t) {
325 x += FONT_PER_CHAR[' '];
326 *p++ = s | ' ';
328 } else {
329 *p++ |= '\t';
330 x = next_tab_pos (x);
332 break;
333 default:
334 the_default:
335 x += convert_to_long_printable (c, text);
336 r = text;
337 s = *p;
338 *p++ = s | *r++;
339 if (!*r)
340 break;
341 *p++ = s | *r++;
342 if (!*r)
343 break;
344 *p++ = s | *r++;
345 break;
347 if (x >= x_max)
348 break;
349 q++;
351 } else if ((m2 < q || m1 > last) && (edit->curs1 < q || edit->curs1 > last) && \
352 (edit->found_start + edit->found_len < q || edit->found_start > last) &&
353 (edit->bracket < q || edit->bracket > last)) {
354 for (;;) {
355 c = edit_get_byte (edit, q);
356 *p = get_style_fast (edit, q, c);
357 switch (c) {
358 case '\n':
359 *p++ |= ' ';
360 *p = 0;
361 if (x > edit->max_column)
362 edit->max_column = x;
363 return;
364 case '\t':
365 if (FIXED_FONT) {
366 int t;
367 t = next_tab_pos (x);
368 t = min (t, x_max);
369 s = *p;
370 while (x < t) {
371 x += FONT_PER_CHAR[' '];
372 *p++ = s | ' ';
374 } else {
375 *p++ |= '\t';
376 x = next_tab_pos (x);
378 break;
379 default:
380 x += convert_to_long_printable (c, text);
381 r = text;
382 s = *p;
383 *p++ = s | *r++;
384 if (!*r)
385 break;
386 *p++ = s | *r++;
387 if (!*r)
388 break;
389 *p++ = s | *r++;
390 break;
392 if (x >= x_max)
393 break;
394 q++;
396 } else {
397 for (;;) {
398 c = edit_get_byte (edit, q);
399 *p = get_style (edit, q, c, m1, m2, x);
400 switch (c) {
401 case '\n':
402 *p++ |= ' ';
403 *p = 0;
404 if (x > edit->max_column)
405 edit->max_column = x;
406 return;
407 case '\t':
408 if (FIXED_FONT) {
409 int t;
410 t = next_tab_pos (x);
411 t = min (t, x_max);
412 s = *p;
413 while (x < t) {
414 x += FONT_PER_CHAR[' '];
415 *p++ = s | ' ';
417 } else {
418 *p++ |= '\t';
419 x = next_tab_pos (x);
421 break;
422 default:
423 x += convert_to_long_printable (c, text);
424 r = text;
425 s = *p;
426 *p++ = s | *r++;
427 if (!*r)
428 break;
429 *p++ = s | *r++;
430 if (!*r)
431 break;
432 *p++ = s | *r++;
433 break;
435 if (x >= x_max)
436 break;
437 q++;
440 if (x > edit->max_column)
441 edit->max_column = x;
442 *p = 0;
445 void edit_set_cursor (Window win, int x, int y, int bg, int fg, int width, char t)
447 #ifdef GTK
448 gdk_gc_set_foreground (win->gc, &win->color[18]);
449 gdk_draw_rectangle (win->text_area, win->gc, 0, x, y + FONT_OVERHEAD, width - 1, FONT_HEIGHT - 1);
450 #else
451 CSetColor (edit_cursor_color);
452 CLine (win, x, y + FONT_OVERHEAD,
453 x, y + FONT_HEIGHT - 1); /* non focussed cursor form */
454 CLine (win, x + 1, y + FONT_OVERHEAD,
455 x + width - 1, y + FONT_OVERHEAD);
456 set_cursor_position (win, x, y, width, FONT_HEIGHT, CURSOR_TYPE_EDITOR, t, bg, fg); /* widget library's flashing cursor */
457 #endif
460 static inline int next_tab (int x, int scroll_right)
462 return next_tab_pos (x - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET) - x + scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET;
465 static int draw_tab (Window win, int x, int y, cache_type s, int scroll_right)
467 int l;
468 #ifdef GTK
469 GdkColor fg, bg;
470 #else
471 unsigned long fg, bg;
472 #endif
473 l = next_tab (x, scroll_right);
474 #ifdef GTK
475 set_style_color (s, &fg.pixel, &bg.pixel);
476 gdk_gc_set_foreground (win->gc, &bg);
477 gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
478 /* if we printed a cursor: */
479 if (s & (MOD_CURSOR * 256))
480 edit_set_cursor (win, x, y, bg.pixel, fg.pixel, FONT_PER_CHAR[' '], ' ');
481 #else
482 set_style_color (s, &fg, &bg);
483 CSetColor (bg);
484 CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
485 /* if we printed a cursor: */
486 if (s & (MOD_CURSOR * 256))
487 edit_set_cursor (win, x, y, bg, fg, FONT_PER_CHAR[' '], ' ');
488 #endif
489 return x + l;
492 #ifdef GTK
493 #include <gdk/gdk.h>
494 #endif
496 static inline void draw_space (Window win, int x, int y, cache_type s, int l)
498 #ifdef GTK
499 GdkColor fg, bg;
500 #else
501 unsigned long fg, bg;
502 #endif
503 #ifdef GTK
504 set_style_color (s, &fg.pixel, &bg.pixel);
505 gdk_gc_set_foreground (win->gc, &bg);
506 gdk_draw_rectangle (win->text_area, win->gc, 1, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
507 #else
508 set_style_color (s, &fg, &bg);
509 CSetColor (bg);
510 CRectangle (win, x, y + FONT_OVERHEAD, l, FONT_HEIGHT);
511 /* if we printed a cursor: */
512 if (s & (MOD_CURSOR * 256))
513 edit_set_cursor (win, x, y, bg, fg, FONT_PER_CHAR[' '], ' ');
514 #endif
517 #ifdef GTK
519 void
520 gdk_draw_image_text (GdkDrawable *drawable,
521 GdkFont *font,
522 GdkGC *gc,
523 gint x,
524 gint y,
525 const gchar *text,
526 gint text_length)
528 GdkWindowPrivate *drawable_private;
529 GdkFontPrivate *font_private;
530 GdkGCPrivate *gc_private;
532 g_return_if_fail (drawable != NULL);
533 g_return_if_fail (font != NULL);
534 g_return_if_fail (gc != NULL);
535 g_return_if_fail (text != NULL);
537 drawable_private = (GdkWindowPrivate*) drawable;
538 if (drawable_private->destroyed)
539 return;
540 gc_private = (GdkGCPrivate*) gc;
541 font_private = (GdkFontPrivate*) font;
543 if (font->type == GDK_FONT_FONT)
545 XFontStruct *xfont = (XFontStruct *) font_private->xfont;
546 XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid);
547 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
549 XDrawImageString (drawable_private->xdisplay, drawable_private->xwindow,
550 gc_private->xgc, x, y, text, text_length);
552 else
554 XDrawImageString16 (drawable_private->xdisplay, drawable_private->xwindow,
555 gc_private->xgc, x, y, (XChar2b *) text, text_length / 2);
558 else if (font->type == GDK_FONT_FONTSET)
560 XFontSet fontset = (XFontSet) font_private->xfont;
561 XmbDrawImageString (drawable_private->xdisplay, drawable_private->xwindow,
562 fontset, gc_private->xgc, x, y, text, text_length);
564 else
565 g_error("undefined font type\n");
569 #endif
571 static int draw_string (Window win, int x, int y, cache_type s, unsigned char *text, int length)
573 #ifdef GTK
574 GdkColor fg, bg;
575 #else
576 unsigned long fg, bg;
577 int underlined, l;
578 #endif
579 #ifdef GTK
580 set_style_color (s, &fg.pixel, &bg.pixel);
581 gdk_gc_set_background (win->gc, &bg);
582 gdk_gc_set_foreground (win->gc, &fg);
583 gdk_draw_image_text (win->text_area, GTK_WIDGET (win)->style->font, win->gc, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, text, length);
584 #else
585 underlined = set_style_color (s, &fg, &bg);
586 CSetBackgroundColor (bg);
587 CSetColor (fg);
588 CImageText (win, x + FONT_OFFSET_X, y + FONT_OFFSET_Y, (char *) text, length);
589 l = CTextWidth ((char *) text, length);
590 if (underlined) {
591 int i, h, inc;
592 inc = FONT_MEAN_WIDTH * 2 / 3;
593 CSetColor (color_palette (18));
594 h = (x / inc) & 1;
595 CLine (win, x, y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h, x + min (l, inc - (x % inc) - 1), y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h);
596 h = h ^ 1;
597 for (i = inc - min (l, (x % inc)); i < l; i += inc) {
598 CLine (win, x + i, y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h, x + min (l, i + inc - 1), y + FONT_HEIGHT + FONT_OVERHEAD - 1 - h);
599 h = h ^ 1;
602 #endif
603 /* if we printed a cursor: */
604 #ifdef GTK
605 if (s & (MOD_CURSOR * 256))
606 edit_set_cursor (win, x, y, bg.pixel, fg.pixel, FONT_PER_CHAR[*text], *text);
607 return x + gdk_text_width (GTK_WIDGET (win)->style->font, text, length);
608 #else
609 if (s & (MOD_CURSOR * 256))
610 edit_set_cursor (win, x, y, bg, fg, FONT_PER_CHAR[*text], *text);
611 return x + l;
612 #endif
615 #define STYLE_DIFF (*cache != *line \
616 || ((*cache | *line) & (MOD_CURSOR * 256)) \
617 || !*cache || !*line)
619 int get_ignore_length (cache_type *cache, cache_type *line)
621 int i;
622 for (i = 0; i < CACHE_WIDTH; i++, line++, cache++) {
623 if (STYLE_DIFF)
624 return i;
626 return CACHE_WIDTH;
629 static inline size_t lwstrnlen (const cache_type *s, size_t count)
631 const cache_type *sc;
632 for (sc = s; count-- && *sc != 0; ++sc);
633 return sc - s;
636 static inline size_t lwstrlen (const cache_type *s)
638 const cache_type *sc;
639 for (sc = s; *sc != 0; ++sc);
640 return sc - s;
643 int get_ignore_trailer (cache_type *cache, cache_type *line, int length)
645 int i;
646 int cache_len, line_len;
647 cache_len = lwstrnlen (cache, CACHE_WIDTH);
648 line_len = lwstrlen (line);
650 if (line_len > cache_len)
651 for (i = line_len - 1; i >= cache_len && i >= length; i--)
652 if (line[i] != ' ')
653 return i + 1;
655 for (i = cache_len - 1, line = line + i, cache = cache + i; i > length; i--, line--, cache--)
656 if (STYLE_DIFF)
657 return i + 1;
659 return length + 1;
662 /* erases trailing bit of old line if a new line is printed over a longer old line */
663 static void cover_trail (Window win, int x_start, int x_new, int x_old, int y)
665 if (x_new < EDIT_TEXT_HORIZONTAL_OFFSET)
666 x_new = EDIT_TEXT_HORIZONTAL_OFFSET;
667 if (x_new < x_old) { /* no need to print */
668 #ifdef GTK
669 gdk_gc_set_foreground (win->gc, &win->color[1]);
670 gdk_draw_rectangle (win->text_area, win->gc, 1, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT);
671 #else
672 CSetColor (edit_normal_background_color);
673 CRectangle (win, x_new, y + FONT_OVERHEAD, x_old - x_new, FONT_HEIGHT + (FONT_OVERHEAD != 0 && !FIXED_FONT));
674 #endif
675 } else {
676 #ifdef GTK
677 gdk_gc_set_foreground (win->gc, &win->color[1]);
678 #else
679 CSetColor (edit_normal_background_color);
680 #endif
682 /* true type fonts print stuff out of the bounding box (aaaaaaaaarrrgh!!) */
683 if (!FIXED_FONT)
684 if (FONT_OVERHEAD && x_new > EDIT_TEXT_HORIZONTAL_OFFSET)
685 #ifdef GTK
686 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);
687 #else
688 CLine (win, max (x_start, EDIT_TEXT_HORIZONTAL_OFFSET), y + FONT_HEIGHT + FONT_OVERHEAD, x_new - 1, y + FONT_HEIGHT + FONT_OVERHEAD);
689 #endif
692 cache_type mode_spacing = 0;
694 #define NOT_VALID (-2000000000)
696 void edit_draw_proportional (void *data,
697 void (*converttext) (void *, long, cache_type *, int, int, int),
698 int calctextpos (void *, long, long *, int),
699 int scroll_right,
700 Window win,
701 int x_max,
702 long b,
703 int row,
704 int y,
705 int x_offset,
706 int tabwidth)
708 static struct cache_line lines[CACHE_HEIGHT];
709 static Window last = 0;
710 cache_type style, line[MAX_LINE_LEN], *p;
711 unsigned char text[128];
712 int x0, x, ignore_text = 0, ignore_trailer = 2000000000, j, i;
713 long q;
715 tab_width = tabwidth;
716 if (option_long_whitespace)
717 tab_width = tabwidth *= 2;
719 x_max -= 3;
721 /* if its not the same window, reset the screen rememberer */
722 if (last != win || !win) {
723 last = win;
724 for (i = 0; i < CACHE_HEIGHT; i++) {
725 lines[i].x0 = NOT_VALID;
726 lines[i].x1 = x_max;
728 if (!win)
729 return;
732 /* get point to start drawing */
733 x0 = (*calctextpos) (data, b, &q, -scroll_right + x_offset);
734 /* q contains the offset in the edit buffer */
736 /* translate this line into printable characters with a style (=color) high byte */
737 (*converttext) (data, q, line, x0, x_max - scroll_right - EDIT_TEXT_HORIZONTAL_OFFSET, row);
739 /* adjust for the horizontal scroll and border */
740 x0 += scroll_right + EDIT_TEXT_HORIZONTAL_OFFSET;
741 x = x0;
743 /* is some of the line identical to that already printed so that we can ignore it? */
744 if (!EditExposeRedraw) {
745 if (lines[row].x0 == x0 && row < CACHE_HEIGHT) { /* i.e. also && lines[row].x0 != NOT_VALID */
746 ignore_text = get_ignore_length (lines[row].data, line);
747 if (FIXED_FONT)
748 ignore_trailer = get_ignore_trailer (lines[row].data, line, ignore_text);
751 p = line;
752 j = 0;
753 while (*p) {
754 if (mode_spacing) {
755 if ((*p & 0x80) && (*p & mode_spacing)) {
756 #ifdef STILL_TO_BE_SUPPORTED
757 x += edit_insert_pixmap (win, x, y, *p & 0x7F);
758 /* the pixmap will be clipped, if it's taller than the
759 current font, else centred top to bottom */
760 #endif
761 p++;
762 continue;
764 goto do_text;
766 if ((*p & 0xFF) == '\t') {
767 j++;
768 if (j > ignore_text && j < ignore_trailer + 1)
769 x = draw_tab (win, x, y, *p, scroll_right);
770 else
771 x += next_tab (x, scroll_right);
772 p++;
773 } else {
774 do_text:
775 style = *p & 0xFFFFFF00UL;
776 i = 0;
777 do {
778 text[i++] = (unsigned char) *p++;
779 j++;
780 if (j == ignore_text || j == ignore_trailer)
781 break;
782 } while (i < 128 && *p && style == (*p & 0xFFFFFF00UL) && (*p & 0xFF) != '\t');
784 if (style & mode_spacing) {
785 int k;
786 for (k = 0; k < i; k++) {
787 draw_space (win, x, y, (0xFFFFFF00UL - mode_spacing) & style, text[k]);
788 x += text[k];
790 } else {
791 if (j > ignore_text && j < ignore_trailer + 1)
792 x = draw_string (win, x, y, style, text, i);
793 else
794 #ifdef GTK
795 x += gdk_text_width (GTK_WIDGET(win)->style->font, text, i);
796 #else
797 x += CTextWidth ((char *) text, i);
798 #endif
803 x = min (x, x_max);
804 if (!EditExposeRedraw || EditClear)
805 cover_trail (win, x0, x, lines[row].x1, y);
806 memcpy (&(lines[row].data[ignore_text]),
807 &(line[ignore_text]),
808 (min (j, CACHE_WIDTH) - ignore_text) * sizeof (cache_type));
810 lines[row].data[min (j, CACHE_WIDTH)] = 0;
812 lines[row].x0 = x0;
813 lines[row].x1 = x;
814 if (EditExposeRedraw)
815 last = 0;
816 else
817 last = win;
821 void edit_draw_this_line_proportional (WEdit * edit, long b, int row, int start_column, int end_column)
823 int fg, bg;
824 if (row < 0 || row >= edit->num_widget_lines)
825 return;
827 if (row + edit->start_line > edit->total_lines)
828 b = edit->last_byte + 1; /* force b out of range of the edit buffer for blanks lines */
830 if (end_column > CWidthOf (edit->widget))
831 end_column = CWidthOf (edit->widget);
833 edit_get_syntax_color (edit, b - 1, &fg, &bg);
835 edit_draw_proportional (edit,
836 (void (*) (void *, long, cache_type *, int, int, int)) convert_text,
837 (int (*) (void *, long, long *, int)) calc_text_pos,
838 edit->start_col, CWindowOf (edit->widget),
839 end_column, b, row, row * FONT_PIX_PER_LINE + EDIT_TEXT_VERTICAL_OFFSET,
840 EditExposeRedraw ? start_column : 0, FONT_PER_CHAR[' '] * TAB_SIZE);
844 /*********************************************************************************/
845 /* The remainder is for the text box widget */
846 /*********************************************************************************/
848 static inline int nroff_printable (int c)
850 return isprint (c);
854 static int calc_text_pos_str (unsigned char *text, long b, long *q, int l)
856 int x = 0, c = 0, xn = 0, d;
857 for (;;) {
858 d = c;
859 c = text[b];
860 switch (c) {
861 case '\0':
862 case '\n':
863 *q = b;
864 return x;
865 case '\t':
866 xn = next_tab_pos (x);
867 break;
868 case '\r':
869 break;
870 case '\b':
871 if (d)
872 xn = x - FONT_PER_CHAR[d];
873 break;
874 default:
875 if (!nroff_printable (c))
876 c = ' ';
877 xn = x + FONT_PER_CHAR[c];
878 break;
880 if (xn > l)
881 break;
882 x = xn;
883 b++;
885 *q = b;
886 return x;
889 int prop_font_strcolmove (unsigned char *str, int i, int column)
891 long q;
892 CPushFont ("editor", 0);
893 calc_text_pos_str (str, i, &q, column * FONT_MEAN_WIDTH);
894 CPopFont ();
895 return q;
898 #ifndef GTK
900 /* b is the beginning of the line. l is the length in pixels up to a point
901 on some character which is unknown. The character pos is returned in
902 *q and the characters pixel x pos from b is return'ed. */
903 int calc_text_pos2 (CWidget * w, long b, long *q, int l)
905 int r;
906 CPushFont ("editor", 0);
907 r = calc_text_pos_str ((unsigned char *) w->text, b, q, l);
908 CPopFont ();
909 return r;
912 int highlight_this_line;
914 /* this is for the text widget (i.e. nroff formatting) */
915 void convert_text2 (CWidget * w, long q, cache_type *line, int x, int x_max, int row)
917 int c = 0, d;
918 cache_type s, *p;
919 long m1, m2;
921 m1 = min (w->mark1, w->mark2);
922 m2 = max (w->mark1, w->mark2);
924 p = line;
925 *p = 0;
926 for (;;) {
927 d = c;
928 c = w->text[q];
929 *(p + 1) = 0;
930 *p |= 0xFFFF0000UL; /* default background colors */
931 if (highlight_this_line)
932 *p |= MOD_HIGHLIGHTED * 256;
933 if (q >= m1 && q < m2)
934 *p |= MOD_MARKED * 256;
935 switch (c) {
936 case '\0':
937 case '\n':
938 *p++ |= ' ';
939 if (highlight_this_line) {
940 q--;
941 x += FONT_PER_CHAR[' '];
942 } else
943 return;
944 break;
945 case '\t':
946 if (FIXED_FONT) {
947 int i;
948 i = next_tab_pos (x) - x;
949 x += i;
950 s = *p;
951 while (i > 0) {
952 i -= FONT_PER_CHAR[' '];
953 *p++ = s | ' ';
954 *p = 0;
956 } else {
957 *p++ |= '\t';
958 x = next_tab_pos (x);
960 break;
961 case '\r':
962 break;
963 case '\b':
964 if (d) {
965 --p;
966 x -= FONT_PER_CHAR[d];
967 if (d == '_')
968 *p |= MOD_ITALIC * 256;
969 else
970 *p |= MOD_BOLD * 256;
972 break;
973 default:
974 if (!nroff_printable (c)) {
975 c = ' ';
976 *p |= MOD_ABNORMAL * 256;
978 x += FONT_PER_CHAR[c];
979 *p &= 0xFFFFFF00UL;
980 *p |= c;
981 p++;
982 break;
984 if (x > x_max)
985 break;
986 q++;
988 *p = 0;
992 #endif