update
[midnight-commander.git] / gtkedit / editdraw.c
blobb864e1cf6f5454132bc1b3f936c8d24ee87035b6
1 /* editor text drawing.
3 Copyright (C) 1996, 1997 the Free Software Foundation
5 Authors: 1996, 1997 Paul Sheer
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include <config.h>
22 #include "edit.h"
24 #define MAX_LINE_LEN 1024
26 #ifndef MIDNIGHT
27 #ifndef GTK
28 #include "app_glob.c"
29 #include "coollocal.h"
30 #endif
31 #else
32 #include "../src/mad.h"
33 #endif
35 extern int column_highlighting;
37 void status_string (WEdit * edit, char *s, int w, int fill, int font_width)
39 int i;
40 char t[160]; /* 160 just to be sure */
41 /* The field lengths just prevents the status line from shortening to much */
42 sprintf (t, "[%c%c%c%c] %2ld:%3ld+%2ld=%3ld/%3ld - *%-4ld/%4ldb=%3d",
43 edit->mark1 != edit->mark2 ? ( column_highlighting ? 'C' : 'B') : '-',
44 edit->modified ? 'M' : '-', edit->macro_i < 0 ? '-' : 'R',
45 edit->overwrite == 0 ? '-' : 'O',
46 edit->curs_col / font_width, edit->start_line + 1, edit->curs_row,
47 edit->curs_line + 1, edit->total_lines + 1, edit->curs1,
48 edit->last_byte, edit->curs1 < edit->last_byte
49 ? edit_get_byte (edit, edit->curs1) : -1);
50 sprintf (s, "%.*s", w + 1, t);
51 i = strlen (s);
52 s[i] = ' ';
53 i = w;
54 do {
55 if (strchr (" +-*=/:b", s[i])) /* chop off the last word/number */
56 break;
57 s[i] = fill;
58 } while (i--);
59 s[i] = fill;
60 s[w] = 0;
64 #ifdef MIDNIGHT
66 /* how to get as much onto the status line as is numerically possible :) */
67 void edit_status (WEdit * edit)
69 int w, i, t;
70 char *s;
71 w = edit->widget.cols - (edit->have_frame * 2);
72 s = malloc (w + 15);
73 if (w < 4)
74 w = 4;
75 memset (s, ' ', w);
76 attrset (SELECTED_COLOR);
77 if (w > 4) {
78 widget_move (edit, edit->have_frame, edit->have_frame);
79 i = w > 24 ? 18 : w - 6;
80 i = i < 13 ? 13 : i;
81 sprintf (s, "%s", (char *) name_trunc (edit->filename ? edit->filename : "", i));
82 i += strlen (s);
83 s[strlen (s)] = ' ';
84 t = w - 20;
85 if (t < 0)
86 t = 0;
87 status_string (edit, s + 20, t, ' ', 1);
88 } else {
89 s[w] = 0;
91 printw ("%.*s", w, s);
92 attrset (NORMAL_COLOR);
93 free (s);
96 #else
98 #ifndef GTK
99 extern int fixed_font;
100 #endif
102 void rerender_text (CWidget * wdt);
104 #ifdef GTK
106 void edit_status (WEdit * edit)
108 GtkEntry *entry;
109 GtkWidget *widget;
110 int w, i, t;
111 char id[33];
112 char s[160];
113 w = edit->num_widget_columns - 1;
114 if (w > 150)
115 w = 150;
116 if (w < 0)
117 w = 0;
118 memset (s, 0, w);
119 if (w > 1) {
120 i = w > 24 ? 18 : w - 6;
121 i = i < 13 ? 13 : i;
122 sprintf (s, "%s", name_trunc (edit->filename ? edit->filename : "", i));
123 i = strlen (s);
124 s[i] = ' ';
125 s[i + 1] = ' ';
126 t = w - i - 2;
127 if (t < 0)
128 t = 0;
129 status_string (edit, s + i + 2, t, 0, FONT_MEAN_WIDTH);
131 s[w] = 0;
132 entry = GTK_ENTRY (edit->widget->status);
133 if (strcmp (s, gtk_entry_get_text (entry)))
134 gtk_entry_set_text (entry, s);
137 #else
139 void edit_status (WEdit * edit)
141 if ((COptionsOf (edit->widget) & EDITOR_NO_TEXT)) {
142 return;
143 } else {
144 int w, i, t;
145 CWidget *wdt;
146 char id[33];
147 char s[160];
148 w = edit->num_widget_columns - 1;
149 if (w > 150)
150 w = 150;
151 if (w < 0)
152 w = 0;
153 memset (s, 0, w);
154 if (w > 1) {
155 i = w > 24 ? 18 : w - 6;
156 i = i < 13 ? 13 : i;
157 sprintf (s, "%s", name_trunc (edit->filename ? edit->filename : "", i));
158 i = strlen (s);
159 s[i] = ' ';
160 s[i+1] = ' ';
161 t = w - i - 2;
162 if (t < 0)
163 t = 0;
164 status_string (edit, s + i + 2, t, 0, FONT_MEAN_WIDTH);
166 s[w] = 0;
167 strcpy (id, CIdentOf (edit->widget));
168 strcat (id, ".text");
169 wdt = CIdent (id);
170 free (wdt->text);
171 wdt->text = strdup (s);
172 CSetWidgetSize (id, CWidthOf (edit->widget), CHeightOf (wdt));
173 rerender_text (wdt);
177 #endif
179 #endif
182 /* boolean */
183 int cursor_in_screen (WEdit * edit, long row)
185 if (row < 0 || row >= edit->num_widget_lines)
186 return 0;
187 else
188 return 1;
191 /* returns rows from the first displayed line to the cursor */
192 int cursor_from_display_top (WEdit * edit)
194 if (edit->curs1 < edit->start_display)
195 return -edit_move_forward (edit, edit->curs1, 0, edit->start_display);
196 else
197 return edit_move_forward (edit, edit->start_display, 0, edit->curs1);
200 /* returns how far the cursor is out of the screen */
201 int cursor_out_of_screen (WEdit * edit)
203 int row = cursor_from_display_top (edit);
204 if (row >= edit->num_widget_lines)
205 return row - edit->num_widget_lines + 1;
206 if (row < 0)
207 return row;
208 return 0;
211 #ifndef MIDNIGHT
212 extern unsigned char per_char[256];
213 int edit_width_of_long_printable (int c);
214 #endif
216 /* this scrolls the text so that cursor is on the screen */
217 void edit_scroll_screen_over_cursor (WEdit * edit)
219 int p, l;
220 int outby;
221 p = edit_get_col (edit);
222 edit_update_curs_row (edit);
223 #ifdef MIDNIGHT
224 outby = p + edit->start_col - edit->num_widget_columns + 1 + (EDIT_RIGHT_EXTREME + edit->found_len);
225 #else
226 outby = p + edit->start_col - CWidthOf (edit->widget) + 7 + (EDIT_RIGHT_EXTREME + edit->found_len) * FONT_MEAN_WIDTH + edit_width_of_long_printable (edit_get_byte (edit, edit->curs1));
227 #endif
228 if (outby > 0)
229 edit_scroll_right (edit, outby);
230 #ifdef MIDNIGHT
231 outby = EDIT_LEFT_EXTREME - p - edit->start_col;
232 #else
233 outby = EDIT_LEFT_EXTREME * FONT_MEAN_WIDTH - p - edit->start_col;
234 #endif
235 if (outby > 0)
236 edit_scroll_left (edit, outby);
237 p = edit->curs_row;
238 l = 0;
239 if (edit->found_len != 0)
240 l = edit->num_widget_lines / 5;
241 outby = p - edit->num_widget_lines + 1 + EDIT_BOTTOM_EXTREME + l;
242 if (outby > 0)
243 edit_scroll_downward (edit, outby);
244 outby = EDIT_TOP_EXTREME - p + l;
245 if (outby > 0)
246 edit_scroll_upward (edit, outby);
247 edit_update_curs_row (edit);
251 #ifndef MIDNIGHT
253 #define CACHE_WIDTH 256
254 #define CACHE_HEIGHT 128
256 int EditExposeRedraw = 0;
257 int EditClear = 0;
259 /* background colors: marked is refers to mouse highlighting, highlighted refers to a found string. */
260 unsigned long edit_abnormal_color, edit_marked_abnormal_color;
261 unsigned long edit_highlighted_color, edit_marked_color;
262 unsigned long edit_normal_background_color;
264 /* foreground colors */
265 unsigned long edit_normal_foreground_color, edit_bold_color;
266 unsigned long edit_italic_color;
268 /* cursor color */
269 unsigned long edit_cursor_color;
271 void edit_set_foreground_colors (unsigned long normal, unsigned long bold, unsigned long italic)
273 edit_normal_foreground_color = normal;
274 edit_bold_color = bold;
275 edit_italic_color = italic;
278 void edit_set_background_colors (unsigned long normal, unsigned long abnormal, unsigned long marked, unsigned long marked_abnormal, unsigned long highlighted)
280 edit_abnormal_color = abnormal;
281 edit_marked_abnormal_color = marked_abnormal;
282 edit_marked_color = marked;
283 edit_highlighted_color = highlighted;
284 edit_normal_background_color = normal;
287 void edit_set_cursor_color (unsigned long c)
289 edit_cursor_color = c;
292 #else
294 #define BOLD_COLOR MARKED_COLOR
295 #define UNDERLINE_COLOR VIEW_UNDERLINED_COLOR
296 #define MARK_COLOR SELECTED_COLOR
297 #define DEF_COLOR NORMAL_COLOR
299 static void set_color (int font)
301 attrset (font);
304 #define edit_move(x,y) widget_move(edit, y, x);
306 static void print_to_widget (WEdit * edit, long row, int start_col, float start_col_real, long end_col, unsigned int line[])
308 int x = (float) start_col_real + EDIT_TEXT_HORIZONTAL_OFFSET;
309 int x1 = start_col + EDIT_TEXT_HORIZONTAL_OFFSET;
310 int y = row + EDIT_TEXT_VERTICAL_OFFSET;
312 set_color (DEF_COLOR);
313 edit_move (x1, y);
314 hline (' ', end_col + 1 - EDIT_TEXT_HORIZONTAL_OFFSET - x1);
316 edit_move (x + FONT_OFFSET_X, y + FONT_OFFSET_Y);
318 unsigned int *p = line;
319 int textchar = ' ';
320 long style;
322 while (*p) {
323 style = *p >> 8;
324 textchar = *p & 0xFF;
325 #ifdef HAVE_SYNTAXH
326 if (!(style & (0xFF - MOD_ABNORMAL - MOD_CURSOR)))
327 SLsmg_set_color ((*p & 0x007F0000) >> 16);
328 #endif
329 if (style & MOD_ABNORMAL)
330 textchar = '.';
331 if (style & MOD_HIGHLIGHTED) {
332 set_color (BOLD_COLOR);
333 } else if (style & MOD_MARKED) {
334 set_color (MARK_COLOR);
336 if (style & MOD_UNDERLINED) {
337 set_color (UNDERLINE_COLOR);
339 if (style & MOD_BOLD) {
340 set_color (BOLD_COLOR);
342 addch (textchar);
343 p++;
348 /* b pointer to begining of line */
349 static void edit_draw_this_line (WEdit * edit, long b, long row, long start_col, long end_col)
351 static unsigned int line[MAX_LINE_LEN];
352 unsigned int *p = line;
353 long m1 = 0, m2 = 0, q, c1, c2;
354 int col, start_col_real;
355 unsigned int c;
356 int fg, bg;
357 int i;
359 edit_get_syntax_color (edit, b - 1, &fg, &bg);
360 q = edit_move_forward3 (edit, b, start_col - edit->start_col, 0);
361 start_col_real = (col = (int) edit_move_forward3 (edit, b, 0, q)) + edit->start_col;
362 c1 = min (edit->column1, edit->column2);
363 c2 = max (edit->column1, edit->column2);
365 if (col + 16 > -edit->start_col) {
366 eval_marks (edit, &m1, &m2);
368 if (row <= edit->total_lines - edit->start_line) {
369 while (col <= end_col - edit->start_col) {
370 *p = 0;
371 if (q == edit->curs1)
372 *p |= MOD_CURSOR * 256;
373 if (q >= m1 && q < m2) {
374 if (column_highlighting) {
375 int x;
376 x = edit_move_forward3 (edit, b, 0, q);
377 if (x >= c1 && x < c2)
378 *p |= MOD_MARKED * 256;
379 } else
380 *p |= MOD_MARKED * 256;
382 if (q == edit->bracket)
383 *p |= MOD_BOLD * 256;
384 if (q >= edit->found_start && q < edit->found_start + edit->found_len)
385 *p |= MOD_HIGHLIGHTED * 256;
386 c = edit_get_byte (edit, q);
387 edit_get_syntax_color (edit, q, &fg, &bg);
388 /* we don't use bg for mc - fg contains both */
389 *p |= fg << 16;
390 q++;
391 switch (c) {
392 case '\n':
393 col = end_col - edit->start_col + 1; /* quit */
394 *(p++) |= ' ';
395 break;
396 case '\t':
397 i = TAB_SIZE - ((int) col % TAB_SIZE);
398 *p |= ' ';
399 c = *(p++) & (0xFFFFFFFF - MOD_CURSOR * 256);
400 col += i;
401 while (--i)
402 *(p++) = c;
403 break;
404 case '\r':
405 break;
406 default:
407 if (is_printable (c)) {
408 *(p++) |= c;
409 } else {
410 *(p++) = '.';
411 *p |= (256 * MOD_ABNORMAL);
413 col++;
414 break;
418 } else {
419 start_col_real = start_col = 0;
421 *p = 0;
423 print_to_widget (edit, row, start_col, start_col_real, end_col, line);
426 #endif
428 #ifdef MIDNIGHT
430 #define key_pending(x) (!is_idle())
432 #else
434 int edit_mouse_pending (Window win);
435 #define edit_draw_this_line edit_draw_this_line_proportional
437 static int key_pending (WEdit * edit)
439 #ifdef GTK
440 /* ******* */
441 #else
442 if (!(edit->force & REDRAW_COMPLETELY) && !EditExposeRedraw)
443 return CKeyPending ();
444 #endif
445 return 0;
448 #endif
451 /* b for pointer to begining of line */
452 static void edit_draw_this_char (WEdit * edit, long curs, long row)
454 int b = edit_bol (edit, curs);
455 #ifdef MIDNIGHT
456 edit_draw_this_line (edit, b, row, 0, edit->num_widget_columns - 1);
457 #else
458 edit_draw_this_line (edit, b, row, 0, CWidthOf (edit->widget));
459 #endif
462 /* cursor must be in screen for other than REDRAW_PAGE passed in force */
463 void render_edit_text (WEdit * edit, long start_row, long start_column, long end_row, long end_column)
465 long row = 0, curs_row;
466 static int prev_curs_row = 0;
467 static int prev_start_col = 0;
468 static long prev_curs = 0;
470 #ifndef MIDNIGHT
471 static unsigned long prev_win = 0;
472 #endif
473 int force = edit->force;
474 long b;
477 if the position of the page has not moved then we can draw the cursor character only.
478 This will prevent line flicker when using arrow keys.
480 if ((!(force & REDRAW_CHAR_ONLY)) || (force & REDRAW_PAGE)
481 #ifndef MIDNIGHT
482 #ifdef GTK
483 || prev_win != ((GdkWindowPrivate *) CWindowOf (edit->widget)->text_area)->xwindow
484 #else
485 || prev_win != CWindowOf (edit->widget)
486 #endif
487 #endif
489 if (!(force & REDRAW_IN_BOUNDS)) { /* !REDRAW_IN_BOUNDS means to ignore bounds and redraw whole rows */
490 start_row = 0;
491 end_row = edit->num_widget_lines - 1;
492 start_column = 0;
493 #ifdef MIDNIGHT
494 end_column = edit->num_widget_columns - 1;
495 #else
496 end_column = CWidthOf (edit->widget);
497 #endif
499 if (force & REDRAW_PAGE) {
500 row = start_row;
501 b = edit_move_forward (edit, edit->start_display, start_row, 0);
502 while (row <= end_row) {
503 if (key_pending (edit))
504 goto exit_render;
505 edit_draw_this_line (edit, b, row, start_column, end_column);
506 b = edit_move_forward (edit, b, 1, 0);
507 row++;
509 } else {
510 curs_row = edit->curs_row;
512 if (force & REDRAW_BEFORE_CURSOR) {
513 if (start_row < curs_row) {
514 long upto = curs_row - 1 <= end_row ? curs_row - 1 : end_row;
515 row = start_row;
516 b = edit->start_display;
517 while (row <= upto) {
518 if (key_pending (edit))
519 goto exit_render;
520 edit_draw_this_line (edit, b, row, start_column, end_column);
521 b = edit_move_forward (edit, b, 1, 0);
525 /* if (force & REDRAW_LINE) { ---> default */
526 b = edit_bol (edit, edit->curs1);
527 if (curs_row >= start_row && curs_row <= end_row) {
528 if (key_pending (edit))
529 goto exit_render;
530 edit_draw_this_line (edit, b, curs_row, start_column, end_column);
532 if (force & REDRAW_AFTER_CURSOR) {
533 if (end_row > curs_row) {
534 row = curs_row + 1 < start_row ? start_row : curs_row + 1;
535 b = edit_move_forward (edit, b, 1, 0);
536 while (row <= end_row) {
537 if (key_pending (edit))
538 goto exit_render;
539 edit_draw_this_line (edit, b, row, start_column, end_column);
540 b = edit_move_forward (edit, b, 1, 0);
541 row++;
545 if (force & REDRAW_LINE_ABOVE && curs_row >= 1) {
546 row = curs_row - 1;
547 b = edit_move_backward (edit, edit_bol (edit, edit->curs1), 1);
548 if (row >= start_row && row <= end_row) {
549 if (key_pending (edit))
550 goto exit_render;
551 edit_draw_this_line (edit, b, row, start_column, end_column);
554 if (force & REDRAW_LINE_BELOW && row < edit->num_widget_lines - 1) {
555 row = curs_row + 1;
556 b = edit_bol (edit, edit->curs1);
557 b = edit_move_forward (edit, b, 1, 0);
558 if (row >= start_row && row <= end_row) {
559 if (key_pending (edit))
560 goto exit_render;
561 edit_draw_this_line (edit, b, row, start_column, end_column);
565 } else {
566 if (prev_curs_row < edit->curs_row) { /* with the new text highlighting, we must draw from the top down */
567 edit_draw_this_char (edit, prev_curs, prev_curs_row);
568 edit_draw_this_char (edit, edit->curs1, edit->curs_row);
569 } else {
570 edit_draw_this_char (edit, edit->curs1, edit->curs_row);
571 edit_draw_this_char (edit, prev_curs, prev_curs_row);
575 edit->force = 0;
577 prev_curs_row = edit->curs_row;
578 prev_curs = edit->curs1;
579 prev_start_col = edit->start_col;
580 #ifndef MIDNIGHT
581 #ifdef GTK
582 prev_win = ((GdkWindowPrivate *) CWindowOf (edit->widget)->text_area)->xwindow;
583 #else
584 prev_win = CWindowOf (edit->widget);
585 #endif
586 #endif
587 exit_render:
592 #ifndef MIDNIGHT
594 void edit_convert_expose_to_area (XExposeEvent * xexpose, int *row1, int *col1, int *row2, int *col2)
596 *col1 = xexpose->x - EDIT_TEXT_HORIZONTAL_OFFSET;
597 *row1 = (xexpose->y - EDIT_TEXT_VERTICAL_OFFSET) / FONT_PIX_PER_LINE;
598 *col2 = xexpose->x + xexpose->width + EDIT_TEXT_HORIZONTAL_OFFSET + 3;
599 *row2 = (xexpose->y + xexpose->height - EDIT_TEXT_VERTICAL_OFFSET) / FONT_PIX_PER_LINE;
602 #ifdef GTK
604 void edit_render_tidbits (GtkEdit * edit)
606 gtk_widget_draw_focus (GTK_WIDGET (edit));
609 #else
611 void edit_render_tidbits (CWidget * wdt)
613 int isfocussed;
614 int w = wdt->width, h = wdt->height;
615 Window win;
617 win = wdt->winid;
618 isfocussed = (win == CGetFocus ());
620 CSetColor (COLOR_FLAT);
622 if (isfocussed) {
623 render_bevel (win, 0, 0, w - 1, h - 1, 3, 1); /*most outer border bevel */
624 } else {
625 render_bevel (win, 2, 2, w - 3, h - 3, 1, 1); /*border bevel */
626 render_bevel (win, 0, 0, w - 1, h - 1, 2, 0); /*most outer border bevel */
630 #endif
632 void edit_set_space_width (int s);
633 extern int option_long_whitespace;
635 #endif
637 void edit_render (WEdit * edit, int page, int row_start, int col_start, int row_end, int col_end)
639 int f = 0;
640 #ifdef GTK
641 GtkEdit *win;
642 #endif
643 if (page) /* if it was an expose event, 'page' would be set */
644 edit->force |= REDRAW_PAGE | REDRAW_IN_BOUNDS;
645 f = edit->force & (REDRAW_PAGE | REDRAW_COMPLETELY);
647 #ifdef MIDNIGHT
648 if (edit->force & REDRAW_COMPLETELY)
649 redraw_labels (edit->widget.parent, (Widget *) edit);
650 #else
651 if (option_long_whitespace)
652 edit_set_space_width (per_char[' '] * 2);
653 else
654 edit_set_space_width (per_char[' ']);
655 #ifdef GTK
656 win = (GtkEdit *) edit->widget;
657 #endif
658 edit_set_foreground_colors (
659 color_palette (option_editor_fg_normal),
660 color_palette (option_editor_fg_bold),
661 color_palette (option_editor_fg_italic)
663 edit_set_background_colors (
664 color_palette (option_editor_bg_normal),
665 color_palette (option_editor_bg_abnormal),
666 color_palette (option_editor_bg_marked),
667 color_palette (option_editor_bg_marked_abnormal),
668 color_palette (option_editor_bg_highlighted)
670 edit_set_cursor_color (
671 color_palette (option_editor_fg_cursor)
674 #ifdef GTK
675 /* *********** */
676 #else
677 if (!EditExposeRedraw)
678 set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
679 #endif
680 #endif
682 render_edit_text (edit, row_start, col_start, row_end, col_end);
683 if (edit->force) /* edit->force != 0 means a key was pending and the redraw
684 was halted, so next time we must redraw everything in case stuff
685 was left undrawn from a previous key press */
686 edit->force |= REDRAW_PAGE;
687 #ifndef MIDNIGHT
688 if (f) {
689 edit_render_tidbits (edit->widget);
690 #ifdef GTK
691 /* ***************** */
692 #else
693 CSetColor (edit_normal_background_color);
694 CLine (CWindowOf (edit->widget), 3, 3, 3, CHeightOf (edit->widget) - 4);
695 #endif
697 #endif
700 #ifndef MIDNIGHT
701 void edit_render_expose (WEdit * edit, XExposeEvent * xexpose)
703 int row_start, col_start, row_end, col_end;
704 EditExposeRedraw = 1;
705 edit->num_widget_lines = (CHeightOf (edit->widget) - 6) / FONT_PIX_PER_LINE;
706 edit->num_widget_columns = (CWidthOf (edit->widget) - 7) / FONT_MEAN_WIDTH;
707 if (edit->force & (REDRAW_PAGE | REDRAW_COMPLETELY)) {
708 edit->force |= REDRAW_PAGE | REDRAW_COMPLETELY;
709 edit_render_keypress (edit);
710 } else {
711 edit_convert_expose_to_area (xexpose, &row_start, &col_start, &row_end, &col_end);
712 edit_render (edit, 1, row_start, col_start, row_end, col_end);
714 EditExposeRedraw = 0;
717 void edit_render_keypress (WEdit * edit)
719 edit_render (edit, 0, 0, 0, 0, 0);
722 #else
724 void edit_render_keypress (WEdit * edit)
726 edit_render (edit, 0, 0, 0, 0, 0);
729 #endif