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

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