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

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