Manual pages: mcmcdiffmceditmcview

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

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