root/src/editor/editdraw.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. printwstr
  2. status_string
  3. edit_status_fullscreen
  4. edit_status_window
  5. edit_draw_frame
  6. edit_draw_window_icons
  7. print_to_widget
  8. edit_draw_this_line
  9. edit_draw_this_char
  10. render_edit_text
  11. edit_render
  12. edit_status
  13. edit_scroll_screen_over_cursor
  14. edit_render_keypress

   1 /*
   2    Editor text drawing.
   3 
   4    Copyright (C) 1996-2024
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Paul Sheer, 1996, 1997
   9    Andrew Borodin <aborodin@vmail.ru> 2012-2022
  10    Slava Zanko <slavazanko@gmail.com>, 2013
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file
  29  *  \brief Source: editor text drawing
  30  *  \author Paul Sheer
  31  *  \date 1996, 1997
  32  */
  33 
  34 #include <config.h>
  35 #include <stdlib.h>
  36 #include <stdio.h>
  37 #include <stdarg.h>
  38 #include <sys/types.h>
  39 #include <unistd.h>
  40 #include <string.h>
  41 #include <ctype.h>
  42 #include <sys/stat.h>
  43 
  44 #include "lib/global.h"
  45 #include "lib/tty/tty.h"        /* tty_printf() */
  46 #include "lib/tty/key.h"        /* is_idle() */
  47 #include "lib/skin.h"
  48 #include "lib/strutil.h"        /* utf string functions */
  49 #include "lib/util.h"           /* is_printable() */
  50 #include "lib/widget.h"
  51 #ifdef HAVE_CHARSET
  52 #include "lib/charsets.h"
  53 #endif
  54 
  55 #include "edit-impl.h"
  56 #include "editwidget.h"
  57 
  58 /*** global variables ****************************************************************************/
  59 
  60 /*** file scope macro definitions ****************************************************************/
  61 
  62 #define MAX_LINE_LEN 1024
  63 
  64 /* Text styles */
  65 #define MOD_ABNORMAL            (1 << 8)
  66 #define MOD_BOLD                (1 << 9)
  67 #define MOD_MARKED              (1 << 10)
  68 #define MOD_CURSOR              (1 << 11)
  69 #define MOD_WHITESPACE          (1 << 12)
  70 
  71 #define edit_move(x,y) widget_gotoyx(edit, y, x);
  72 
  73 #define key_pending(x) (!is_idle())
  74 
  75 #define EDITOR_MINIMUM_TERMINAL_WIDTH 30
  76 
  77 /*** file scope type declarations ****************************************************************/
  78 
  79 typedef struct
  80 {
  81     unsigned int ch;
  82     unsigned int style;
  83 } line_s;
  84 
  85 /*** forward declarations (file scope functions) *************************************************/
  86 
  87 /*** file scope variables ************************************************************************/
  88 
  89 /*** file scope functions ************************************************************************/
  90 
  91 static inline void
  92 printwstr (const char *s, int len)
     /* [previous][next][first][last][top][bottom][index][help]  */
  93 {
  94     if (len > 0)
  95         tty_printf ("%-*.*s", len, len, s);
  96 }
  97 
  98 /* --------------------------------------------------------------------------------------------- */
  99 
 100 static inline void
 101 status_string (WEdit *edit, char *s, int w)
     /* [previous][next][first][last][top][bottom][index][help]  */
 102 {
 103     char byte_str[16];
 104 
 105     /*
 106      * If we are at the end of file, print <EOF>,
 107      * otherwise print the current character as is (if printable),
 108      * as decimal and as hex.
 109      */
 110     if (edit->buffer.curs1 >= edit->buffer.size)
 111         strcpy (byte_str, "<EOF>     ");
 112 #ifdef HAVE_CHARSET
 113     else if (edit->utf8)
 114     {
 115         unsigned int cur_utf;
 116         int char_length = 1;
 117 
 118         cur_utf = edit_buffer_get_utf (&edit->buffer, edit->buffer.curs1, &char_length);
 119         if (char_length > 0)
 120             g_snprintf (byte_str, sizeof (byte_str), "%04u 0x%03X",
 121                         (unsigned) cur_utf, (unsigned) cur_utf);
 122         else
 123         {
 124             cur_utf = edit_buffer_get_current_byte (&edit->buffer);
 125             g_snprintf (byte_str, sizeof (byte_str), "%04d 0x%03X",
 126                         (int) cur_utf, (unsigned) cur_utf);
 127         }
 128     }
 129 #endif
 130     else
 131     {
 132         unsigned char cur_byte;
 133 
 134         cur_byte = edit_buffer_get_current_byte (&edit->buffer);
 135         g_snprintf (byte_str, sizeof (byte_str), "%4d 0x%03X", (int) cur_byte, (unsigned) cur_byte);
 136     }
 137 
 138     /* The field lengths just prevent the status line from shortening too much */
 139     if (edit_options.simple_statusbar)
 140         g_snprintf (s, w,
 141                     "%c%c%c%c %3ld %5ld/%ld %6ld/%ld %s %s",
 142                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',
 143                     edit->modified ? 'M' : '-',
 144                     macro_index < 0 ? '-' : 'R',
 145                     edit->overwrite == 0 ? '-' : 'O',
 146                     edit->curs_col + edit->over_col,
 147                     edit->buffer.curs_line + 1,
 148                     edit->buffer.lines + 1, (long) edit->buffer.curs1, (long) edit->buffer.size,
 149                     byte_str,
 150 #ifdef HAVE_CHARSET
 151                     mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage) :
 152 #endif
 153                     "");
 154     else
 155         g_snprintf (s, w,
 156                     "[%c%c%c%c] %2ld L:[%3ld+%2ld %3ld/%3ld] *(%-4ld/%4ldb) %s  %s",
 157                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',
 158                     edit->modified ? 'M' : '-',
 159                     macro_index < 0 ? '-' : 'R',
 160                     edit->overwrite == 0 ? '-' : 'O',
 161                     edit->curs_col + edit->over_col,
 162                     edit->start_line + 1,
 163                     edit->curs_row,
 164                     edit->buffer.curs_line + 1,
 165                     edit->buffer.lines + 1, (long) edit->buffer.curs1, (long) edit->buffer.size,
 166                     byte_str,
 167 #ifdef HAVE_CHARSET
 168                     mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage) :
 169 #endif
 170                     "");
 171 }
 172 
 173 /* --------------------------------------------------------------------------------------------- */
 174 /**
 175  * Draw the status line at the top of the screen for fullscreen editor window.
 176  *
 177  * @param edit  editor object
 178  * @param color color pair
 179  */
 180 
 181 static inline void
 182 edit_status_fullscreen (WEdit *edit, int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 183 {
 184     Widget *h = WIDGET (WIDGET (edit)->owner);
 185     const int w = h->rect.cols;
 186     const int gap = 3;          /* between the filename and the status */
 187     const int right_gap = 5;    /* at the right end of the screen */
 188     const int preferred_fname_len = 16;
 189     char *status;
 190     size_t status_size;
 191     int status_len;
 192     const char *fname = "";
 193     int fname_len;
 194 
 195     status_size = w + 1;
 196     status = g_malloc (status_size);
 197     status_string (edit, status, status_size);
 198     status_len = (int) str_term_width1 (status);
 199 
 200     if (edit->filename_vpath != NULL)
 201     {
 202         fname = vfs_path_get_last_path_str (edit->filename_vpath);
 203 
 204         if (!edit_options.state_full_filename)
 205             fname = x_basename (fname);
 206     }
 207 
 208     fname_len = str_term_width1 (fname);
 209     if (fname_len < preferred_fname_len)
 210         fname_len = preferred_fname_len;
 211 
 212     if (fname_len + gap + status_len + right_gap >= w)
 213     {
 214         if (preferred_fname_len + gap + status_len + right_gap >= w)
 215             fname_len = preferred_fname_len;
 216         else
 217             fname_len = w - (gap + status_len + right_gap);
 218         fname = str_trunc (fname, fname_len);
 219     }
 220 
 221     widget_gotoyx (h, 0, 0);
 222     tty_setcolor (color);
 223     printwstr (fname, fname_len + gap);
 224     printwstr (status, w - (fname_len + gap));
 225 
 226     if (edit_options.simple_statusbar && w > EDITOR_MINIMUM_TERMINAL_WIDTH)
 227     {
 228         int percent;
 229 
 230         percent = edit_buffer_calc_percent (&edit->buffer, edit->buffer.curs1);
 231         widget_gotoyx (h, 0, w - 6 - 6);
 232         tty_printf (" %3d%%", percent);
 233     }
 234 
 235     g_free (status);
 236 }
 237 
 238 /* --------------------------------------------------------------------------------------------- */
 239 /**
 240  * Draw status line for editor window if window is not in fullscreen mode.
 241  *
 242  * @param edit editor object
 243  */
 244 
 245 static inline void
 246 edit_status_window (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 247 {
 248     Widget *w = WIDGET (edit);
 249     int y, x;
 250     int cols = w->rect.cols;
 251 
 252     tty_setcolor (STATUSBAR_COLOR);
 253 
 254     if (cols > 5)
 255     {
 256         const char *fname = N_("NoName");
 257 
 258         if (edit->filename_vpath != NULL)
 259         {
 260             fname = vfs_path_get_last_path_str (edit->filename_vpath);
 261 
 262             if (!edit_options.state_full_filename)
 263                 fname = x_basename (fname);
 264         }
 265 #ifdef ENABLE_NLS
 266         else
 267             fname = _(fname);
 268 #endif
 269 
 270         edit_move (2, 0);
 271         tty_printf ("[%s]", str_term_trim (fname, w->rect.cols - 8 - 6));
 272     }
 273 
 274     tty_getyx (&y, &x);
 275     x -= w->rect.x;
 276     x += 4;
 277     if (x + 6 <= cols - 2 - 6)
 278     {
 279         edit_move (x, 0);
 280         tty_printf ("[%c%c%c%c]",
 281                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',
 282                     edit->modified ? 'M' : '-',
 283                     macro_index < 0 ? '-' : 'R', edit->overwrite == 0 ? '-' : 'O');
 284     }
 285 
 286     if (cols > 30)
 287     {
 288         edit_move (2, w->rect.lines - 1);
 289         tty_printf ("%3ld %5ld/%ld %6ld/%ld",
 290                     edit->curs_col + edit->over_col,
 291                     edit->buffer.curs_line + 1, edit->buffer.lines + 1, (long) edit->buffer.curs1,
 292                     (long) edit->buffer.size);
 293     }
 294 
 295     /*
 296      * If we are at the end of file, print <EOF>,
 297      * otherwise print the current character as is (if printable),
 298      * as decimal and as hex.
 299      */
 300     if (cols > 46)
 301     {
 302         edit_move (32, w->rect.lines - 1);
 303         if (edit->buffer.curs1 >= edit->buffer.size)
 304             tty_print_string ("[<EOF>       ]");
 305 #ifdef HAVE_CHARSET
 306         else if (edit->utf8)
 307         {
 308             unsigned int cur_utf;
 309             int char_length = 1;
 310 
 311             cur_utf = edit_buffer_get_utf (&edit->buffer, edit->buffer.curs1, &char_length);
 312             if (char_length <= 0)
 313                 cur_utf = edit_buffer_get_current_byte (&edit->buffer);
 314             tty_printf ("[%05u 0x%04X]", cur_utf, cur_utf);
 315         }
 316 #endif
 317         else
 318         {
 319             unsigned char cur_byte;
 320 
 321             cur_byte = edit_buffer_get_current_byte (&edit->buffer);
 322             tty_printf ("[%05u 0x%04X]", (unsigned int) cur_byte, (unsigned int) cur_byte);
 323         }
 324     }
 325 }
 326 
 327 /* --------------------------------------------------------------------------------------------- */
 328 /**
 329  * Draw a frame around edit area.
 330  *
 331  * @param edit   editor object
 332  * @param color  color pair
 333  * @param active TRUE if editor object is focused
 334  */
 335 
 336 static inline void
 337 edit_draw_frame (const WEdit *edit, int color, gboolean active)
     /* [previous][next][first][last][top][bottom][index][help]  */
 338 {
 339     const Widget *w = CONST_WIDGET (edit);
 340 
 341     /* draw a frame around edit area */
 342     tty_setcolor (color);
 343     /* draw double frame for active window if skin supports that */
 344     tty_draw_box (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, !active);
 345     /* draw a drag marker */
 346     if (edit->drag_state == MCEDIT_DRAG_NONE)
 347     {
 348         tty_setcolor (EDITOR_FRAME_DRAG);
 349         widget_gotoyx (w, w->rect.lines - 1, w->rect.cols - 1);
 350         tty_print_alt_char (ACS_LRCORNER, TRUE);
 351     }
 352 }
 353 
 354 /* --------------------------------------------------------------------------------------------- */
 355 /**
 356  * Draw a window control buttons.
 357  *
 358  * @param edit  editor object
 359  * @param color color pair
 360  */
 361 
 362 static inline void
 363 edit_draw_window_icons (const WEdit *edit, int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 364 {
 365     const Widget *w = CONST_WIDGET (edit);
 366     char tmp[17];
 367 
 368     tty_setcolor (color);
 369     if (edit->fullscreen)
 370         widget_gotoyx (w->owner, 0, WIDGET (w->owner)->rect.cols - 6);
 371     else
 372         widget_gotoyx (w, 0, w->rect.cols - 8);
 373     g_snprintf (tmp, sizeof (tmp), "[%s][%s]", edit_window_state_char, edit_window_close_char);
 374     tty_print_string (tmp);
 375 }
 376 
 377 /* --------------------------------------------------------------------------------------------- */
 378 
 379 static inline void
 380 print_to_widget (WEdit *edit, long row, int start_col, int start_col_real,
     /* [previous][next][first][last][top][bottom][index][help]  */
 381                  long end_col, line_s line[], char *status, int bookmarked)
 382 {
 383     Widget *w = WIDGET (edit);
 384     line_s *p;
 385     int x, x1, y, cols_to_skip;
 386     int i;
 387     int wrap_start;
 388     int len;
 389 
 390     x = start_col_real;
 391     x1 = start_col + EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width;
 392     y = row + EDIT_TEXT_VERTICAL_OFFSET;
 393     cols_to_skip = abs (x);
 394 
 395     if (!edit->fullscreen)
 396     {
 397         x1++;
 398         y++;
 399     }
 400 
 401     tty_setcolor (EDITOR_NORMAL_COLOR);
 402     if (bookmarked != 0)
 403         tty_setcolor (bookmarked);
 404 
 405     len = end_col + 1 - start_col;
 406     wrap_start = edit_options.word_wrap_line_length + edit->start_col;
 407 
 408     if (len > 0 && w->rect.y + y >= 0)
 409     {
 410         if (!edit_options.show_right_margin || wrap_start > end_col)
 411             tty_draw_hline (w->rect.y + y, w->rect.x + x1, ' ', len);
 412         else if (wrap_start < 0)
 413         {
 414             tty_setcolor (EDITOR_RIGHT_MARGIN_COLOR);
 415             tty_draw_hline (w->rect.y + y, w->rect.x + x1, ' ', len);
 416         }
 417         else
 418         {
 419             if (wrap_start > 0)
 420                 tty_draw_hline (w->rect.y + y, w->rect.x + x1, ' ', wrap_start);
 421 
 422             len -= wrap_start;
 423             if (len > 0)
 424             {
 425                 tty_setcolor (EDITOR_RIGHT_MARGIN_COLOR);
 426                 tty_draw_hline (w->rect.y + y, w->rect.x + x1 + wrap_start, ' ', len);
 427             }
 428         }
 429     }
 430 
 431     if (edit_options.line_state)
 432     {
 433         tty_setcolor (LINE_STATE_COLOR);
 434 
 435         for (i = 0; i < LINE_STATE_WIDTH; i++)
 436         {
 437             edit_move (x1 + i - edit_options.line_state_width, y);
 438             if (status[i] == '\0')
 439                 status[i] = ' ';
 440             tty_print_char (status[i]);
 441         }
 442     }
 443 
 444     edit_move (x1, y);
 445 
 446     i = 1;
 447     for (p = line; p->ch != 0; p++)
 448     {
 449         int style;
 450         unsigned int textchar;
 451 
 452         if (cols_to_skip != 0)
 453         {
 454             cols_to_skip--;
 455             continue;
 456         }
 457 
 458         style = p->style & 0xFF00;
 459         textchar = p->ch;
 460 
 461         if ((style & MOD_WHITESPACE) != 0)
 462         {
 463             if ((style & MOD_MARKED) == 0)
 464                 tty_setcolor (EDITOR_WHITESPACE_COLOR);
 465             else
 466             {
 467                 textchar = ' ';
 468                 tty_setcolor (EDITOR_MARKED_COLOR);
 469             }
 470         }
 471         else if ((style & MOD_BOLD) != 0)
 472             tty_setcolor (EDITOR_BOLD_COLOR);
 473         else if ((style & MOD_MARKED) != 0)
 474             tty_setcolor (EDITOR_MARKED_COLOR);
 475         else if ((style & MOD_ABNORMAL) != 0)
 476             tty_setcolor (EDITOR_NONPRINTABLE_COLOR);
 477         else
 478             tty_lowlevel_setcolor (p->style >> 16);
 479 
 480         if (edit_options.show_right_margin)
 481         {
 482             if (i > edit_options.word_wrap_line_length + edit->start_col)
 483                 tty_setcolor (EDITOR_RIGHT_MARGIN_COLOR);
 484             i++;
 485         }
 486 
 487         tty_print_anychar (textchar);
 488     }
 489 }
 490 
 491 /* --------------------------------------------------------------------------------------------- */
 492 /** b is a pointer to the beginning of the line */
 493 
 494 static void
 495 edit_draw_this_line (WEdit *edit, off_t b, long row, long start_col, long end_col)
     /* [previous][next][first][last][top][bottom][index][help]  */
 496 {
 497     Widget *w = WIDGET (edit);
 498     line_s line[MAX_LINE_LEN];
 499     line_s *p = line;
 500     off_t q;
 501     int col, start_col_real;
 502     int abn_style;
 503     int book_mark = 0;
 504     char line_stat[LINE_STATE_WIDTH + 1] = "\0";
 505 
 506     if (row > w->rect.lines - 1 - EDIT_TEXT_VERTICAL_OFFSET - 2 * (edit->fullscreen ? 0 : 1))
 507         return;
 508 
 509     if (book_mark_query_color (edit, edit->start_line + row, BOOK_MARK_COLOR))
 510         book_mark = BOOK_MARK_COLOR;
 511     else if (book_mark_query_color (edit, edit->start_line + row, BOOK_MARK_FOUND_COLOR))
 512         book_mark = BOOK_MARK_FOUND_COLOR;
 513 
 514     if (book_mark != 0)
 515         abn_style = book_mark << 16;
 516     else
 517         abn_style = MOD_ABNORMAL;
 518 
 519     end_col -= EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width;
 520     if (!edit->fullscreen)
 521     {
 522         end_col--;
 523         if (w->rect.x + w->rect.cols <= WIDGET (w->owner)->rect.cols)
 524             end_col--;
 525     }
 526 
 527     q = edit_move_forward3 (edit, b, start_col - edit->start_col, 0);
 528     col = (int) edit_move_forward3 (edit, b, 0, q);
 529     start_col_real = col + edit->start_col;
 530 
 531     if (edit_options.line_state)
 532     {
 533         long cur_line;
 534 
 535         cur_line = edit->start_line + row;
 536         if (cur_line <= edit->buffer.lines)
 537             g_snprintf (line_stat, sizeof (line_stat), "%7ld ", cur_line + 1);
 538         else
 539         {
 540             memset (line_stat, ' ', LINE_STATE_WIDTH);
 541             line_stat[LINE_STATE_WIDTH] = '\0';
 542         }
 543 
 544         if (book_mark_query_color (edit, cur_line, BOOK_MARK_COLOR))
 545             g_snprintf (line_stat, 2, "*");
 546     }
 547 
 548     if (col <= -(edit->start_col + 16))
 549         start_col_real = start_col = 0;
 550     else
 551     {
 552         off_t m1 = 0, m2 = 0;
 553 
 554         eval_marks (edit, &m1, &m2);
 555 
 556         if (row <= edit->buffer.lines - edit->start_line)
 557         {
 558             off_t tws = 0;
 559 
 560             if (edit_options.visible_tws && tty_use_colors ())
 561                 for (tws = edit_buffer_get_eol (&edit->buffer, b); tws > b; tws--)
 562                 {
 563                     unsigned int c;
 564 
 565                     c = edit_buffer_get_byte (&edit->buffer, tws - 1);
 566                     if (!whitespace (c))
 567                         break;
 568                 }
 569 
 570             while (col <= end_col - edit->start_col)
 571             {
 572                 int char_length = 1;
 573                 unsigned int c;
 574                 gboolean wide_width_char = FALSE;
 575                 gboolean control_char = FALSE;
 576                 gboolean printable;
 577 
 578                 p->ch = 0;
 579                 p->style = q == edit->buffer.curs1 ? MOD_CURSOR : 0;
 580 
 581                 if (q >= m1 && q < m2)
 582                 {
 583                     if (!edit->column_highlight)
 584                         p->style |= MOD_MARKED;
 585                     else
 586                     {
 587                         long x, cl;
 588 
 589                         x = (long) edit_move_forward3 (edit, b, 0, q);
 590                         cl = MIN (edit->column1, edit->column2);
 591                         if (x >= cl)
 592                         {
 593                             cl = MAX (edit->column1, edit->column2);
 594                             if (x < cl)
 595                                 p->style |= MOD_MARKED;
 596                         }
 597                     }
 598                 }
 599 
 600                 if (q == edit->bracket)
 601                     p->style |= MOD_BOLD;
 602                 if (q >= edit->found_start && q < (off_t) (edit->found_start + edit->found_len))
 603                     p->style |= MOD_BOLD;
 604 
 605 #ifdef HAVE_CHARSET
 606                 if (edit->utf8)
 607                     c = edit_buffer_get_utf (&edit->buffer, q, &char_length);
 608                 else
 609 #endif
 610                     c = edit_buffer_get_byte (&edit->buffer, q);
 611 
 612                 /* we don't use bg for mc - fg contains both */
 613                 if (book_mark != 0)
 614                     p->style |= book_mark << 16;
 615                 else
 616                 {
 617                     int color;
 618 
 619                     color = edit_get_syntax_color (edit, q);
 620                     p->style |= color << 16;
 621                 }
 622 
 623                 switch (c)
 624                 {
 625                 case '\n':
 626                     col = end_col - edit->start_col + 1;        /* quit */
 627                     break;
 628 
 629                 case '\t':
 630                     {
 631                         int tab_over;
 632                         int i;
 633 
 634                         i = TAB_SIZE - ((int) col % TAB_SIZE);
 635                         tab_over = (end_col - edit->start_col) - (col + i - 1);
 636                         if (tab_over < 0)
 637                             i += tab_over;
 638                         col += i;
 639                         if ((edit_options.visible_tabs || (edit_options.visible_tws && q >= tws))
 640                             && enable_show_tabs_tws && tty_use_colors ())
 641                         {
 642                             if ((p->style & MOD_MARKED) != 0)
 643                                 c = p->style;
 644                             else if (book_mark != 0)
 645                                 c |= book_mark << 16;
 646                             else
 647                                 c = p->style | MOD_WHITESPACE;
 648                             if (i > 2)
 649                             {
 650                                 p->ch = '<';
 651                                 p->style = c;
 652                                 p++;
 653                                 while (--i > 1)
 654                                 {
 655                                     p->ch = '-';
 656                                     p->style = c;
 657                                     p++;
 658                                 }
 659                                 p->ch = '>';
 660                                 p->style = c;
 661                                 p++;
 662                             }
 663                             else if (i > 1)
 664                             {
 665                                 p->ch = '<';
 666                                 p->style = c;
 667                                 p++;
 668                                 p->ch = '>';
 669                                 p->style = c;
 670                                 p++;
 671                             }
 672                             else
 673                             {
 674                                 p->ch = '>';
 675                                 p->style = c;
 676                                 p++;
 677                             }
 678                         }
 679                         else if (edit_options.visible_tws && q >= tws && enable_show_tabs_tws
 680                                  && tty_use_colors ())
 681                         {
 682                             p->ch = '.';
 683                             p->style |= MOD_WHITESPACE;
 684                             c = p->style & ~MOD_CURSOR;
 685                             p++;
 686                             while (--i != 0)
 687                             {
 688                                 p->ch = ' ';
 689                                 p->style = c;
 690                                 p++;
 691                             }
 692                         }
 693                         else
 694                         {
 695                             p->ch |= ' ';
 696                             c = p->style & ~MOD_CURSOR;
 697                             p++;
 698                             while (--i != 0)
 699                             {
 700                                 p->ch = ' ';
 701                                 p->style = c;
 702                                 p++;
 703                             }
 704                         }
 705                     }
 706                     break;
 707 
 708                 case ' ':
 709                     if (edit_options.visible_tws && q >= tws && enable_show_tabs_tws
 710                         && tty_use_colors ())
 711                     {
 712                         p->ch = '.';
 713                         p->style |= MOD_WHITESPACE;
 714                         p++;
 715                         col++;
 716                         break;
 717                     }
 718                     MC_FALLTHROUGH;
 719 
 720                 default:
 721 #ifdef HAVE_CHARSET
 722                     if (mc_global.utf8_display)
 723                     {
 724                         if (!edit->utf8)
 725                             c = convert_from_8bit_to_utf_c ((unsigned char) c, edit->converter);
 726                         else if (g_unichar_iswide (c))
 727                         {
 728                             wide_width_char = TRUE;
 729                             col++;
 730                         }
 731                     }
 732                     else if (edit->utf8)
 733                         c = convert_from_utf_to_current_c (c, edit->converter);
 734                     else
 735                         c = convert_to_display_c (c);
 736 #endif
 737 
 738                     /* Caret notation for control characters */
 739                     if (c < 32)
 740                     {
 741                         p->ch = '^';
 742                         p->style = abn_style;
 743                         p++;
 744                         p->ch = c + 0x40;
 745                         p->style = abn_style;
 746                         p++;
 747                         col += 2;
 748                         control_char = TRUE;
 749                         break;
 750                     }
 751                     if (c == 127)
 752                     {
 753                         p->ch = '^';
 754                         p->style = abn_style;
 755                         p++;
 756                         p->ch = '?';
 757                         p->style = abn_style;
 758                         p++;
 759                         col += 2;
 760                         control_char = TRUE;
 761                         break;
 762                     }
 763 
 764 #ifdef HAVE_CHARSET
 765                     if (edit->utf8)
 766                     {
 767                         if (mc_global.utf8_display)
 768                             /* c is gunichar */
 769                             printable = g_unichar_isprint (c);
 770                         else
 771                             /* c was gunichar; now c is 8-bit char converted from gunichar */
 772                             printable = is_printable (c);
 773                     }
 774                     else
 775 #endif
 776                         /* c is 8-bit char */
 777                         printable = is_printable (c);
 778 
 779                     if (printable)
 780                         p->ch = c;
 781                     else
 782                     {
 783                         p->ch = '.';
 784                         p->style = abn_style;
 785                     }
 786                     p++;
 787                     col++;
 788                     break;
 789                 }               /* case */
 790 
 791                 q++;
 792                 if (char_length > 1)
 793                     q += char_length - 1;
 794 
 795                 if (col > (end_col - edit->start_col + 1))
 796                 {
 797                     if (wide_width_char)
 798                     {
 799                         p--;
 800                         break;
 801                     }
 802                     if (control_char)
 803                     {
 804                         p -= 2;
 805                         break;
 806                     }
 807                 }
 808             }
 809         }
 810     }
 811 
 812     p->ch = 0;
 813 
 814     print_to_widget (edit, row, start_col, start_col_real, end_col, line, line_stat, book_mark);
 815 }
 816 
 817 /* --------------------------------------------------------------------------------------------- */
 818 
 819 static inline void
 820 edit_draw_this_char (WEdit *edit, off_t curs, long row, long start_column, long end_column)
     /* [previous][next][first][last][top][bottom][index][help]  */
 821 {
 822     off_t b;
 823 
 824     b = edit_buffer_get_bol (&edit->buffer, curs);
 825     edit_draw_this_line (edit, b, row, start_column, end_column);
 826 }
 827 
 828 /* --------------------------------------------------------------------------------------------- */
 829 /** cursor must be in screen for other than REDRAW_PAGE passed in force */
 830 
 831 static inline void
 832 render_edit_text (WEdit *edit, long start_row, long start_column, long end_row, long end_column)
     /* [previous][next][first][last][top][bottom][index][help]  */
 833 {
 834     static long prev_curs_row = 0;
 835     static off_t prev_curs = 0;
 836 
 837     Widget *we = WIDGET (edit);
 838     Widget *wh = WIDGET (we->owner);
 839     WRect *w = &we->rect;
 840 
 841     int force = edit->force;
 842     int y1, x1, y2, x2;
 843     int last_line, last_column;
 844 
 845     /* draw only visible region */
 846 
 847     last_line = wh->rect.y + wh->rect.lines - 1;
 848 
 849     y1 = w->y;
 850     if (y1 > last_line - 1 /* buttonbar */ )
 851         return;
 852 
 853     last_column = wh->rect.x + wh->rect.cols - 1;
 854 
 855     x1 = w->x;
 856     if (x1 > last_column)
 857         return;
 858 
 859     y2 = w->y + w->lines - 1;
 860     if (y2 < wh->rect.y + 1 /* menubar */ )
 861         return;
 862 
 863     x2 = w->x + w->cols - 1;
 864     if (x2 < wh->rect.x)
 865         return;
 866 
 867     if ((force & REDRAW_IN_BOUNDS) == 0)
 868     {
 869         /* !REDRAW_IN_BOUNDS means to ignore bounds and redraw whole rows */
 870         /* draw only visible region */
 871 
 872         if (y2 <= last_line - 1 /* buttonbar */ )
 873             end_row = w->lines - 1;
 874         else if (y1 >= wh->rect.y + 1 /* menubar */ )
 875             end_row = wh->rect.lines - 1 - y1 - 1;
 876         else
 877             end_row = start_row + wh->rect.lines - 1 - 1;
 878 
 879         if (x2 <= last_column)
 880             end_column = w->cols - 1;
 881         else if (x1 >= wh->rect.x)
 882             end_column = wh->rect.cols - 1 - x1;
 883         else
 884             end_column = start_column + wh->rect.cols - 1;
 885     }
 886 
 887     /*
 888      * If the position of the page has not moved then we can draw the cursor
 889      * character only.  This will prevent line flicker when using arrow keys.
 890      */
 891     if ((force & REDRAW_CHAR_ONLY) == 0 || (force & REDRAW_PAGE) != 0)
 892     {
 893         long row = 0;
 894         long b;
 895 
 896         if ((force & REDRAW_PAGE) != 0)
 897         {
 898             b = edit_buffer_get_forward_offset (&edit->buffer, edit->start_display, start_row, 0);
 899             for (row = start_row; row <= end_row; row++)
 900             {
 901                 if (key_pending (edit))
 902                     return;
 903                 edit_draw_this_line (edit, b, row, start_column, end_column);
 904                 b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 905             }
 906         }
 907         else
 908         {
 909             long curs_row = edit->curs_row;
 910 
 911             if ((force & REDRAW_BEFORE_CURSOR) != 0 && start_row < curs_row)
 912             {
 913                 long upto;
 914 
 915                 b = edit->start_display;
 916                 upto = MIN (curs_row - 1, end_row);
 917                 for (row = start_row; row <= upto; row++)
 918                 {
 919                     if (key_pending (edit))
 920                         return;
 921                     edit_draw_this_line (edit, b, row, start_column, end_column);
 922                     b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 923                 }
 924             }
 925 
 926             /*          if (force & REDRAW_LINE)          ---> default */
 927             b = edit_buffer_get_current_bol (&edit->buffer);
 928             if (curs_row >= start_row && curs_row <= end_row)
 929             {
 930                 if (key_pending (edit))
 931                     return;
 932                 edit_draw_this_line (edit, b, curs_row, start_column, end_column);
 933             }
 934 
 935             if ((force & REDRAW_AFTER_CURSOR) != 0 && end_row > curs_row)
 936             {
 937                 b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 938                 for (row = MAX (curs_row + 1, start_row); row <= end_row; row++)
 939                 {
 940                     if (key_pending (edit))
 941                         return;
 942                     edit_draw_this_line (edit, b, row, start_column, end_column);
 943                     b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 944                 }
 945             }
 946 
 947             if ((force & REDRAW_LINE_ABOVE) != 0 && curs_row >= 1)
 948             {
 949                 row = curs_row - 1;
 950                 b = edit_buffer_get_current_bol (&edit->buffer);
 951                 b = edit_buffer_get_backward_offset (&edit->buffer, b, 1);
 952                 if (row >= start_row && row <= end_row)
 953                 {
 954                     if (key_pending (edit))
 955                         return;
 956                     edit_draw_this_line (edit, b, row, start_column, end_column);
 957                 }
 958             }
 959 
 960             if ((force & REDRAW_LINE_BELOW) != 0 && row < w->lines - 1)
 961             {
 962                 row = curs_row + 1;
 963                 b = edit_buffer_get_current_bol (&edit->buffer);
 964                 b = edit_buffer_get_forward_offset (&edit->buffer, b, 1, 0);
 965                 if (row >= start_row && row <= end_row)
 966                 {
 967                     if (key_pending (edit))
 968                         return;
 969                     edit_draw_this_line (edit, b, row, start_column, end_column);
 970                 }
 971             }
 972         }
 973     }
 974     else if (prev_curs_row < edit->curs_row)
 975     {
 976         /* with the new text highlighting, we must draw from the top down */
 977         edit_draw_this_char (edit, prev_curs, prev_curs_row, start_column, end_column);
 978         edit_draw_this_char (edit, edit->buffer.curs1, edit->curs_row, start_column, end_column);
 979     }
 980     else
 981     {
 982         edit_draw_this_char (edit, edit->buffer.curs1, edit->curs_row, start_column, end_column);
 983         edit_draw_this_char (edit, prev_curs, prev_curs_row, start_column, end_column);
 984     }
 985 
 986     edit->force = 0;
 987 
 988     prev_curs_row = edit->curs_row;
 989     prev_curs = edit->buffer.curs1;
 990 }
 991 
 992 /* --------------------------------------------------------------------------------------------- */
 993 
 994 static inline void
 995 edit_render (WEdit *edit, int page, int row_start, int col_start, int row_end, int col_end)
     /* [previous][next][first][last][top][bottom][index][help]  */
 996 {
 997     if (page != 0)              /* if it was an expose event, 'page' would be set */
 998         edit->force |= REDRAW_PAGE | REDRAW_IN_BOUNDS;
 999 
1000     render_edit_text (edit, row_start, col_start, row_end, col_end);
1001 
1002     /*
1003      * edit->force != 0 means a key was pending and the redraw
1004      * was halted, so next time we must redraw everything in case stuff
1005      * was left undrawn from a previous key press.
1006      */
1007     if (edit->force != 0)
1008         edit->force |= REDRAW_PAGE;
1009 }
1010 
1011 /* --------------------------------------------------------------------------------------------- */
1012 /*** public functions ****************************************************************************/
1013 /* --------------------------------------------------------------------------------------------- */
1014 
1015 void
1016 edit_status (WEdit *edit, gboolean active)
     /* [previous][next][first][last][top][bottom][index][help]  */
1017 {
1018     int color;
1019 
1020     if (edit->fullscreen)
1021     {
1022         color = STATUSBAR_COLOR;
1023         edit_status_fullscreen (edit, color);
1024     }
1025     else
1026     {
1027         color = edit->drag_state != MCEDIT_DRAG_NONE ? EDITOR_FRAME_DRAG : active ?
1028             EDITOR_FRAME_ACTIVE : EDITOR_FRAME;
1029         edit_draw_frame (edit, color, active);
1030         edit_status_window (edit);
1031     }
1032 
1033     edit_draw_window_icons (edit, color);
1034 }
1035 
1036 /* --------------------------------------------------------------------------------------------- */
1037 
1038 /** this scrolls the text so that cursor is on the screen */
1039 void
1040 edit_scroll_screen_over_cursor (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1041 {
1042     WRect *w = &WIDGET (edit)->rect;
1043 
1044     long p;
1045     long outby;
1046     int b_extreme, t_extreme, l_extreme, r_extreme;
1047 
1048     if (w->lines <= 0 || w->cols <= 0)
1049         return;
1050 
1051     rect_resize (w, -EDIT_TEXT_VERTICAL_OFFSET,
1052                  -(EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width));
1053 
1054     if (!edit->fullscreen)
1055         rect_grow (w, -1, -1);
1056 
1057     r_extreme = EDIT_RIGHT_EXTREME;
1058     l_extreme = EDIT_LEFT_EXTREME;
1059     b_extreme = EDIT_BOTTOM_EXTREME;
1060     t_extreme = EDIT_TOP_EXTREME;
1061     if (edit->found_len != 0)
1062     {
1063         b_extreme = MAX (w->lines / 4, b_extreme);
1064         t_extreme = MAX (w->lines / 4, t_extreme);
1065     }
1066     if (b_extreme + t_extreme + 1 > w->lines)
1067     {
1068         int n;
1069 
1070         n = b_extreme + t_extreme;
1071         if (n == 0)
1072             n = 1;
1073         b_extreme = (b_extreme * (w->lines - 1)) / n;
1074         t_extreme = (t_extreme * (w->lines - 1)) / n;
1075     }
1076     if (l_extreme + r_extreme + 1 > w->cols)
1077     {
1078         int n;
1079 
1080         n = l_extreme + r_extreme;
1081         if (n == 0)
1082             n = 1;
1083         l_extreme = (l_extreme * (w->cols - 1)) / n;
1084         r_extreme = (r_extreme * (w->cols - 1)) / n;
1085     }
1086     p = edit_get_col (edit) + edit->over_col;
1087     edit_update_curs_row (edit);
1088     outby = p + edit->start_col - w->cols + 1 + (r_extreme + edit->found_len);
1089     if (outby > 0)
1090         edit_scroll_right (edit, outby);
1091     outby = l_extreme - p - edit->start_col;
1092     if (outby > 0)
1093         edit_scroll_left (edit, outby);
1094     p = edit->curs_row;
1095     outby = p - w->lines + 1 + b_extreme;
1096     if (outby > 0)
1097         edit_scroll_downward (edit, outby);
1098     outby = t_extreme - p;
1099     if (outby > 0)
1100         edit_scroll_upward (edit, outby);
1101     edit_update_curs_row (edit);
1102 
1103     rect_resize (w, EDIT_TEXT_VERTICAL_OFFSET,
1104                  EDIT_TEXT_HORIZONTAL_OFFSET + edit_options.line_state_width);
1105     if (!edit->fullscreen)
1106         rect_grow (w, 1, 1);
1107 }
1108 
1109 /* --------------------------------------------------------------------------------------------- */
1110 
1111 void
1112 edit_render_keypress (WEdit *edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1113 {
1114     edit_render (edit, 0, 0, 0, 0, 0);
1115 }
1116 
1117 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */