root/src/editor/editwidget.c

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

DEFINITIONS

This source file includes following definitions.
  1. edit_dlg_init
  2. edit_dlg_deinit
  3. edit_about
  4. edit_help
  5. edit_dialog_resize_cb
  6. edit_restore_size
  7. edit_window_move
  8. edit_window_resize
  9. get_hotkey
  10. edit_window_list
  11. edit_get_shortcut
  12. edit_get_title
  13. edit_dialog_command_execute
  14. edit_translate_key
  15. edit_quit
  16. edit_set_buttonbar
  17. edit_total_update
  18. edit_update_cursor
  19. edit_dialog_callback
  20. edit_dialog_mouse_callback
  21. edit_callback
  22. edit_mouse_handle_move_resize
  23. edit_mouse_callback
  24. edit_file
  25. edit_files
  26. edit_get_file_name
  27. find_editor
  28. edit_widget_is_editor
  29. edit_update_screen
  30. edit_save_size
  31. edit_add_window
  32. edit_handle_move_resize
  33. edit_toggle_fullscreen

   1 /*
   2    Editor initialisation and callback handler.
   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 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 /** \file
  28  *  \brief Source: editor initialisation and callback handler
  29  *  \author Paul Sheer
  30  *  \date 1996, 1997
  31  */
  32 
  33 #include <config.h>
  34 
  35 #include <ctype.h>
  36 #include <errno.h>
  37 #include <stdlib.h>
  38 #include <string.h>
  39 #include <sys/types.h>
  40 #include <unistd.h>
  41 
  42 #include "lib/global.h"
  43 
  44 #include "lib/tty/tty.h"        /* LINES, COLS */
  45 #include "lib/tty/key.h"        /* is_idle() */
  46 #include "lib/tty/color.h"      /* tty_setcolor() */
  47 #include "lib/skin.h"
  48 #include "lib/fileloc.h"        /* EDIT_DIR */
  49 #include "lib/strutil.h"        /* str_term_trim() */
  50 #include "lib/util.h"           /* mc_build_filename() */
  51 #include "lib/widget.h"
  52 #include "lib/mcconfig.h"
  53 #include "lib/event.h"          /* mc_event_raise() */
  54 #ifdef HAVE_CHARSET
  55 #include "lib/charsets.h"
  56 #endif
  57 
  58 #include "src/keybind-defaults.h"       /* keybind_lookup_keymap_command() */
  59 #include "src/setup.h"          /* home_dir */
  60 #include "src/filemanager/cmd.h"        /* view_other_cmd(), save_setup_cmd()  */
  61 #include "src/learn.h"          /* learn_keys() */
  62 #include "src/args.h"           /* mcedit_arg_t */
  63 
  64 #include "edit-impl.h"
  65 #include "editwidget.h"
  66 #ifdef HAVE_ASPELL
  67 #include "spell.h"
  68 #endif
  69 
  70 /*** global variables ****************************************************************************/
  71 
  72 char *edit_window_state_char = NULL;
  73 char *edit_window_close_char = NULL;
  74 
  75 /*** file scope macro definitions ****************************************************************/
  76 
  77 #define WINDOW_MIN_LINES (2 + 2)
  78 #define WINDOW_MIN_COLS (2 + LINE_STATE_WIDTH + 2)
  79 
  80 /*** file scope type declarations ****************************************************************/
  81 
  82 /*** file scope variables ************************************************************************/
  83 static unsigned int edit_dlg_init_refcounter = 0;
  84 
  85 /*** file scope functions ************************************************************************/
  86 
  87 static cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
  88                                       void *data);
  89 
  90 /* --------------------------------------------------------------------------------------------- */
  91 /**
  92  * Init the 'edit' subsystem
  93  */
  94 
  95 static void
  96 edit_dlg_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  97 {
  98     if (edit_dlg_init_refcounter == 0)
  99     {
 100         edit_window_state_char = mc_skin_get ("widget-editor", "window-state-char", "*");
 101         edit_window_close_char = mc_skin_get ("widget-editor", "window-close-char", "X");
 102 
 103 #ifdef HAVE_ASPELL
 104         aspell_init ();
 105 #endif
 106     }
 107 
 108     edit_dlg_init_refcounter++;
 109 }
 110 
 111 /* --------------------------------------------------------------------------------------------- */
 112 /**
 113  * Deinit the 'edit' subsystem
 114  */
 115 
 116 static void
 117 edit_dlg_deinit (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 118 {
 119     if (edit_dlg_init_refcounter != 0)
 120         edit_dlg_init_refcounter--;
 121 
 122     if (edit_dlg_init_refcounter == 0)
 123     {
 124         g_free (edit_window_state_char);
 125         g_free (edit_window_close_char);
 126 
 127 #ifdef HAVE_ASPELL
 128         aspell_clean ();
 129 #endif
 130     }
 131 }
 132 
 133 /* --------------------------------------------------------------------------------------------- */
 134 /**
 135  * Show info about editor
 136  */
 137 
 138 static void
 139 edit_about (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 140 {
 141     quick_widget_t quick_widgets[] = {
 142         /* *INDENT-OFF* */
 143         QUICK_LABEL ("MCEdit " VERSION, NULL),
 144         QUICK_SEPARATOR (TRUE),
 145         QUICK_LABEL (N_("A user friendly text editor\n"
 146                         "written for the Midnight Commander."), NULL),
 147         QUICK_SEPARATOR (FALSE),
 148         QUICK_LABEL (N_("Copyright (C) 1996-2019 the Free Software Foundation"), NULL),
 149         QUICK_START_BUTTONS (TRUE, TRUE),
 150             QUICK_BUTTON (N_("&OK"), B_ENTER, NULL, NULL),
 151         QUICK_END
 152         /* *INDENT-ON* */
 153     };
 154 
 155     quick_dialog_t qdlg = {
 156         -1, -1, 40,
 157         N_("About"), "[Internal File Editor]",
 158         quick_widgets, NULL, NULL
 159     };
 160 
 161     quick_widgets[0].pos_flags = WPOS_KEEP_TOP | WPOS_CENTER_HORZ;
 162     quick_widgets[2].pos_flags = WPOS_KEEP_TOP | WPOS_CENTER_HORZ;
 163     quick_widgets[4].pos_flags = WPOS_KEEP_TOP | WPOS_CENTER_HORZ;
 164 
 165     (void) quick_dialog (&qdlg);
 166 }
 167 
 168 /* --------------------------------------------------------------------------------------------- */
 169 /**
 170  * Show a help window
 171  */
 172 
 173 static void
 174 edit_help (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 175 {
 176     ev_help_t event_data = { NULL, "[Internal File Editor]" };
 177     mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
 178 }
 179 
 180 /* --------------------------------------------------------------------------------------------- */
 181 /**
 182  * Callback for the iteration of objects in the 'editors' array.
 183  * Resize the editor window.
 184  *
 185  * @param data      probably WEdit object
 186  * @param user_data unused
 187  */
 188 
 189 static void
 190 edit_dialog_resize_cb (void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 191 {
 192     Widget *w = WIDGET (data);
 193 
 194     (void) user_data;
 195 
 196     if (edit_widget_is_editor (w) && ((WEdit *) w)->fullscreen)
 197     {
 198         Widget *wh = WIDGET (w->owner);
 199 
 200         w->lines = wh->lines - 2;
 201         w->cols = wh->cols;
 202     }
 203 }
 204 
 205 /* --------------------------------------------------------------------------------------------- */
 206 /**
 207  * Restore saved window size.
 208  *
 209  * @param edit editor object
 210  */
 211 
 212 static void
 213 edit_restore_size (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 214 {
 215     Widget *w = WIDGET (edit);
 216 
 217     edit->drag_state = MCEDIT_DRAG_NONE;
 218     w->mouse.forced_capture = FALSE;
 219     widget_set_size (w, edit->y_prev, edit->x_prev, edit->lines_prev, edit->cols_prev);
 220     dlg_redraw (w->owner);
 221 }
 222 
 223 /* --------------------------------------------------------------------------------------------- */
 224 /**
 225  * Move window by one row or column in any direction.
 226  *
 227  * @param edit    editor object
 228  * @param command direction (CK_Up, CK_Down, CK_Left, CK_Right)
 229  */
 230 
 231 static void
 232 edit_window_move (WEdit * edit, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 233 {
 234     Widget *w = WIDGET (edit);
 235     Widget *wh = WIDGET (w->owner);
 236 
 237     switch (command)
 238     {
 239     case CK_Up:
 240         if (w->y > wh->y + 1)   /* menubar */
 241             w->y--;
 242         break;
 243     case CK_Down:
 244         if (w->y < wh->y + wh->lines - 2)       /* buttonbar */
 245             w->y++;
 246         break;
 247     case CK_Left:
 248         if (w->x + w->cols > wh->x)
 249             w->x--;
 250         break;
 251     case CK_Right:
 252         if (w->x < wh->x + wh->cols)
 253             w->x++;
 254         break;
 255     default:
 256         return;
 257     }
 258 
 259     edit->force |= REDRAW_PAGE;
 260     dlg_redraw (w->owner);
 261 }
 262 
 263 /* --------------------------------------------------------------------------------------------- */
 264 /**
 265  * Resize window by one row or column in any direction.
 266  *
 267  * @param edit    editor object
 268  * @param command direction (CK_Up, CK_Down, CK_Left, CK_Right)
 269  */
 270 
 271 static void
 272 edit_window_resize (WEdit * edit, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 273 {
 274     Widget *w = WIDGET (edit);
 275     Widget *wh = WIDGET (w->owner);
 276 
 277     switch (command)
 278     {
 279     case CK_Up:
 280         if (w->lines > WINDOW_MIN_LINES)
 281             w->lines--;
 282         break;
 283     case CK_Down:
 284         if (w->y + w->lines < wh->y + wh->lines - 1)    /* buttonbar */
 285             w->lines++;
 286         break;
 287     case CK_Left:
 288         if (w->cols > WINDOW_MIN_COLS)
 289             w->cols--;
 290         break;
 291     case CK_Right:
 292         if (w->x + w->cols < wh->x + wh->cols)
 293             w->cols++;
 294         break;
 295     default:
 296         return;
 297     }
 298 
 299     edit->force |= REDRAW_COMPLETELY;
 300     dlg_redraw (w->owner);
 301 }
 302 
 303 /* --------------------------------------------------------------------------------------------- */
 304 /**
 305  * Get hotkey by number.
 306  *
 307  * @param n number
 308  * @return hotkey
 309  */
 310 
 311 static unsigned char
 312 get_hotkey (int n)
     /* [previous][next][first][last][top][bottom][index][help]  */
 313 {
 314     return (n <= 9) ? '0' + n : 'a' + n - 10;
 315 }
 316 
 317 /* --------------------------------------------------------------------------------------------- */
 318 
 319 static void
 320 edit_window_list (const WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 321 {
 322     const size_t dlg_num = g_list_length (h->widgets) - 2;      /* 2 = skip menu and buttonbar */
 323     int lines, cols;
 324     Listbox *listbox;
 325     GList *w;
 326     WEdit *selected;
 327     int i = 0;
 328 
 329     lines = MIN ((size_t) (LINES * 2 / 3), dlg_num);
 330     cols = COLS * 2 / 3;
 331 
 332     listbox = create_listbox_window (lines, cols, _("Open files"), "[Open files]");
 333 
 334     for (w = h->widgets; w != NULL; w = g_list_next (w))
 335         if (edit_widget_is_editor (CONST_WIDGET (w->data)))
 336         {
 337             WEdit *e = (WEdit *) w->data;
 338             char *fname;
 339 
 340             if (e->filename_vpath == NULL)
 341                 fname = g_strdup_printf ("%c [%s]", e->modified ? '*' : ' ', _("NoName"));
 342             else
 343                 fname =
 344                     g_strdup_printf ("%c%s", e->modified ? '*' : ' ',
 345                                      vfs_path_as_str (e->filename_vpath));
 346 
 347             listbox_add_item (listbox->list, LISTBOX_APPEND_AT_END, get_hotkey (i++),
 348                               str_term_trim (fname, WIDGET (listbox->list)->cols - 2), e, FALSE);
 349             g_free (fname);
 350         }
 351 
 352     selected = run_listbox_with_data (listbox, h->current->data);
 353     if (selected != NULL)
 354         widget_select (WIDGET (selected));
 355 }
 356 
 357 /* --------------------------------------------------------------------------------------------- */
 358 
 359 static char *
 360 edit_get_shortcut (long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 361 {
 362     const char *ext_map;
 363     const char *shortcut = NULL;
 364 
 365     shortcut = keybind_lookup_keymap_shortcut (editor_map, command);
 366     if (shortcut != NULL)
 367         return g_strdup (shortcut);
 368 
 369     ext_map = keybind_lookup_keymap_shortcut (editor_map, CK_ExtendedKeyMap);
 370     if (ext_map != NULL)
 371         shortcut = keybind_lookup_keymap_shortcut (editor_x_map, command);
 372     if (shortcut != NULL)
 373         return g_strdup_printf ("%s %s", ext_map, shortcut);
 374 
 375     return NULL;
 376 }
 377 
 378 /* --------------------------------------------------------------------------------------------- */
 379 
 380 static char *
 381 edit_get_title (const WDialog * h, size_t len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 382 {
 383     const WEdit *edit = find_editor (h);
 384     const char *modified = edit->modified ? "(*) " : "    ";
 385     const char *file_label;
 386     char *filename;
 387 
 388     len -= 4;
 389 
 390     if (edit->filename_vpath == NULL)
 391         filename = g_strdup (_("[NoName]"));
 392     else
 393         filename = g_strdup (vfs_path_as_str (edit->filename_vpath));
 394 
 395     file_label = str_term_trim (filename, len - str_term_width1 (_("Edit: ")));
 396     g_free (filename);
 397 
 398     return g_strconcat (_("Edit: "), modified, file_label, (char *) NULL);
 399 }
 400 
 401 /* --------------------------------------------------------------------------------------------- */
 402 
 403 static cb_ret_t
 404 edit_dialog_command_execute (WDialog * h, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 405 {
 406     Widget *wh = WIDGET (h);
 407     cb_ret_t ret = MSG_HANDLED;
 408 
 409     switch (command)
 410     {
 411     case CK_EditNew:
 412         edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0);
 413         break;
 414     case CK_EditFile:
 415         edit_load_cmd (h);
 416         break;
 417     case CK_History:
 418         edit_load_file_from_history (h);
 419         break;
 420     case CK_EditSyntaxFile:
 421         edit_load_syntax_file (h);
 422         break;
 423     case CK_EditUserMenu:
 424         edit_load_menu_file (h);
 425         break;
 426     case CK_Close:
 427         /* if there are no opened files anymore, close MC editor */
 428         if (edit_widget_is_editor (CONST_WIDGET (h->current->data)) &&
 429             edit_close_cmd ((WEdit *) h->current->data) && find_editor (h) == NULL)
 430             dlg_stop (h);
 431         break;
 432     case CK_Help:
 433         edit_help ();
 434         /* edit->force |= REDRAW_COMPLETELY; */
 435         break;
 436     case CK_Menu:
 437         edit_menu_cmd (h);
 438         break;
 439     case CK_Quit:
 440     case CK_Cancel:
 441         /* don't close editor due to SIGINT, but stop move/resize window */
 442         {
 443             Widget *w = WIDGET (h->current->data);
 444 
 445             if (edit_widget_is_editor (w) && ((WEdit *) w)->drag_state != MCEDIT_DRAG_NONE)
 446                 edit_restore_size ((WEdit *) w);
 447             else if (command == CK_Quit)
 448                 dlg_stop (h);
 449         }
 450         break;
 451     case CK_About:
 452         edit_about ();
 453         break;
 454     case CK_SyntaxOnOff:
 455         edit_syntax_onoff_cmd (h);
 456         break;
 457     case CK_ShowTabTws:
 458         edit_show_tabs_tws_cmd (h);
 459         break;
 460     case CK_ShowMargin:
 461         edit_show_margin_cmd (h);
 462         break;
 463     case CK_ShowNumbers:
 464         edit_show_numbers_cmd (h);
 465         break;
 466     case CK_Refresh:
 467         edit_refresh_cmd ();
 468         break;
 469     case CK_Shell:
 470         view_other_cmd ();
 471         break;
 472     case CK_LearnKeys:
 473         learn_keys ();
 474         break;
 475     case CK_WindowMove:
 476     case CK_WindowResize:
 477         if (edit_widget_is_editor (CONST_WIDGET (h->current->data)))
 478             edit_handle_move_resize ((WEdit *) h->current->data, command);
 479         break;
 480     case CK_WindowList:
 481         edit_window_list (h);
 482         break;
 483     case CK_WindowNext:
 484         dlg_select_next_widget (h);
 485         break;
 486     case CK_WindowPrev:
 487         dlg_select_prev_widget (h);
 488         break;
 489     case CK_Options:
 490         edit_options_dialog (h);
 491         break;
 492     case CK_OptionsSaveMode:
 493         edit_save_mode_cmd ();
 494         break;
 495     case CK_SaveSetup:
 496         save_setup_cmd ();
 497         break;
 498     default:
 499         ret = MSG_NOT_HANDLED;
 500         break;
 501     }
 502 
 503     return ret;
 504 }
 505 
 506 /* --------------------------------------------------------------------------------------------- */
 507 /*
 508  * Translate the keycode into either 'command' or 'char_for_insertion'.
 509  * 'command' is one of the editor commands from cmddef.h.
 510  */
 511 
 512 static gboolean
 513 edit_translate_key (WEdit * edit, long x_key, int *cmd, int *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 514 {
 515     long command = CK_InsertChar;
 516     int char_for_insertion = -1;
 517 
 518     /* an ordinary insertable character */
 519     if (!edit->extmod && x_key < 256)
 520     {
 521 #ifndef HAVE_CHARSET
 522         if (is_printable (x_key))
 523         {
 524             char_for_insertion = x_key;
 525             goto fin;
 526         }
 527 #else
 528         int c;
 529 
 530         if (edit->charpoint >= 4)
 531         {
 532             edit->charpoint = 0;
 533             edit->charbuf[edit->charpoint] = '\0';
 534         }
 535         if (edit->charpoint < 4)
 536         {
 537             edit->charbuf[edit->charpoint++] = x_key;
 538             edit->charbuf[edit->charpoint] = '\0';
 539         }
 540 
 541         /* input from 8-bit locale */
 542         if (!mc_global.utf8_display)
 543         {
 544             /* source in 8-bit codeset */
 545             c = convert_from_input_c (x_key);
 546 
 547             if (is_printable (c))
 548             {
 549                 if (!edit->utf8)
 550                     char_for_insertion = c;
 551                 else
 552                     char_for_insertion = convert_from_8bit_to_utf_c2 ((char) x_key);
 553                 goto fin;
 554             }
 555         }
 556         else
 557         {
 558             /* UTF-8 locale */
 559             int res;
 560 
 561             res = str_is_valid_char (edit->charbuf, edit->charpoint);
 562             if (res < 0 && res != -2)
 563             {
 564                 edit->charpoint = 0;    /* broken multibyte char, skip */
 565                 goto fin;
 566             }
 567 
 568             if (edit->utf8)
 569             {
 570                 /* source in UTF-8 codeset */
 571                 if (res < 0)
 572                 {
 573                     char_for_insertion = x_key;
 574                     goto fin;
 575                 }
 576 
 577                 edit->charbuf[edit->charpoint] = '\0';
 578                 edit->charpoint = 0;
 579                 if (g_unichar_isprint (g_utf8_get_char (edit->charbuf)))
 580                 {
 581                     char_for_insertion = x_key;
 582                     goto fin;
 583                 }
 584             }
 585             else
 586             {
 587                 /* 8-bit source */
 588                 if (res < 0)
 589                 {
 590                     /* not finised multibyte input (in meddle multibyte utf-8 char) */
 591                     goto fin;
 592                 }
 593 
 594                 if (g_unichar_isprint (g_utf8_get_char (edit->charbuf)))
 595                 {
 596                     c = convert_from_utf_to_current (edit->charbuf);
 597                     edit->charbuf[0] = '\0';
 598                     edit->charpoint = 0;
 599                     char_for_insertion = c;
 600                     goto fin;
 601                 }
 602 
 603                 /* unprinteble utf input, skip it */
 604                 edit->charbuf[0] = '\0';
 605                 edit->charpoint = 0;
 606             }
 607         }
 608 #endif /* HAVE_CHARSET */
 609     }
 610 
 611     /* Commands specific to the key emulation */
 612     if (edit->extmod)
 613     {
 614         edit->extmod = FALSE;
 615         command = keybind_lookup_keymap_command (editor_x_map, x_key);
 616     }
 617     else
 618         command = keybind_lookup_keymap_command (editor_map, x_key);
 619 
 620     if (command == CK_IgnoreKey)
 621         command = CK_InsertChar;
 622 
 623   fin:
 624     *cmd = (int) command;       /* FIXME */
 625     *ch = char_for_insertion;
 626 
 627     return !(command == CK_InsertChar && char_for_insertion == -1);
 628 }
 629 
 630 
 631 /* --------------------------------------------------------------------------------------------- */
 632 
 633 static inline void
 634 edit_quit (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 635 {
 636     GList *l;
 637     WEdit *e = NULL;
 638     GSList *m = NULL;
 639     GSList *me;
 640 
 641     /* don't stop the dialog before final decision */
 642     widget_set_state (WIDGET (h), WST_ACTIVE, TRUE);
 643 
 644     /* check window state and get modified files */
 645     for (l = h->widgets; l != NULL; l = g_list_next (l))
 646         if (edit_widget_is_editor (CONST_WIDGET (l->data)))
 647         {
 648             e = (WEdit *) l->data;
 649 
 650             if (e->drag_state != MCEDIT_DRAG_NONE)
 651             {
 652                 edit_restore_size (e);
 653                 g_slist_free (m);
 654                 return;
 655             }
 656 
 657             /* create separate list because widget_select()
 658                changes the window position in Z order */
 659             if (e->modified)
 660                 m = g_slist_prepend (m, l->data);
 661         }
 662 
 663     for (me = m; me != NULL; me = g_slist_next (me))
 664     {
 665         e = (WEdit *) me->data;
 666 
 667         widget_select (WIDGET (e));
 668 
 669         if (!edit_ok_to_exit (e))
 670             break;
 671     }
 672 
 673     /* if all files were checked, quit editor */
 674     if (me == NULL)
 675         dlg_stop (h);
 676 
 677     g_slist_free (m);
 678 }
 679 
 680 /* --------------------------------------------------------------------------------------------- */
 681 
 682 static inline void
 683 edit_set_buttonbar (WEdit * edit, WButtonBar * bb)
     /* [previous][next][first][last][top][bottom][index][help]  */
 684 {
 685     buttonbar_set_label (bb, 1, Q_ ("ButtonBar|Help"), editor_map, NULL);
 686     buttonbar_set_label (bb, 2, Q_ ("ButtonBar|Save"), editor_map, WIDGET (edit));
 687     buttonbar_set_label (bb, 3, Q_ ("ButtonBar|Mark"), editor_map, WIDGET (edit));
 688     buttonbar_set_label (bb, 4, Q_ ("ButtonBar|Replac"), editor_map, WIDGET (edit));
 689     buttonbar_set_label (bb, 5, Q_ ("ButtonBar|Copy"), editor_map, WIDGET (edit));
 690     buttonbar_set_label (bb, 6, Q_ ("ButtonBar|Move"), editor_map, WIDGET (edit));
 691     buttonbar_set_label (bb, 7, Q_ ("ButtonBar|Search"), editor_map, WIDGET (edit));
 692     buttonbar_set_label (bb, 8, Q_ ("ButtonBar|Delete"), editor_map, WIDGET (edit));
 693     buttonbar_set_label (bb, 9, Q_ ("ButtonBar|PullDn"), editor_map, NULL);
 694     buttonbar_set_label (bb, 10, Q_ ("ButtonBar|Quit"), editor_map, NULL);
 695 }
 696 
 697 /* --------------------------------------------------------------------------------------------- */
 698 
 699 static void
 700 edit_total_update (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 701 {
 702     edit_find_bracket (edit);
 703     edit->force |= REDRAW_COMPLETELY;
 704     edit_update_curs_row (edit);
 705     edit_update_screen (edit);
 706 }
 707 
 708 /* --------------------------------------------------------------------------------------------- */
 709 
 710 static gboolean
 711 edit_update_cursor (WEdit * edit, const mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
 712 {
 713     int x, y;
 714     gboolean done;
 715 
 716     x = event->x - (edit->fullscreen ? 0 : 1);
 717     y = event->y - (edit->fullscreen ? 0 : 1);
 718 
 719     if (edit->mark2 != -1 && event->msg == MSG_MOUSE_UP)
 720         return TRUE;            /* don't do anything */
 721 
 722     if (event->msg == MSG_MOUSE_DOWN || event->msg == MSG_MOUSE_UP)
 723         edit_push_key_press (edit);
 724 
 725     if (!option_cursor_beyond_eol)
 726         edit->prev_col = x - edit->start_col - option_line_state_width;
 727     else
 728     {
 729         long line_len;
 730 
 731         line_len =
 732             edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), 0,
 733                                 edit_buffer_get_current_eol (&edit->buffer));
 734 
 735         if (x > line_len - 1)
 736         {
 737             edit->over_col = x - line_len - edit->start_col - option_line_state_width;
 738             edit->prev_col = line_len;
 739         }
 740         else
 741         {
 742             edit->over_col = 0;
 743             edit->prev_col = x - option_line_state_width - edit->start_col;
 744         }
 745     }
 746 
 747     if (y > edit->curs_row)
 748         edit_move_down (edit, y - edit->curs_row, FALSE);
 749     else if (y < edit->curs_row)
 750         edit_move_up (edit, edit->curs_row - y, FALSE);
 751     else
 752         edit_move_to_prev_col (edit, edit_buffer_get_current_bol (&edit->buffer));
 753 
 754     if (event->msg == MSG_MOUSE_CLICK)
 755     {
 756         edit_mark_cmd (edit, TRUE);     /* reset */
 757         edit->highlight = 0;
 758     }
 759 
 760     done = (event->msg != MSG_MOUSE_DRAG);
 761     if (done)
 762         edit_mark_cmd (edit, FALSE);
 763 
 764     return done;
 765 }
 766 
 767 /* --------------------------------------------------------------------------------------------- */
 768 /** Callback for the edit dialog */
 769 
 770 static cb_ret_t
 771 edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 772 {
 773     WMenuBar *menubar;
 774     WButtonBar *buttonbar;
 775     WDialog *h = DIALOG (w);
 776 
 777     switch (msg)
 778     {
 779     case MSG_INIT:
 780         edit_dlg_init ();
 781         return MSG_HANDLED;
 782 
 783     case MSG_DRAW:
 784         /* don't use dlg_default_repaint() -- we don't need a frame */
 785         tty_setcolor (EDITOR_BACKGROUND);
 786         dlg_erase (h);
 787         return MSG_HANDLED;
 788 
 789     case MSG_RESIZE:
 790         menubar = find_menubar (h);
 791         buttonbar = find_buttonbar (h);
 792         /* dlg_set_size() is surplus for this case */
 793         w->lines = LINES;
 794         w->cols = COLS;
 795         widget_set_size (WIDGET (buttonbar), w->lines - 1, w->x, 1, w->cols);
 796         widget_set_size (WIDGET (menubar), w->y, w->x, 1, w->cols);
 797         menubar_arrange (menubar);
 798         g_list_foreach (h->widgets, (GFunc) edit_dialog_resize_cb, NULL);
 799         return MSG_HANDLED;
 800 
 801     case MSG_ACTION:
 802         {
 803             /* Handle shortcuts, menu, and buttonbar. */
 804 
 805             cb_ret_t result;
 806 
 807             result = edit_dialog_command_execute (h, parm);
 808 
 809             /* We forward any commands coming from the menu, and which haven't been
 810                handled by the dialog, to the focused WEdit window. */
 811             if (result == MSG_NOT_HANDLED && sender == WIDGET (find_menubar (h)))
 812                 result = send_message (h->current->data, NULL, MSG_ACTION, parm, NULL);
 813 
 814             return result;
 815         }
 816 
 817     case MSG_KEY:
 818         {
 819             Widget *we = WIDGET (h->current->data);
 820             cb_ret_t ret = MSG_NOT_HANDLED;
 821 
 822             if (edit_widget_is_editor (we))
 823             {
 824                 WEdit *e = (WEdit *) we;
 825                 long command;
 826 
 827                 if (!e->extmod)
 828                     command = keybind_lookup_keymap_command (editor_map, parm);
 829                 else
 830                     command = keybind_lookup_keymap_command (editor_x_map, parm);
 831 
 832                 if (command == CK_IgnoreKey)
 833                     e->extmod = FALSE;
 834                 else
 835                 {
 836                     ret = edit_dialog_command_execute (h, command);
 837                     /* if command was not handled, keep the extended mode
 838                        for the further key processing */
 839                     if (ret == MSG_HANDLED)
 840                         e->extmod = FALSE;
 841                 }
 842             }
 843 
 844             /*
 845              * Due to the "end of bracket" escape the editor sees input with is_idle() == false
 846              * (expects more characters) and hence doesn't yet refresh the screen, but then
 847              * no further characters arrive (there's only an "end of bracket" which is swallowed
 848              * by tty_get_event()), so you end up with a screen that's not refreshed after pasting.
 849              * So let's trigger an IDLE signal.
 850              */
 851             if (!is_idle ())
 852                 widget_idle (w, TRUE);
 853             return ret;
 854         }
 855 
 856         /* hardcoded menu hotkeys (see edit_drop_hotkey_menu) */
 857     case MSG_UNHANDLED_KEY:
 858         return edit_drop_hotkey_menu (h, parm) ? MSG_HANDLED : MSG_NOT_HANDLED;
 859 
 860     case MSG_VALIDATE:
 861         edit_quit (h);
 862         return MSG_HANDLED;
 863 
 864     case MSG_END:
 865         edit_dlg_deinit ();
 866         return MSG_HANDLED;
 867 
 868     case MSG_IDLE:
 869         widget_idle (w, FALSE);
 870         return send_message (h->current->data, NULL, MSG_IDLE, 0, NULL);
 871 
 872     default:
 873         return dlg_default_callback (w, sender, msg, parm, data);
 874     }
 875 }
 876 
 877 /* --------------------------------------------------------------------------------------------- */
 878 
 879 /**
 880  * Handle mouse events of editor screen.
 881  *
 882  * @param w Widget object (the editor)
 883  * @param msg mouse event message
 884  * @param event mouse event data
 885  */
 886 static void
 887 edit_dialog_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
 888 {
 889     gboolean unhandled = TRUE;
 890 
 891     if (msg == MSG_MOUSE_DOWN && event->y == 0)
 892     {
 893         WDialog *h = DIALOG (w);
 894         WMenuBar *b;
 895 
 896         b = find_menubar (h);
 897 
 898         if (!widget_get_state (WIDGET (b), WST_FOCUSED))
 899         {
 900             /* menubar */
 901 
 902             GList *l;
 903             GList *top = NULL;
 904             int x;
 905 
 906             /* Try find top fullscreen window */
 907             for (l = h->widgets; l != NULL; l = g_list_next (l))
 908                 if (edit_widget_is_editor (CONST_WIDGET (l->data))
 909                     && ((WEdit *) l->data)->fullscreen)
 910                     top = l;
 911 
 912             /* Handle fullscreen/close buttons in the top line */
 913             x = w->cols - 6;
 914 
 915             if (top != NULL && event->x >= x)
 916             {
 917                 WEdit *e = (WEdit *) top->data;
 918 
 919                 if (top != h->current)
 920                 {
 921                     /* Window is not active. Activate it */
 922                     widget_select (WIDGET (e));
 923                 }
 924 
 925                 /* Handle buttons */
 926                 if (event->x - x <= 2)
 927                     edit_toggle_fullscreen (e);
 928                 else
 929                     send_message (h, NULL, MSG_ACTION, CK_Close, NULL);
 930 
 931                 unhandled = FALSE;
 932             }
 933 
 934             if (unhandled)
 935                 menubar_activate (b, drop_menus, -1);
 936         }
 937     }
 938 
 939     /* Continue handling of unhandled event in window or menu */
 940     event->result.abort = unhandled;
 941 }
 942 
 943 /* --------------------------------------------------------------------------------------------- */
 944 
 945 static cb_ret_t
 946 edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 947 {
 948     WEdit *e = (WEdit *) w;
 949 
 950     switch (msg)
 951     {
 952     case MSG_FOCUS:
 953         edit_set_buttonbar (e, find_buttonbar (w->owner));
 954         return MSG_HANDLED;
 955 
 956     case MSG_DRAW:
 957         e->force |= REDRAW_COMPLETELY;
 958         edit_update_screen (e);
 959         return MSG_HANDLED;
 960 
 961     case MSG_KEY:
 962         {
 963             int cmd, ch;
 964             cb_ret_t ret = MSG_NOT_HANDLED;
 965 
 966             /* The user may override the access-keys for the menu bar. */
 967             if (macro_index == -1 && edit_execute_macro (e, parm))
 968             {
 969                 edit_update_screen (e);
 970                 ret = MSG_HANDLED;
 971             }
 972             else if (edit_translate_key (e, parm, &cmd, &ch))
 973             {
 974                 edit_execute_key_command (e, cmd, ch);
 975                 edit_update_screen (e);
 976                 ret = MSG_HANDLED;
 977             }
 978 
 979             return ret;
 980         }
 981 
 982     case MSG_ACTION:
 983         /* command from menubar or buttonbar */
 984         edit_execute_key_command (e, parm, -1);
 985         edit_update_screen (e);
 986         return MSG_HANDLED;
 987 
 988     case MSG_CURSOR:
 989         {
 990             int y, x;
 991 
 992             y = (e->fullscreen ? 0 : 1) + EDIT_TEXT_VERTICAL_OFFSET + e->curs_row;
 993             x = (e->fullscreen ? 0 : 1) + EDIT_TEXT_HORIZONTAL_OFFSET + option_line_state_width +
 994                 e->curs_col + e->start_col + e->over_col;
 995 
 996             widget_move (w, y, x);
 997             return MSG_HANDLED;
 998         }
 999 
1000     case MSG_IDLE:
1001         edit_update_screen (e);
1002         return MSG_HANDLED;
1003 
1004     case MSG_DESTROY:
1005         edit_clean (e);
1006         return MSG_HANDLED;
1007 
1008     default:
1009         return widget_default_callback (w, sender, msg, parm, data);
1010     }
1011 }
1012 
1013 /* --------------------------------------------------------------------------------------------- */
1014 
1015 /**
1016  * Handle move/resize mouse events.
1017  */
1018 static void
1019 edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
1020 {
1021     WEdit *edit = (WEdit *) (w);
1022     Widget *h = WIDGET (w->owner);
1023     int global_x, global_y;
1024 
1025     if (msg == MSG_MOUSE_UP)
1026     {
1027         /* Exit move/resize mode. */
1028         edit_execute_cmd (edit, CK_Enter, -1);
1029         edit_update_screen (edit);      /* Paint the buttonbar over our possibly overlapping frame. */
1030         return;
1031     }
1032 
1033     if (msg != MSG_MOUSE_DRAG)
1034         /**
1035          * We ignore any other events. Specifically, MSG_MOUSE_DOWN.
1036          *
1037          * When the move/resize is initiated by the menu, we let the user
1038          * stop it by clicking with the mouse. Which is why we don't want
1039          * a mouse down to affect the window.
1040          */
1041         return;
1042 
1043     /* Convert point to global coordinates for easier calculations. */
1044     global_x = event->x + w->x;
1045     global_y = event->y + w->y;
1046 
1047     /* Clamp the point to the dialog's client area. */
1048     global_y = CLAMP (global_y, h->y + 1, h->y + h->lines - 2); /* Status line, buttonbar */
1049     global_x = CLAMP (global_x, h->x, h->x + h->cols - 1);      /* Currently a no-op, as the dialog has no left/right margins. */
1050 
1051     if (edit->drag_state == MCEDIT_DRAG_MOVE)
1052     {
1053         w->y = global_y;
1054         w->x = global_x - edit->drag_state_start;
1055     }
1056     else if (edit->drag_state == MCEDIT_DRAG_RESIZE)
1057     {
1058         w->lines = MAX (WINDOW_MIN_LINES, global_y - w->y + 1);
1059         w->cols = MAX (WINDOW_MIN_COLS, global_x - w->x + 1);
1060     }
1061 
1062     edit->force |= REDRAW_COMPLETELY;   /* Not really needed as WEdit's MSG_DRAW already does this. */
1063 
1064     /* We draw the whole dialog because dragging/resizing exposes area beneath. */
1065     dlg_redraw (w->owner);
1066 }
1067 
1068 /* --------------------------------------------------------------------------------------------- */
1069 
1070 /**
1071  * Handle mouse events of editor window
1072  *
1073  * @param w Widget object (the editor window)
1074  * @param msg mouse event message
1075  * @param event mouse event data
1076  */
1077 static void
1078 edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
1079 {
1080     WEdit *edit = (WEdit *) w;
1081     /* buttons' distance from right edge */
1082     int dx = edit->fullscreen ? 0 : 2;
1083     /* location of 'Close' and 'Toggle fullscreen' pictograms */
1084     int close_x, toggle_fullscreen_x;
1085 
1086     close_x = (w->cols - 1) - dx - 1;
1087     toggle_fullscreen_x = close_x - 3;
1088 
1089     if (edit->drag_state != MCEDIT_DRAG_NONE)
1090     {
1091         /* window is being resized/moved */
1092         edit_mouse_handle_move_resize (w, msg, event);
1093         return;
1094     }
1095 
1096     /* If it's the last line on the screen, we abort the event to make the
1097      * system channel it to the overlapping buttonbar instead. We have to do
1098      * this because a WEdit has the WOP_TOP_SELECT flag, which makes it above
1099      * the buttonbar in Z-order. */
1100     if (msg == MSG_MOUSE_DOWN && (event->y + w->y == LINES - 1))
1101     {
1102         event->result.abort = TRUE;
1103         return;
1104     }
1105 
1106     switch (msg)
1107     {
1108     case MSG_MOUSE_DOWN:
1109         widget_select (w);
1110         edit_update_curs_row (edit);
1111         edit_update_curs_col (edit);
1112 
1113         if (!edit->fullscreen)
1114         {
1115             if (event->y == 0)
1116             {
1117                 if (event->x >= close_x - 1 && event->x <= close_x + 1)
1118                     ;           /* do nothing (see MSG_MOUSE_CLICK) */
1119                 else if (event->x >= toggle_fullscreen_x - 1 && event->x <= toggle_fullscreen_x + 1)
1120                     ;           /* do nothing (see MSG_MOUSE_CLICK) */
1121                 else
1122                 {
1123                     /* start window move */
1124                     edit_execute_cmd (edit, CK_WindowMove, -1);
1125                     edit_update_screen (edit);  /* Paint the buttonbar over our possibly overlapping frame. */
1126                     edit->drag_state_start = event->x;
1127                 }
1128                 break;
1129             }
1130 
1131             if (event->y == w->lines - 1 && event->x == w->cols - 1)
1132             {
1133                 /* bottom-right corner -- start window resize */
1134                 edit_execute_cmd (edit, CK_WindowResize, -1);
1135                 break;
1136             }
1137         }
1138 
1139         MC_FALLTHROUGH;         /* to start/stop text selection */
1140 
1141     case MSG_MOUSE_UP:
1142         edit_update_cursor (edit, event);
1143         edit_total_update (edit);
1144         break;
1145 
1146     case MSG_MOUSE_CLICK:
1147         if (event->y == 0)
1148         {
1149             if (event->x >= close_x - 1 && event->x <= close_x + 1)
1150                 send_message (w->owner, NULL, MSG_ACTION, CK_Close, NULL);
1151             else if (event->x >= toggle_fullscreen_x - 1 && event->x <= toggle_fullscreen_x + 1)
1152                 edit_toggle_fullscreen (edit);
1153             else if (!edit->fullscreen && event->count == GPM_DOUBLE)
1154                 /* double click on top line (toggle fullscreen) */
1155                 edit_toggle_fullscreen (edit);
1156         }
1157         else if (event->count == GPM_DOUBLE)
1158         {
1159             /* double click */
1160             edit_mark_current_word_cmd (edit);
1161             edit_total_update (edit);
1162         }
1163         else if (event->count == GPM_TRIPLE)
1164         {
1165             /* triple click: works in GPM only, not in xterm */
1166             edit_mark_current_line_cmd (edit);
1167             edit_total_update (edit);
1168         }
1169         break;
1170 
1171     case MSG_MOUSE_DRAG:
1172         edit_update_cursor (edit, event);
1173         edit_total_update (edit);
1174         break;
1175 
1176     case MSG_MOUSE_SCROLL_UP:
1177         edit_move_up (edit, 2, TRUE);
1178         edit_total_update (edit);
1179         break;
1180 
1181     case MSG_MOUSE_SCROLL_DOWN:
1182         edit_move_down (edit, 2, TRUE);
1183         edit_total_update (edit);
1184         break;
1185 
1186     default:
1187         break;
1188     }
1189 }
1190 
1191 /* --------------------------------------------------------------------------------------------- */
1192 /*** public functions ****************************************************************************/
1193 /* --------------------------------------------------------------------------------------------- */
1194 /**
1195  * Edit one file.
1196  *
1197  * @param file_vpath file object
1198  * @param line       line number
1199  * @return TRUE if no errors was occurred, FALSE otherwise
1200  */
1201 
1202 gboolean
1203 edit_file (const vfs_path_t * file_vpath, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
1204 {
1205     mcedit_arg_t arg = { (vfs_path_t *) file_vpath, line };
1206     GList *files;
1207     gboolean ok;
1208 
1209     files = g_list_prepend (NULL, &arg);
1210     ok = edit_files (files);
1211     g_list_free (files);
1212 
1213     return ok;
1214 }
1215 
1216 /* --------------------------------------------------------------------------------------------- */
1217 
1218 gboolean
1219 edit_files (const GList * files)
     /* [previous][next][first][last][top][bottom][index][help]  */
1220 {
1221     static gboolean made_directory = FALSE;
1222     WDialog *edit_dlg;
1223     WMenuBar *menubar;
1224     const GList *file;
1225     gboolean ok = FALSE;
1226 
1227     if (!made_directory)
1228     {
1229         char *dir;
1230 
1231         dir = mc_build_filename (mc_config_get_cache_path (), EDIT_DIR, (char *) NULL);
1232         made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1233         g_free (dir);
1234 
1235         dir = mc_build_filename (mc_config_get_path (), EDIT_DIR, (char *) NULL);
1236         made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1237         g_free (dir);
1238 
1239         dir = mc_build_filename (mc_config_get_data_path (), EDIT_DIR, (char *) NULL);
1240         made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1241         g_free (dir);
1242     }
1243 
1244     /* Create a new dialog and add it widgets to it */
1245     edit_dlg =
1246         dlg_create (FALSE, 0, 0, 1, 1, WPOS_FULLSCREEN, FALSE, NULL, edit_dialog_callback,
1247                     edit_dialog_mouse_callback, "[Internal File Editor]", NULL);
1248     widget_want_tab (WIDGET (edit_dlg), TRUE);
1249 
1250     edit_dlg->get_shortcut = edit_get_shortcut;
1251     edit_dlg->get_title = edit_get_title;
1252 
1253     menubar = menubar_new (0, 0, COLS, NULL, TRUE);
1254     add_widget (edit_dlg, menubar);
1255     edit_init_menu (menubar);
1256 
1257     add_widget (edit_dlg, buttonbar_new (TRUE));
1258 
1259     for (file = files; file != NULL; file = g_list_next (file))
1260     {
1261         Widget *w = WIDGET (edit_dlg);
1262         mcedit_arg_t *f = (mcedit_arg_t *) file->data;
1263         gboolean f_ok;
1264 
1265         f_ok = edit_add_window (edit_dlg, w->y + 1, w->x, w->lines - 2, w->cols, f->file_vpath,
1266                                 f->line_number);
1267         /* at least one file has been opened succefully */
1268         ok = ok || f_ok;
1269     }
1270 
1271     if (ok)
1272         dlg_run (edit_dlg);
1273 
1274     if (!ok || widget_get_state (WIDGET (edit_dlg), WST_CLOSED))
1275         dlg_destroy (edit_dlg);
1276 
1277     return ok;
1278 }
1279 
1280 /* --------------------------------------------------------------------------------------------- */
1281 
1282 const char *
1283 edit_get_file_name (const WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1284 {
1285     return vfs_path_as_str (edit->filename_vpath);
1286 }
1287 
1288 /* --------------------------------------------------------------------------------------------- */
1289 
1290 WEdit *
1291 find_editor (const WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
1292 {
1293     if (edit_widget_is_editor (CONST_WIDGET (h->current->data)))
1294         return (WEdit *) h->current->data;
1295     return (WEdit *) find_widget_type (h, edit_callback);
1296 }
1297 
1298 /* --------------------------------------------------------------------------------------------- */
1299 /**
1300  * Check if widget is an WEdit class.
1301  *
1302  * @param w probably editor object
1303  * @return TRUE if widget is an WEdit class, FALSE otherwise
1304  */
1305 
1306 gboolean
1307 edit_widget_is_editor (const Widget * w)
     /* [previous][next][first][last][top][bottom][index][help]  */
1308 {
1309     return (w != NULL && w->callback == edit_callback);
1310 }
1311 
1312 /* --------------------------------------------------------------------------------------------- */
1313 
1314 void
1315 edit_update_screen (WEdit * e)
     /* [previous][next][first][last][top][bottom][index][help]  */
1316 {
1317     WDialog *h = WIDGET (e)->owner;
1318 
1319     edit_scroll_screen_over_cursor (e);
1320     edit_update_curs_col (e);
1321     edit_status (e, widget_get_state (WIDGET (e), WST_FOCUSED));
1322 
1323     /* pop all events for this window for internal handling */
1324     if (!is_idle ())
1325         e->force |= REDRAW_PAGE;
1326     else
1327     {
1328         if ((e->force & REDRAW_COMPLETELY) != 0)
1329             e->force |= REDRAW_PAGE;
1330         edit_render_keypress (e);
1331     }
1332 
1333     widget_redraw (WIDGET (find_buttonbar (h)));
1334 }
1335 
1336 /* --------------------------------------------------------------------------------------------- */
1337 /**
1338  * Save current window size.
1339  *
1340  * @param edit editor object
1341  */
1342 
1343 void
1344 edit_save_size (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1345 {
1346     Widget *w = WIDGET (edit);
1347 
1348     edit->y_prev = w->y;
1349     edit->x_prev = w->x;
1350     edit->lines_prev = w->lines;
1351     edit->cols_prev = w->cols;
1352 }
1353 
1354 /* --------------------------------------------------------------------------------------------- */
1355 /**
1356  * Create new editor window and insert it into editor screen.
1357  *
1358  * @param h     editor dialog (screen)
1359  * @param y     y coordinate
1360  * @param x     x coordinate
1361  * @param lines window height
1362  * @param cols  window width
1363  * @param f     file object
1364  * @param fline line number in file
1365  * @return TRUE if new window was successfully created and inserted into editor screen,
1366  *         FALSE otherwise
1367  */
1368 
1369 gboolean
1370 edit_add_window (WDialog * h, int y, int x, int lines, int cols, const vfs_path_t * f, long fline)
     /* [previous][next][first][last][top][bottom][index][help]  */
1371 {
1372     WEdit *edit;
1373     Widget *w;
1374 
1375     edit = edit_init (NULL, y, x, lines, cols, f, fline);
1376     if (edit == NULL)
1377         return FALSE;
1378 
1379     w = WIDGET (edit);
1380     w->callback = edit_callback;
1381     w->mouse_callback = edit_mouse_callback;
1382 
1383     add_widget (h, w);
1384     edit_set_buttonbar (edit, find_buttonbar (h));
1385     dlg_redraw (h);
1386 
1387     return TRUE;
1388 }
1389 
1390 /* --------------------------------------------------------------------------------------------- */
1391 /**
1392  * Handle move/resize events.
1393  *
1394  * @param edit    editor object
1395  * @param command action id
1396  * @return TRUE if the action was handled, FALSE otherwise
1397  */
1398 
1399 gboolean
1400 edit_handle_move_resize (WEdit * edit, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
1401 {
1402     Widget *w = WIDGET (edit);
1403     gboolean ret = FALSE;
1404 
1405     if (edit->fullscreen)
1406     {
1407         edit->drag_state = MCEDIT_DRAG_NONE;
1408         w->mouse.forced_capture = FALSE;
1409         return ret;
1410     }
1411 
1412     switch (edit->drag_state)
1413     {
1414     case MCEDIT_DRAG_NONE:
1415         /* possible start move/resize */
1416         switch (command)
1417         {
1418         case CK_WindowMove:
1419             edit->drag_state = MCEDIT_DRAG_MOVE;
1420             edit_save_size (edit);
1421             edit_status (edit, TRUE);   /* redraw frame and status */
1422             /**
1423              * If a user initiates a move by the menu, not by the mouse, we
1424              * make a subsequent mouse drag pull the frame from its middle.
1425              * (We can instead choose '0' to pull it from the corner.)
1426              */
1427             edit->drag_state_start = w->cols / 2;
1428             ret = TRUE;
1429             break;
1430         case CK_WindowResize:
1431             edit->drag_state = MCEDIT_DRAG_RESIZE;
1432             edit_save_size (edit);
1433             edit_status (edit, TRUE);   /* redraw frame and status */
1434             ret = TRUE;
1435             break;
1436         default:
1437             break;
1438         }
1439         break;
1440 
1441     case MCEDIT_DRAG_MOVE:
1442         switch (command)
1443         {
1444         case CK_WindowResize:
1445             edit->drag_state = MCEDIT_DRAG_RESIZE;
1446             ret = TRUE;
1447             break;
1448         case CK_Up:
1449         case CK_Down:
1450         case CK_Left:
1451         case CK_Right:
1452             edit_window_move (edit, command);
1453             ret = TRUE;
1454             break;
1455         case CK_Enter:
1456         case CK_WindowMove:
1457             edit->drag_state = MCEDIT_DRAG_NONE;
1458             edit_status (edit, TRUE);   /* redraw frame and status */
1459             MC_FALLTHROUGH;
1460         default:
1461             ret = TRUE;
1462             break;
1463         }
1464         break;
1465 
1466     case MCEDIT_DRAG_RESIZE:
1467         switch (command)
1468         {
1469         case CK_WindowMove:
1470             edit->drag_state = MCEDIT_DRAG_MOVE;
1471             ret = TRUE;
1472             break;
1473         case CK_Up:
1474         case CK_Down:
1475         case CK_Left:
1476         case CK_Right:
1477             edit_window_resize (edit, command);
1478             ret = TRUE;
1479             break;
1480         case CK_Enter:
1481         case CK_WindowResize:
1482             edit->drag_state = MCEDIT_DRAG_NONE;
1483             edit_status (edit, TRUE);   /* redraw frame and status */
1484             MC_FALLTHROUGH;
1485         default:
1486             ret = TRUE;
1487             break;
1488         }
1489         break;
1490 
1491     default:
1492         break;
1493     }
1494 
1495     /**
1496      * - We let the user stop a resize/move operation by clicking with the
1497      *   mouse anywhere. ("clicking" = pressing and releasing a button.)
1498      * - We let the user perform a resize/move operation by a mouse drag
1499      *   initiated anywhere.
1500      *
1501      * "Anywhere" means: inside or outside the window. We make this happen
1502      * with the 'forced_capture' flag.
1503      */
1504     w->mouse.forced_capture = (edit->drag_state != MCEDIT_DRAG_NONE);
1505 
1506     return ret;
1507 }
1508 
1509 /* --------------------------------------------------------------------------------------------- */
1510 /**
1511  * Toggle window fuulscreen mode.
1512  *
1513  * @param edit editor object
1514  */
1515 
1516 void
1517 edit_toggle_fullscreen (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1518 {
1519     edit->fullscreen = !edit->fullscreen;
1520     edit->force = REDRAW_COMPLETELY;
1521 
1522     if (!edit->fullscreen)
1523         edit_restore_size (edit);
1524     else
1525     {
1526         Widget *w = WIDGET (edit);
1527         Widget *h = WIDGET (w->owner);
1528 
1529         edit_save_size (edit);
1530         widget_set_size (w, h->y + 1, h->x, h->lines - 2, h->cols);
1531         edit->force |= REDRAW_PAGE;
1532         edit_update_screen (edit);
1533     }
1534 }
1535 
1536 /* --------------------------------------------------------------------------------------------- */

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